mirror of
https://github.com/rustfs/rustfs.git
synced 2026-11-01 08:40:23 +00:00
3.3 KiB
3.3 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
- Fallible public APIs use typed errors that fit the boundary, preferably an existing domain error or standard error type; do not return
Result<_, String>. - Preserve error variants callers need for recovery, aggregation, or quorum decisions. Use type-erased errors only when erasure is intentional in the boundary contract, not as a shortcut around error design.
- When implementing
std::error::Error, expose a stored inner error throughsource()so the error chain remains available. - 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 typed error handling; clamp or saturate only when the domain explicitly requires it. - Before converting floating-point input to an integer, validate finiteness, sign, and the destination range. A lower-bound clamp alone is insufficient.
- Review narrowing, signedness-changing, and float-to-integer casts against the value range and domain contract; do not require unrelated rewrites of proven lossless conversions.
Testing
- Keep unit tests close to the module they test.
- Keep integration tests under each crate's
tests/directory. - Add or update regression tests when existing tests do not directly cover the changed behavior; a bug regression should fail without the fix.
- 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.