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
2 changes: 2 additions & 0 deletions languages/rust/architect.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ When opening an ADR for a Rust crate, the template should cover:
- **`unsafe` without a soundness comment.** Every `unsafe` block needs a justification.
- **Undocumented public items.** A `pub` item with no `///` doc comment ships an unexplained contract.
- **`dyn Trait` in a hot-path signature** chosen by default rather than measured.
- **Overengineering.** Reaching for a trait, macro, generic, or `unsafe` before a plain function would do, or optimizing before profiling — the "four horsemen" of bad Rust. Prefer the simplest construct that *still honors the idioms in this guide* — simple, not simplistic. Simplicity is never a license to erase intent: a named enum or newtype still beats a fistful of `bool`/`String` parameters ([`idioms.md`](./idioms.md)).

## Related

Expand All @@ -101,3 +102,4 @@ When opening an ADR for a Rust crate, the template should cover:
- Forest's [`AI_POLICY.md`](https://github.com/ChainSafe/forest/blob/main/AI_POLICY.md) — Filecoin/Forest-specific AI norms; informs Rust review at ChainSafe.
- [`../../invariants/invariance-framework.md`](../../invariants/invariance-framework.md) — architectural framework this page defers to.
- [Effective Rust](https://effective-rust.com/) (Drysdale) and [The Rust Book](https://doc.rust-lang.org/book/) — the canonical practice references this section builds on; cataloged in [`sources.md`](../../references/sources.md).
- [Idiomatic Rust](https://github.com/mre/idiomatic-rust) (peer-reviewed corpus) and the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/) — idiomatic-Rust principles and API conventions.
46 changes: 46 additions & 0 deletions languages/rust/idioms.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,51 @@ A `UserId` and `OrderId` are not interchangeable. Newtypes make the type system

For numeric newtypes, `derive_more` or hand-written `From`/`Into`/`Display` are common.

## Enums over booleans

```rust
fn set_visibility(v: Visibility) // Visibility::Hidden — intent is obvious
fn set_visible(visible: bool) // what does set_visible(true) mean at the call site?
```

A `bool` parameter erases intent at the call site, and a pair of them makes illegal combinations representable. An `enum` names the states and gets exhaustiveness checking (mre/idiomatic-rust: *Enums Instead of Booleans*).

## Accept flexible input types

```rust
fn greet(name: &str) // &str, not &String
fn join(parts: &[&str]) -> String // &[T], not &Vec<T>
fn read(path: impl AsRef<Path>) -> ... // &str / String / &Path / PathBuf all work
Comment on lines +60 to +61

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add somewhere an admonition that this must not be used in interfaces so that they are object-safe (or dyn-compatible). Otherwise one would not be able to, e.g., use Box<dyn MyTrait>.

```

Take the most general borrowed form. Callers pass what they already have without converting, and ownership decisions stay at the boundary. A recurring theme across the idiomatic-Rust corpus.

> **Caveat — don't use this in a `dyn`-compatible trait.** A generic or `impl Trait` parameter on a *trait method* makes the trait no longer `dyn`-compatible (formerly "object safe"), so `Box<dyn MyTrait>` / `&dyn MyTrait` stop compiling. In a trait you intend to use behind `dyn`, take the concrete borrowed type in the trait method and expose the flexible form as a wrapper — an inherent `impl dyn MyTrait`, or a default method bounded `where Self: Sized` (which keeps it out of the vtable):
>
> ```rust
> trait Loader {
> fn load(&self, path: &Path) -> io::Result<Vec<u8>>; // concrete type → `dyn Loader` works
> }
>
> impl dyn Loader {
> fn load_any(&self, path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
> self.load(path.as_ref()) // ergonomic wrapper, off the vtable
> }
> }
> ```
>
> Free functions and inherent methods have no such constraint — use the flexible form freely. See the dispatch section in [`architect.md`](./architect.md).

## Conversion method naming

Name conversions by cost, per the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/):

- **`as_`** — cheap, borrow-to-borrow, no allocation (`str::as_bytes`).
- **`to_`** — expensive, borrow-to-owned; it allocates (`str::to_string`).
- **`into_`** — consumes `self`, owned-to-owned (`String::into_bytes`).

Iterator producers are `iter` / `iter_mut` / `into_iter`; getters take no `get_` prefix (`config.timeout()`, not `config.get_timeout()`).

## Builder

```rust
Expand Down Expand Up @@ -182,3 +227,4 @@ pub fn fetch(key: &str) -> Result<Data, FetchError> { ... }
- [`developer.md`](./developer.md) — fuller rationale.
- [`gotchas.md`](./gotchas.md) — what to avoid.
- [Effective Rust](https://effective-rust.com/) · [The Rust Book](https://doc.rust-lang.org/book/) — the upstream practice references.
- [Idiomatic Rust](https://github.com/mre/idiomatic-rust) · [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/) — the idiomatic-Rust corpus and API conventions.
4 changes: 4 additions & 0 deletions languages/rust/reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ Per [reviewer-severity tier table](../../operating-model/gates-and-escalation.md
- **Public items are documented.** New `pub` items carry `///` docs (what it does, returns, errors, panics); examples are doc-tested (Effective Rust Item 27).
- **Dispatch is justified.** Generics / `impl Trait` on hot paths; `dyn Trait` only where heterogeneity or binary size earns the indirection.
- **Breaking changes are intentional.** Removing or renaming a `pub` item, or adding a constructible field, is a SemVer break — flag it. API-visible dependency types are re-exported.
- **Flexible input types.** Public functions take `&str` / `&[T]` / `impl AsRef<Path>` over `&String` / `&Vec<T>` / concrete owned types where reasonable.
- **Conversion and getter naming** follow the Rust API Guidelines: `as_` / `to_` / `into_` by cost, `iter` / `iter_mut` / `into_iter`, no `get_` prefix.
- **Enums over boolean parameters** where a `bool` argument erases intent at the call site.

### Concurrency primitives

Expand Down Expand Up @@ -96,3 +99,4 @@ Per [reviewer-severity tier table](../../operating-model/gates-and-escalation.md
- [`../../invariants/agent-era-invariants.md`](../../invariants/agent-era-invariants.md#7-no-bypass-of-reviewer-skill-hard-fail-findings) — HARD FAIL semantics; `unsafe` promotes here.
- Forest's [`AI_POLICY.md`](https://github.com/ChainSafe/forest/blob/main/AI_POLICY.md) — the Filecoin-specific extension.
- [Effective Rust](https://effective-rust.com/) · [The Rust Book](https://doc.rust-lang.org/book/) — canonical practice references (see [`sources.md`](../../references/sources.md)).
- [Idiomatic Rust](https://github.com/mre/idiomatic-rust) · [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/) — idiomatic-Rust corpus and API conventions.
10 changes: 9 additions & 1 deletion references/sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ Entries are added when the handbook starts deferring to a new source. Removal is
- **Used by.** [`../languages/rust/architect.md`](../languages/rust/architect.md), [`../languages/rust/developer.md`](../languages/rust/developer.md), [`../languages/rust/reviewer.md`](../languages/rust/reviewer.md), [`../languages/rust/idioms.md`](../languages/rust/idioms.md), [`../languages/rust/gotchas.md`](../languages/rust/gotchas.md). ChainSafe's canonical Rust codebase is [Forest](https://github.com/ChainSafe/forest) (Filecoin).
- **Coordination.** External upstream, treated as canonical for idiomatic Rust. **Effective Rust is CC-BY-NC-ND** — the handbook references and credits specific items by number and link; it does not reproduce or adapt the text. Re-anchor item links if the upstream reorganizes; the weekly link-check catches rot.

### Idiomatic Rust corpus + Rust API Guidelines

- **Source.** [mre/idiomatic-rust](https://github.com/mre/idiomatic-rust) — Matthias Endler's peer-reviewed collection of articles, talks, and repos that teach concise, idiomatic Rust (released **CC0** / public domain; sortable index at [corrode.dev/idiomatic-rust](https://corrode.dev/idiomatic-rust/)). The highest-leverage standards it points to are the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/) (the official idiomatic-API checklist), [Canonical's Rust Best Practices](https://canonical.github.io/rust-best-practices/), and [Elements of Rust](https://github.com/ferrous-systems/elements-of-rust).
- **Maintainer.** External — Matthias Endler (corpus) and the Rust library team (API Guidelines). Internal coordination point: the Rust CODEOWNER ([@LesnyRumcajs](https://github.com/LesnyRumcajs) / [@hanabi1224](https://github.com/hanabi1224)).
- **Covers.** Idiomatic, ergonomic Rust: flexible input types (`&str` / `&[T]` / `impl AsRef`), conversion and getter naming (`as_` / `to_` / `into_`, `iter` / `iter_mut` / `into_iter`, no `get_` prefix), enums over booleans to express intent, the common conversion traits (`From` / `Into` / `TryFrom` / `AsRef` / `Cow`), and simplicity over overengineering. Complements Effective Rust + The Rust Book; the handbook applies the principles rather than copying the corpus.
- **Used by.** [`../languages/rust/architect.md`](../languages/rust/architect.md), [`../languages/rust/developer.md`](../languages/rust/developer.md), [`../languages/rust/reviewer.md`](../languages/rust/reviewer.md), [`../languages/rust/idioms.md`](../languages/rust/idioms.md), [`../languages/rust/gotchas.md`](../languages/rust/gotchas.md).
- **Coordination.** External upstream. The corpus is CC0 (no attribution required; credited as a courtesy), and the Rust API Guidelines are the stable, authoritative reference for naming and API conventions. Re-anchor links if the upstream reorganizes; the weekly link-check catches rot.

### Effective Python (idiomatic Python)

- **Source.** [Effective Python](https://effectivepython.com/) by Brett Slatkin — *125 Specific Ways to Write Better Python* (3rd ed., Pearson Addison-Wesley; covers the language through Python 3.13). The book is copyrighted and not free online; the companion code is open at [bslatkin/effectivepython](https://github.com/bslatkin/effectivepython). The handbook references items by number and title, and does not reproduce the text.
Expand All @@ -103,7 +111,7 @@ Entries are added when the handbook starts deferring to a new source. Removal is
Surfacing known candidates rather than fabricating coverage:

- **Other internal artifacts to canonicalize.** When team members surface practices that exist in product repos or docs and could become canonical sources, they get added here with the original author credited (see [`./attribution.md`](./attribution.md)).
- **Language-specific upstream references.** Per-language reviewer pages may deep-link into language-community standards (e.g., the Rust API guidelines). Those entries are added here when a page starts deferring to one.
- **Language-specific upstream references.** Per-language reviewer pages may deep-link into language-community standards (e.g., Go's *Effective Go*, the TypeScript handbook). Those entries are added here when a page starts deferring to one.

## Related

Expand Down
Loading