Rust API and Crate Shape

Rust rules cover public API shape, crate layout, dependency policy, docs.rs behavior, feature flags, public errors, unsafe boundaries, and release checks.

Public API, crate layout, features, docs.rs, and release behavior.

90 rules

Add Benchmarks for Performance ClaimsRUST-ADD-BENCHMARKS-FOR-PERFORMANCE-CLAIMSUse benchmarks when Rust changes rely on speed, allocation, or hot-path claims. The evidence makes performance tradeoffs reviewable instead of relying on intuition.Align Release Support ClaimsRUST-ALIGN-RELEASE-SUPPORT-CLAIMSKeep crate metadata, docs, changelogs, and support statements saying the same thing. The alignment helps downstream users know which compatibility contract to trust.Avoid Broad Context and CallbacksRUST-AVOID-BROAD-CONTEXT-AND-CALLBACKSPass explicit inputs and keep control flow local instead of hiding it in context bags or callbacks. This makes ownership, effects, and ordering easier to audit.Avoid Empty Wrapper TypesRUST-AVOID-EMPTY-WRAPPER-TYPESAdd a wrapper type only when it carries an invariant, behavior, or ownership boundary. Otherwise it adds conversions and concepts without improving correctness.Avoid Giant Crate RootsRUST-AVOID-GIANT-CRATE-ROOTSUse the crate root to teach the public shape and route readers to focused modules. This keeps lib.rs or main.rs from becoming the whole implementation surface.Avoid Glob Re-ExportsRUST-AVOID-GLOB-REEXPORTSRe-export public facade names explicitly instead of using globs. This prevents accidental API expansion and makes exported names visible during review.Avoid Inline ModulesRUST-AVOID-INLINE-MODULESPut nontrivial modules in named files unless tests, preludes, or generated code justify inline layout. Stable paths make search, review, and ownership clearer.Avoid mod.rs by DefaultRUST-AVOID-MOD-RS-BY-DEFAULTPrefer named module files when they make tabs, paths, and search results clearer. Reserve mod.rs for cases where local convention or layout makes it the better signal.Avoid Overcommenting Trivial CodeRUST-AVOID-OVERCOMMENTING-TRIVIAL-CODEComment Rust code for invariants, contracts, and surprising tradeoffs rather than restating obvious operations. This keeps comments useful and less prone to drift.Avoid Path AttributesRUST-AVOID-PATH-ATTRIBUTEUse normal Rust module lookup unless generated or platform-specific layout needs #[path]. Predictable file paths make navigation and ownership easier to infer.Avoid Public Dependency CouplingRUST-AVOID-PUBLIC-DEPENDENCY-COUPLINGKeep dependency types out of public APIs unless interoperability is the purpose. This preserves semver freedom and avoids forcing downstream users onto implementation choices.Avoid Tiny Module MazesRUST-AVOID-TINY-MODULE-MAZESKeep small helper code near its use unless a separate module owns a real concept. This reduces file-jumping and preserves reader locality.Avoid Vague Docs and Generic ExamplesRUST-AVOID-VAGUE-DOCS-AND-GENERIC-EXAMPLESWrite Rustdoc and examples around real caller scenarios, not generic claims of usefulness. Concrete examples expose ownership, errors, features, and lifecycle expectations.Central Item FirstRUST-CENTRAL-ITEM-FIRSTPut the main type, trait, enum, or function before supporting details. Readers can learn the modules purpose before chasing helpers and adapters.Choose Generics and Trait Objects DeliberatelyRUST-CHOOSE-GENERICS-AND-TRAIT-OBJECTS-DELIBERATELYPick generics, stored type parameters, or trait objects for the variation they actually model. The choice affects compile cost, object safety, lifetimes, and caller ergonomics.Compare Crates by Fit and TradeoffRUST-COMPARE-CRATES-BY-FIT-AND-TRADEOFFCompare adjacent crates by intended fit, scope, and constraints instead of broad superiority claims. This helps users choose without turning docs into brittle marketing.Configure docs.rsRUST-CONFIGURE-DOCS-RSConfigure docs.rs metadata when features, cfgs, or rustdoc flags affect rendered API docs. Users should see the documentation surface the crate expects to support.Consider Downstream API ImpactRUST-CONSIDER-DOWNSTREAM-API-IMPACTCheck public API changes against downstream imports, traits, inference, and examples before reshaping them. Additive paths and deprecations often avoid unnecessary breakage.Contain UnsafeRUST-CONTAIN-UNSAFEKeep unsafe blocks small, wrapped by safe APIs, documented, and tested through safe behavior. Localized obligations make the safety argument auditable.Deny Accidental UnsafeRUST-DENY-ACCIDENTAL-UNSAFEUse a crate-level lint when a crate intends to avoid unsafe code entirely. Executable policy catches accidental unsafe before it becomes normal implementation detail.Do Not Default pub(crate)RUST-DO-NOT-DEFAULT-PUB-CRATEStart items private and widen to pub(crate) only for deliberate shared internals. This keeps modules independent and makes crate-local contracts visible.Do Not Pin Patch VersionsRUST-DO-NOT-PIN-PATCH-VERSIONSKeep manifest requirements as wide as the crate honestly supports. Patch pins belong in Cargo.toml only when code depends on that patchs API, fix, or behavior.Document Current Implemented BehaviorRUST-DOCUMENT-CURRENT-IMPLEMENTED-BEHAVIORDocument what the crate does today instead of presenting future plans as available contract. Clear tense and labels prevent callers from relying on unimplemented behavior.Document Feature ContractsRUST-DOCUMENT-FEATURE-CONTRACTSExplain what each feature flag enables, requires, and promises. Feature contracts help users choose combinations without guessing from dependency names.Document Lifecycle Side EffectsRUST-DOCUMENT-LIFECYCLE-SIDE-EFFECTSDocument construction, start, stop, drop, and cleanup behavior when side effects matter. Callers need to know when resources are acquired, released, spawned, or blocked.Document Performance ContractsRUST-DOCUMENT-PERFORMANCE-CONTRACTSState meaningful performance expectations when callers may design around them. Clear limits keep complexity and optimization claims tied to supported behavior.Document Public Panic ContractsRUST-DOCUMENT-PUBLIC-PANIC-CONTRACTSDocument when public APIs can panic and what callers can do to avoid it. Panic contracts keep recoverable errors, invariants, and misuse boundaries explicit.Document Scheduling for Long Async WorkRUST-DOCUMENT-SCHEDULING-FOR-LONG-ASYNCExplain executor, cancellation, blocking, and fairness expectations for async work that can run long. Callers need those constraints to avoid starvation and runtime surprises.Document Visibility OwnershipRUST-DOCUMENT-VISIBILITY-OWNERSHIPPair widened visibility with names and docs that identify the owning concept. This prevents shared internals from looking like accidental stable API.Encode Durable Rules in LintsRUST-ENCODE-DURABLE-RULES-IN-LINTSUse lint configuration for project policies stable enough to automate. Durable lints catch repeated mistakes without turning subjective taste into CI noise.Expose Primary Path from Crate RootRUST-EXPOSE-PRIMARY-PATH-FROM-CRATE-ROOTMake the crate root show the main workflow, types, and import path. Users should not have to infer the intended entry point from private layout details.Format Docs and Comments ConsistentlyRUST-FORMAT-DOCS-AND-COMMENTS-CONSISTENTLYApply stable formatting to Rustdoc, examples, attributes, and prose comments. Consistent source formatting keeps docs readable and prevents noisy future diffs.Group Module ImportsRUST-GROUP-MODULE-IMPORTSGroup related imports by module when that matches local style. This makes dependency shape easier to scan and avoids churn from one-import-per-line edits.Group Private Imports Before Public Re-ExportsRUST-GROUP-PRIVATE-IMPORTS-BEFORE-PUBLIC-RE-EXPORTSSeparate implementation imports from public re-exports in module prologues. The grouping lets readers distinguish internal dependencies from the API surface being presented.Hide Test-Only HelpersRUST-HIDE-TEST-ONLY-HELPERSKeep fixtures and shortcuts behind test-only modules, features, or support crates unless they are deliberate API. This prevents scaffolding from leaking into production contracts.Implement Debug for Public TypesRUST-IMPLEMENT-DEBUG-FOR-PUBLIC-TYPESProvide Debug for public types unless it would expose secrets or mislead callers. The trait is baseline support for tests, assertions, logs, and downstream diagnostics.Implement Standard Traits for Public ErrorsRUST-IMPLEMENT-STANDARD-TRAITS-FOR-PUBLIC-ERRORSMake reusable public errors implement the standard diagnostic traits where appropriate. This lets callers compose, display, chain, and inspect errors in ordinary Rust workflows.Inject Host Interactions at BoundariesRUST-INJECT-HOST-INTERACTIONS-AT-BOUNDARIESPass filesystem, network, time, randomness, and process behavior through boundaries when tests or alternate environments need control. This keeps the core deterministic and effects explicit.Keep CI High SignalRUST-KEEP-CI-HIGH-SIGNALKeep required Rust checks strict, fast, deterministic, and actionable. Slow or flaky ritual trains maintainers to ignore failures while real drift accumulates.Keep Compatible Updates in LockfileRUST-KEEP-COMPATIBLE-UPDATES-IN-LOCKFILELet lockfiles record newer compatible dependency versions when the manifest floor has not changed. This tests fresh releases without narrowing downstream compatibility.Keep Concepts CoherentRUST-KEEP-CONCEPTS-COHERENTGive each module, type, or helper one recognizable idea to own. Coherent ownership keeps readers from carrying unrelated parsing, state, rendering, and policy facts at once.Keep Crate Boundaries NarrowRUST-KEEP-CRATE-BOUNDARIES-NARROWPut behavior and tests in the crate or module that owns them before extracting shared helpers. Narrow boundaries reduce dependency fan-out, feature pressure, and hidden coupling.Keep Dependency Updates IntentionalRUST-KEEP-DEPENDENCY-UPDATES-INTENTIONALSeparate maintenance-only dependency refreshes from updates that change behavior, features, MSRV, or integration. Reviewable grouping lowers noise without hiding downstream risk.Keep Edits Scoped to Owning ConceptRUST-KEEP-EDITS-SCOPED-TO-OWNING-CONCEPTChange the module, crate, feature, or facade that owns the behavior being fixed. Scoped edits keep reviews atomic and prevent nearby files from pulling in unrelated concepts.Keep Lints ActionableRUST-KEEP-LINTS-ACTIONABLEEnforce lints that improve correctness, API quality, docs, portability, or maintenance in ways reviewers want automated. Scope suppressions tightly so exceptions stay visible.Keep Markdown Outside Rustdoc PurposefulRUST-KEEP-MARKDOWN-OUTSIDE-RUSTDOC-PURPOSEFULUse standalone Markdown for architecture, workflow, release, or operational guidance that would make API docs noisy. Choosing the right surface keeps contracts and long-form context current.Keep Pre-Release Compatibility IntentionalRUST-KEEP-PRE-RELEASE-COMPATIBILITY-INTENTIONALPreserve pre-release compatibility only when it reflects a chosen contract. Early cleanup is often cheaper than freezing accidental names, re-exports, features, or variants.Keep Preludes Re-Export OnlyRUST-KEEP-PRELUDES-REEXPORT-ONLYPut only re-exports in prelude modules and keep original behavior in its owning module. Users expect preludes to aid imports, not hide implementation ownership.Keep Public API Shape IntentionalRUST-KEEP-PUBLIC-API-SHAPE-INTENTIONALMake public visibility, aliases, features, re-exports, bounds, and variants reflect intended commitments. Published surface area becomes something downstream users can depend on.Keep Rustdoc and README Examples AlignedRUST-KEEP-RUSTDOC-AND-README-EXAMPLES-ALIGNEDKeep README, Rustdoc, generated docs, and example directories teaching the same current usage contract. Aligned examples prevent users from guessing which import path or lifecycle is correct.Make Feature Flags Additive Where PossibleRUST-MAKE-FEATURE-FLAGS-ADDITIVE-WHERE-POSSIBLEDesign feature flags as additive capabilities whenever possible so Cargo feature unification does not surprise downstream builds. Make incompatible combinations explicit when addition cannot model the real choice.Make Public API Browseable From LayoutRUST-MAKE-PUBLIC-API-BROWSEABLE-FROM-LAYOUTAlign public modules, re-exports, and source files so readers can navigate from API to ownership without translation. Facades are fine when they improve discovery and still point toward the owning concept.Make Side Effects ExplicitRUST-MAKE-SIDE-EFFECTS-EXPLICITPut mutation, I/O, registration, cleanup, and background work in names, call sites, or docs when callers must account for them. Keep tiny private helpers plain when the surrounding code already makes the effect obvious.Name Auditable IntermediatesRUST-NAME-AUDITABLE-INTERMEDIATESIntroduce named locals where parsing, validation, rendering, ownership, or side-effect decisions need review. Avoid naming every trivial expression when it would add ceremony without clarifying the boundary.Name Tests By BehaviorRUST-NAME-TESTS-BY-BEHAVIORName tests after the behavior, boundary, or regression they protect so failure output is useful before a reader opens the body. Keep names concise and let module context carry repeated setup details.Non Exhaustive Public ErrorsRUST-NON-EXHAUSTIVE-PUBLIC-ERRORSMark public error enums non-exhaustive unless exhaustive matching is part of the contract. This preserves room for future integration, validation, or provider failures without needless downstream breakage.Order Code For ReadingRUST-ORDER-CODE-FOR-READINGArrange code so central items, callers, or public API appear before supporting helpers when that makes the file readable top to bottom. Prefer the order that reduces reader jumping over mechanical rearrangement.Order Items For API ReadingRUST-ORDER-ITEMS-FOR-API-READINGOrder imports, public items, impls, trait impls, and helpers so the API story is easy to scan. Respect macros, generated code, and local convention when another order communicates better.Prefer Boring Direct CodeRUST-PREFER-BORING-DIRECT-CODEPrefer explicit Rust control flow, types, and error handling over clever framework-shaped indirection. Use macros or abstractions when they remove real repetition or enforce real invariants.Prefer Concept Owned Modules And Named FilesRUST-PREFER-CONCEPT-OWNED-MODULES-AND-NAMED-FILESOrganize modules around domain concepts and give important concepts named files that own their types, invariants, tests, and docs. Use infrastructure modules only when the cross-cutting concept is real and bounded.Prefer Constructors And Conversion TraitsRUST-PREFER-CONSTRUCTORS-AND-CONVERSION-TRAITSUse inherent constructors and standard conversion traits to show whether construction builds, validates, converts, borrows, allocates, or can fail. Prefer public fields only when direct construction is truly part of the contract.Prefer Expect For Lint SuppressionsRUST-PREFER-EXPECT-FOR-LINT-SUPPRESSIONSUse #[expect] for targeted lint suppressions that should disappear when the warning is fixed. Reserve broad allow attributes for deliberate policy choices that are not expected to expire.Prefer Small Clear ShapesRUST-PREFER-SMALL-CLEAR-SHAPESFavor small functions, narrow structs, and simple enums that keep live facts local for readers. Do not split cohesive logic into fragments that force more navigation than understanding.Preserve Error ContextRUST-PRESERVE-ERROR-CONTEXTWrap and model errors so callers can see the operation, relevant input, source cause, and recovery signal. Avoid flattening failures into broad strings or generic variants that remove actionable context.Preserve Valid State On FailureRUST-PRESERVE-VALID-STATE-ON-FAILUREKeep values valid when fallible operations return errors so callers can retry, inspect, or drop them predictably. Use transactional updates or staging when partial mutation would expose a broken state.Reexport For DiscoveryRUST-REEXPORT-FOR-DISCOVERYRe-export public items where callers naturally look so the crate surface is discoverable without hiding ownership. Keep canonical definitions and docs clear so re-exports do not become competing homes.Release Only After Artifact ValidationRUST-RELEASE-ONLY-AFTER-ARTIFACT-VALIDATIONValidate the actual release artifact before publishing instead of trusting the working tree. This catches missing files, stale generated content, and packaging mistakes while the release can still be fixed.Review As Future MaintainerRUST-REVIEW-AS-FUTURE-MAINTAINERReview Rust changes for the reader who will debug, extend, or release the code later, not only for immediate correctness. Favor maintainable API shape, docs, tests, and error behavior over changes that merely compile.Run Feature Gated ValidationRUST-RUN-FEATURE-GATED-VALIDATIONExercise the feature combinations touched by a Rust change so gated code, docs, and integrations actually build. Choose representative combinations when exhaustive feature matrices would be too expensive.Shape Expressions For AuditabilityRUST-SHAPE-EXPRESSIONS-FOR-AUDITABILITYShape complex expressions so ownership, validation, error handling, and side effects can be audited at the point they occur. Break chains or introduce names when density hides a decision readers must verify.Teach Crate From Crate RootRUST-TEACH-CRATE-FROM-CRATE-ROOTUse crate-root docs and exports to teach the crates main concepts, entry points, and common paths. Keep the root focused enough to orient readers without duplicating every item-level contract.Tie Optional Dependencies To Named FeaturesRUST-TIE-OPTIONAL-DEPENDENCIES-TO-NAMED-FEATURESConnect optional dependencies to clear feature names that explain the capability callers enable. Avoid leaking dependency names as the public feature design when the capability needs a more stable contract.Use Builders For Optional Or Validated FieldsRUST-USE-BUILDERS-FOR-OPTIONAL-OR-VALIDATED-FIELDSUse builders when construction has many optional inputs or cross-field validation that would make constructors hard to read. Avoid builder APIs for simple values where direct construction communicates the contract better.Use Debug Assert For Internal InvariantsRUST-USE-DEBUG-ASSERT-FOR-INTERNAL-INVARIANTSUse debug assertions for internal invariants that should hold if nearby code is correct. Do not use them for caller validation or safety requirements that must be enforced in release builds.Use Directory Modules As Tables Of ContentsRUST-USE-DIRECTORY-MODULES-AS-TABLES-OF-CONTENTSLet directory module files introduce, organize, and re-export the concepts owned by that directory. Keep substantial implementation in named child files so the module remains a readable table of contents.Use Doc Inline For Canonical ReexportsRUST-USE-DOC-INLINE-FOR-CANONICAL-REEXPORTSUse #[doc(inline)] when a re-export should be the canonical place readers encounter an item. Avoid inlining re-exports that would obscure the owning module or create duplicate-looking documentation.Use Field Init ShorthandRUST-USE-FIELD-INIT-SHORTHANDUse field init shorthand when variable names already match struct fields so initialization stays compact and familiar. Spell fields out when renaming, conversion, or policy deserves visible attention.Use Functions For Incidental TypesRUST-USE-FUNCTIONS-FOR-INCIDENTAL-TYPESPrefer free or module functions when a type does not own the operation or invariant. Move behavior onto a type when the method relationship clarifies state, policy, or trait design.Use Honest Minimum DependenciesRUST-USE-HONEST-MINIMUM-DEPENDENCIESSet dependency requirements to the lowest compatible versions the crate actually supports. Raise minimums only for required APIs, fixes, features, security needs, or MSRV interactions.Use Meaningful Standard TypesRUST-USE-MEANINGFUL-STANDARD-TYPESPrefer standard or ecosystem types that encode ownership, units, paths, durations, optionality, and invariants better than raw strings or integers. Use domain newtypes when the standard type cannot prevent meaningful mixups.Use Send Static Across TasksRUST-USE-SEND-STATIC-ACROSS-TASKSRequire owned Send + static values, futures, errors, and handles when they cross spawn or thread boundaries. Avoid imposing those bounds on local synchronous APIs where they would reject valid use.Validate Builders On BuildRUST-VALIDATE-BUILDERS-ON-BUILDValidate cross-field builder invariants in build where partial configuration becomes a usable value. Keep build infallible only when defaults and setters make invalid states impossible.Validate Package Contents Before ReleaseRUST-VALIDATE-PACKAGE-CONTENTS-BEFORE-RELEASEInspect and build the package users will receive, not just the repository checkout. This catches missing assets, accidental inclusions, README drift, and include/exclude mistakes before publication.Validate Rust Docs As CodeRUST-VALIDATE-RUST-DOCS-AS-CODETreat Rust documentation examples, links, feature assumptions, and generated README content as code that must be checked. Use docs builds, doctests, feature-gated checks, and Markdown lint according to the changed surface.Validate Semver Breaks Against External UseRUST-VALIDATE-SEMVER-BREAKS-AGAINST-EXTERNAL-USECheck semver-breaking changes against real examples, dependents, or migration paths before treating an API cleanup as cheap. External evidence informs the cost even when security, soundness, or design repair still justify the break.Validate Unsafe Through Safe APIRUST-VALIDATE-UNSAFE-THROUGH-SAFE-APITest unsafe internals through the safe API wrapper that callers rely on. Internal unsafe tests and tools such as Miri should support, not replace, proof that safe calls uphold the contract.Working Rust Code Not EnoughRUST-WORKING-RUST-CODE-NOT-ENOUGHTreat compilation as necessary but insufficient evidence for long-lived Rust code. Review API shape, docs, errors, tests, features, dependencies, and module organization because users and maintainers inherit those choices.Write Actionable Error DisplayRUST-WRITE-ACTIONABLE-ERROR-DISPLAYWrite Display messages that tell humans what failed and what useful next action or context exists. Keep structured state in error fields, sources, diagnostics, or Debug instead of dumping internals into the user-facing string.Write Public Docs For Caller TasksRUST-WRITE-PUBLIC-DOCS-FOR-CALLER-TASKSWrite public Rustdoc around what callers are trying to decide, do, and rely on. Start with concise behavior and add arguments, failures, lifecycle, features, links, or examples only when they help the task.Write Rustdoc As API ContractRUST-WRITE-RUSTDOC-AS-API-CONTRACTUse Rustdoc to state caller-facing behavior, invariants, failures, side effects, and compatibility promises. Leave private implementation detail in comments unless it helps maintain the public contract.