mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-22 20:36:38 +00:00
3.0 KiB
3.0 KiB
Crates Instructions
Applies to all paths under crates/.
Library Design
- Treat crate code as reusable library code by default.
- Prefer
thiserrorfor library-facing error types. - Do not use
unwrap(),expect(), or panic-driven control flow outside tests.
Error Type Design
- Public API functions must return a typed error enum (preferably
thiserror-derived), neverResult<_, String>. - Do not use
Box<dyn Error>orBox<dyn Error + Send + Sync>in public trait methods or struct methods. Define a concrete error type with specific variants. - When implementing
std::error::Error, always overridefn source()if you store an inner error. Breaking the error chain makes debugging impossible. - Internal helpers that return
Result<_, String>and are immediately wrapped via.map_err(Error::other)should return the actual error type directly.
Concurrency
- Document lock acquisition order when a module uses multiple locks. Never acquire the same set of locks in different orders across code paths.
- Never hold a
tokio::sync::RwLock/Mutexwrite guard across.awaitpoints unless the critical section is unavoidably async and the hold time is bounded. - Prefer direct atomic
fetch_*operations for unconditional updates andcompare_exchangeloops only for conditional updates such as peaks or adaptive state. - When resetting multi-field atomic statistics, use a version/sequence counter or accept that concurrent readers may see partial snapshots; document the tradeoff.
std::sync::Mutexis acceptable in async context only when held for a brief, non-await-containing critical section. If in doubt, usetokio::sync::Mutex.
Recursion Safety
- Recursive tree/graph traversals must have a depth limit (e.g.,
max_depthcounter) or use an iterative approach with an explicitVecstack. - This applies to cache trees, directory walks, and any user-influenced hierarchy.
- A corrupted or malicious input must not be able to overflow the thread stack.
Type Casting
- Never use
asfor numeric conversions that may truncate or overflow. Usetry_into()with explicit error handling, or clamp withvalue.max(0) as usizewhen the domain is bounded. f64 as usizesaturates but is fragile; clamp to[0, usize::MAX as f64]first.- Treat every
ascast in a PR review as a potential bug; require justification.
Testing
- Keep unit tests close to the module they test.
- Keep integration tests under each crate's
tests/directory. - Add regression tests for bug fixes and behavior changes.
- Every test needs an observable failure criterion. Direct assertions,
delegated assertions, snapshots/properties,
#[should_panic], and meaningfulResultfailures are all valid; a call that can silently succeed is not. - In tests, prefer
.expect("context: what was being tested")over bare.unwrap(). A test failure should tell you which operation failed and with what input.
Async and Performance
- Keep async paths non-blocking.
- Move CPU-heavy operations out of async hot paths with
tokio::task::spawn_blockingwhen appropriate.