- Prefer borrowing (
&T,&mut T) over cloning unless ownership transfer is semantically correct. - Avoid unnecessary
clone()— if you reach for it, reconsider the data flow. - Use
Cow<'_, T>when a function sometimes needs owned data and sometimes can borrow. - Return owned types from public APIs; accept borrowed types as arguments (
&strnotString,&[T]notVec<T>).
- Use
thiserrorfor library error types — deriveErroron an enum that covers each failure mode explicitly. - Never use
unwrap()orexpect()in library code (only in tests and examples). - Propagate errors with
?; only convert at API boundaries where the caller needs a different type. - Avoid
Box<dyn Error>in public APIs — callers can't match on it.
- Prefer iterators over index-based loops; they enable bound-check elision and better auto-vectorization.
- Annotate hot paths with
#[inline]and cold error paths with#[cold]. - Use
#[repr(C)]or#[repr(transparent)]on types that cross FFI or SIMD boundaries. - Avoid heap allocation in inner loops — preallocate buffers and pass them in.
- Profile before optimizing:
cargo flamegraphorperffirst.
- Minimize
unsafesurface — eachunsafeblock must have a// SAFETY:comment explaining the invariant upheld. - Encapsulate
unsafeinside safe abstractions; never let unsafe preconditions leak to callers. - Run
cargo miri testto catch UB in unsafe code.
- Follow the Rust API Guidelines.
- Use the builder pattern for types with many optional parameters.
- Implement standard traits where applicable:
Debug,Clone,PartialEq,Display,From/Into,Default. - Seal traits that are not intended for downstream implementation (
mod private { pub trait Sealed {} }). - Mark experimental or unstable items with
#[doc(hidden)]or a feature flag, not just a comment.
- Unit tests live in a
#[cfg(test)]module at the bottom of the file they test. - Integration tests go in
tests/and exercise the public API only. - Use
#[should_panic(expected = "...")]sparingly — preferResult-returning tests. - Benchmark with
criterion— add benches underbenches/.
- Code must pass
cargo clippy -- -D warningswith no suppressions unless justified. - Suppress a lint with
#[allow(clippy::lint_name)]at the narrowest scope, always with a comment explaining why. cargo fmtis non-negotiable — CI should enforce it.
- Add dependencies deliberately — evaluate maintenance status and compile-time cost.
- Prefer
no_std-compatible crates where possible to keep the library portable. - Specify minimum required versions, not
*.
- For BatchNorm kernels targeting Triton, never place
T::sum(or other reductions) insidescf.forloops. - Triton currently cannot lower reductions nested in
scf.for; keep reductions outside the loop structure. - If a refactor reintroduces an in-loop reduction, treat it as a compiler-compatibility bug and revert to the "reduce outside loop" pattern.