How it works
ArchUnitRust turns a Cargo workspace into a directed dependency graph, reshapes that graph into the vocabulary of a rule or report, and keeps the verdict separate from its presentation.
The pipeline
SOURCE -> EXTRACT -> PROJECT -> ASSERT -> REPORT
| Stage | Responsibility | Rust-specific? |
|---|---|---|
| Source | Locate a package or workspace and enumerate selected Cargo targets | Cargo-specific |
| Extract | Parse modules and references into normalized Edge values |
Yes |
| Project | Relabel or select edges as files, layers, slices, metrics, or report nodes | Mostly no |
| Assert | Compare immutable projected data with one condition and emit violations | No |
| Report | Format test output or render an artifact | Only at integration edges |
Almost all language-specific work belongs in extraction. Projection and assertion operate on the same graph shapes used across the ArchUnitEverything family.
Rust source extraction
Project discovery uses cargo_metadata; syntax extraction uses syn with proc_macro2 source
locations. The extractor understands Rust module layout, inline and outlined modules, literal
#[path = "..."], use, pub use, extern crate, mod, qualified expression/type/pattern paths,
impls, and qualified attribute or derive paths.
Every internal source file receives a self-edge so isolated files remain visible. Parallel edges
with the same source and target are merged while unioning their ImportKind values. Internal
identifiers are stable workspace-relative paths with normalized separators.
The analysis is deliberately syntax-based. It does not expand declarative or procedural macros,
inspect build-script-generated source, evaluate the active target’s cfg expressions, promise
rust-analyzer semantic parity, or expose item-level architecture nodes. cfg branches are analyzed
as a conservative union; non-fatal ambiguities remain available as ExtractionDiagnostic values.
Repository layout
src/common/ shared extraction, projection, matching, errors, options, logging
src/files/ file rules and FileInfo extraction
src/layers/ named-layer policies
src/slices/ slice projections, pair rules, PlantUML checking and rendering
src/metrics/ Rust source metrics, conditions, and HTML reports
src/graph/ report queries, snapshots, and six renderers
src/testing/ assertion evaluation and stable violation formatting
src/checkable.rs cross-domain terminal contract
src/violation.rs closed cross-domain violation sum
src/lib.rs outward-only public re-export surface
Each domain owns its fluentapi and assertion folders, adding projection, extraction,
calculation, or reporting only when needed. Pure assertion, projection, and calculation code is
tested with hand-built in-memory values before integration fixtures exercise the Cargo boundary.
Self-enforced architecture
tests/architecture.rs dogfoods the public API and keeps five directions executable:
commondepends only on itself, the standard library, and the explicit analysis toolchain.files,graph,layers,metrics, andslicesdo not depend on one another.checkableandviolationare the intentional closed aggregation seam above domain data.testingconsumes those shared and domain contracts; product domains do not consume testing.lib.rsdepends outward as the public facade, while implementation files never import through it.
Each architectural unit also rejects executable dependency cycles. The rule excludes structural
Mod and PubUse evidence while retaining any parallel Use, PathReference, or other executable
evidence on the same edge.
Adding a rule
A new check normally follows one path:
- write the fluent sentence and choose its owning domain;
- define a data-only domain violation;
- implement the pure gather/assertion function over projected data;
- add consuming fluent stages and a terminal implementing
Checkable; - apply the strict empty-subject guard;
- add centralized formatting in
testing; - test the pure behavior, public builder, fixture project, error path, and failure message;
- update the family page and API doc comments in the same change.
The closed Violation enum is an intentional Rust adaptation: callers get typed accessors and one
stable catalogue, while each domain continues to own its violation data.
Why the documents are tested
The README is included as crate-level documentation. Every guide page is attached to a private
cfg(doctest) host in src/site_docs.rs, so every Rust fence compiles against the current public
crate without becoming shipped API. A separate site-integrity test checks front matter, navigation
order, local links and fragments, the expected chapter set, layout wiring, and deployment inputs.
The Pages workflow builds these Markdown chapters with GitHub’s Jekyll action and builds the generated rustdoc from the same commit. There is no JavaScript application, documentation package manager, or second hand-written API reference to drift.
Read the generated Rust API reference for signatures and type-level contracts, or return to the landing page.