Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/copyright.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

# If there are new files with headers that cannot match the conditions here,
# then the files can be ignored by an additional glob argument via the -g flag.
# For example:
# -g "!src/special_file.rs"
# -g "!src/special_directory"

# Check all the standard Rust source files.
output=$(rg "^// Copyright (19|20)[\d]{2} (.+ and )?the Addressable Authors( and .+)?$\n^// SPDX-License-Identifier: Apache-2\.0 OR MIT$\n\n" --files-without-match --multiline -g "*.rs" .)

if [ -n "$output" ]; then
echo -e "The following files lack the correct copyright header:\n"
echo "$output"
echo -e "\n\nPlease add the following header:\n"
echo "// Copyright $(date +%Y) the Addressable Authors"
echo "// SPDX-License-Identifier: Apache-2.0 OR MIT"
echo -e "\n... rest of the file ...\n"
exit 1
fi

echo "All files have correct copyright headers."
exit 0
169 changes: 169 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
env:
# Keep the minimum version in sync with workspace.package.rust-version.
RUST_MIN_VER: "1.88"
RUST_STABLE_VER: "1.97"

name: CI

on:
pull_request:
merge_group:
push:
branches:
- main

jobs:
fmt:
name: formatting and repository policy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: install stable toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_STABLE_VER }}
components: rustfmt

- name: cargo fmt
run: cargo fmt --all --check

- name: install Taplo
uses: uncenter/setup-taplo@09968a8ae38d66ddd3d23802c44bf6122d7aa991 # v1
with:
version: "0.9.3"

- name: taplo fmt
run: taplo fmt --check --diff

- name: install ripgrep
run: |
sudo apt update
sudo apt install ripgrep

- name: check copyright headers
run: bash .github/copyright.sh

clippy:
name: cargo clippy
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v6

- name: install stable toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_STABLE_VER }}
components: clippy

- name: restore cache
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.event_name != 'merge_group' }}

- name: cargo clippy
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings

portable-core:
name: portable core
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: install stable toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_STABLE_VER }}
targets: x86_64-unknown-none,wasm32-unknown-unknown

- name: restore cache
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.event_name != 'merge_group' }}

- name: check bare-metal core
run: cargo check -p addressable --locked --target x86_64-unknown-none

- name: check WebAssembly core
run: cargo check -p addressable --locked --target wasm32-unknown-unknown

test:
name: cargo test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v6

- name: install stable toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_STABLE_VER }}

- name: restore cache
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.event_name != 'merge_group' }}

- name: cargo test
run: cargo test --workspace --all-features --locked

- name: cargo test docs
run: cargo test --doc --workspace --all-features --locked

msrv:
name: Rust 1.88
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: install MSRV toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_MIN_VER }}
targets: x86_64-unknown-none

- name: restore cache
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.event_name != 'merge_group' }}

- name: check workspace
run: cargo check --workspace --all-targets --all-features --locked

- name: check bare-metal core
run: cargo check -p addressable --locked --target x86_64-unknown-none

docs:
name: rustdoc
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: install stable toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_STABLE_VER }}

- name: restore cache
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.event_name != 'merge_group' }}

- name: cargo doc
run: cargo doc --workspace --all-features --locked --no-deps --document-private-items
env:
RUSTDOCFLAGS: "-D warnings"

typos:
name: typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: check typos
uses: crate-ci/typos@v1.46.0
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
8 changes: 8 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# See https://github.com/crate-ci/typos/blob/master/docs/reference.md

[default.extend-words]
referent = "referent"

[files]
ignore-hidden = false
extend-exclude = ["/.git"]
57 changes: 57 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Instructions for agents

Read `MANDATE.md`, `docs/ARCHITECTURE.md`, and `STATUS.md` before making
architectural or implementation changes.

This repository is intended to become a long-lived Rust foundation for the
forest-rs ecosystem. Treat the mature system described in the architecture as
the design target. Do not reduce the project to a string-path utility merely
because exact addresses are the first primitive needed by consumers.

## Local context

When the checkout is under `/Users/bruce/Development/forest-rs`, inspect the
applicable instructions, old forest-rs tenets, and current conventions in the
sibling repositories before scaffolding or changing CI. In particular, compare
representative current practice in `exedra`, `portolan`, `layerstack`,
`understory`, `overstory`, and `inkstone`. Sibling repositories are references;
do not modify them as part of Addressable work.

Repository-local and ancestor `AGENTS.md` instructions take precedence over
this file where their scope applies. Record significant architectural choices
and reversals in a decision log rather than allowing them to survive only in a
chat transcript.

## Engineering expectations

- Preserve strong Rust typing. Do not introduce a universal value enum into the
ordinary typed API.
- Keep durable semantic identities and addresses distinct from arena slots,
interned IDs, generational handles, and other runtime-local accelerators.
- Keep referent identity, occurrence identity, endpoint identity, and revision
context distinguishable.
- Prefer `no_std` plus `alloc` for foundational crates where practical. Put
genuinely `std`-dependent execution facilities behind honest boundaries.
- Treat textual syntax as parsing and serialization of structured data, not as
the in-memory representation.
- Make cardinality, ordering, deduplication, traversal budgets, and cycle policy
explicit in query APIs.
- Require preconditions for potentially stale addressed mutations. A pinned
reference must never silently rebind.
- Favor executable semantic laws, property tests, conformance fixtures, fuzzing,
and examples over claims that cannot be checked.
- Add crate boundaries only where they express a real dependency or portability
boundary. Avoid both a monolith and a family of speculative empty crates.

## Delegated authority

Within this repository, exercise architectural judgment rather than waiting for
approval on every type or module name. It is acceptable to revise this initial
architecture when concrete implementation evidence demands it; explain the
reason and preserve the important semantic distinctions.

Stop for actions that are public, destructive, difficult to reverse, or outside
the repository's delegated scope: merging to `main`, publishing crates or
releases, changing licensing, changing sibling repositories, spending money,
or making commitments on behalf of the owner.

31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 81 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
[workspace]
resolver = "2"
members = [
"crates/addressable",
"crates/addressable_reference",
"crates/addressable_tooling",
"examples/addressable_tour",
]

[workspace.package]
version = "0.1.0"
edition = "2024"
rust-version = "1.88"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/forest-rs/addressable"

[workspace.dependencies]
addressable = { path = "crates/addressable", version = "0.1.0" }
addressable_reference = { path = "crates/addressable_reference", version = "0.1.0" }
addressable_tooling = { path = "crates/addressable_tooling", version = "0.1.0" }

[workspace.lints]
# LINEBENDER LINT SET - Cargo.toml - v8
# See https://linebender.org/wiki/canonical-lints/
rust.keyword_idents_2024 = "forbid"
rust.non_ascii_idents = "forbid"
rust.non_local_definitions = "forbid"
rust.unsafe_op_in_unsafe_fn = "forbid"

rust.elided_lifetimes_in_paths = "warn"
rust.missing_debug_implementations = "warn"
rust.missing_docs = "warn"
rust.trivial_numeric_casts = "warn"
rust.unnameable_types = "warn"
rust.unreachable_pub = "warn"
rust.unused_import_braces = "warn"
rust.unused_lifetimes = "warn"
rust.unused_macro_rules = "warn"
rust.unused_qualifications = "warn"

rust.unsafe_code = "deny"

clippy.too_many_arguments = "allow"

clippy.allow_attributes_without_reason = "warn"
clippy.cast_possible_truncation = "warn"
clippy.cast_possible_wrap = "warn"
clippy.collection_is_never_read = "warn"
clippy.dbg_macro = "warn"
clippy.debug_assert_with_mut_call = "warn"
clippy.default_trait_access = "warn"
clippy.doc_markdown = "warn"
clippy.fn_to_numeric_cast_any = "warn"
clippy.infinite_loop = "warn"
clippy.large_stack_arrays = "warn"
clippy.mismatching_type_param_order = "warn"
clippy.missing_assert_message = "warn"
clippy.missing_fields_in_debug = "warn"
clippy.same_functions_in_if_condition = "warn"
clippy.semicolon_if_nothing_returned = "warn"
clippy.should_panic_without_expect = "warn"
clippy.todo = "warn"
clippy.unseparated_literal_suffix = "warn"
clippy.use_self = "warn"

clippy.cargo_common_metadata = "warn"
clippy.negative_feature_names = "warn"
clippy.redundant_feature_names = "warn"
clippy.wildcard_dependencies = "warn"
# END LINEBENDER LINT SET

# Prefer `#[expect(...)]` so stale suppressions are visible.
clippy.allow_attributes = "warn"

[profile.ci]
inherits = "dev"
debug = 0
strip = "debuginfo"

[profile.ci.package."*"]
debug-assertions = true
Loading