All skills
massimodeluisa avatar

/rust-best-practices

@d521b51

Write and review production Rust using the official API Guidelines, Style Guide, and this engineering standard: allocation contracts, ownership, Result vs panic, debug_assert, Clippy, tests, rustdoc, unsafe, and Cargo CI. Use when writing, reviewing, or refactoring Rust; choosing borrow vs clone; designing crate APIs; handling errors; bounding heap use; configuring clippy or rustfmt; or when the user runs /rust-best-practices. Do not use for other languages. Triggers: rust, rustc, cargo, clippy, rustfmt, ownership, clone, borrow, Result, unwrap, expect, panic, thiserror, anyhow, heapless, no_std, allocation, debug_assert, type-state, Send, Sync, unsafe, FFI, rustdoc, MSRV, rust-best-practices, rust style, rust guidelines

Use this Skill: https://skilld.dev/gh/massimodeluisa/rust-best-practices-skill/rust-best-practices

This session only. Nothing lands on disk.

referencesownership.md

≈986 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Ownership, borrowing, and values

Borrow by default

Take borrowed inputs unless ownership transfer is required.

fn checksum(bytes: &[u8]) -> u32 {
    bytes.iter().fold(0u32, |sum, byte| sum.wrapping_add(u32::from(*byte)))
}

Use: &str not &String; &[T] not &Vec<T>; &Path not &PathBuf; borrowed domain views rather than cloned domain objects.

A clone is appropriate when independent ownership is semantically required. Make the cost visible and intentional. NEVER clone only to satisfy the borrow checker before the ownership model is understood.

When clone is justified

  • The caller needs an independent snapshot while the original mutates.
  • Arc / Rc (clone is refcount, the value stays heap-backed; not strict heapless).
  • The underlying API requires owned data.
  • Caching a result that must outlive the borrow.
  • Avoiding a massive refactor on a non-hot path, with the cost documented.

Clone traps

  • Auto-cloning inside loops (.map(|x| x.clone())). Prefer .cloned() / .copied() at the iterator edge, or do not clone.
  • Cloning large Vec<T> or HashMap<K, V>.
  • Cloning because the API took the wrong ownership (fix the signature: if the callee needs ownership, take T, not &T then .clone()).
  • Cloning a Copy type (use assignment; Clippy clone_on_copy).

Leave a necessary clone as late as possible.

Pass small Copy values by value

Pass scalars, compact newtypes, and small Copy structs by value when that is clearer. Do not apply a universal byte threshold; measure ABI and target when size is in question.

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Range32 {
    pub start: u32,
    pub end: u32,
}

fn contains(range: Range32, value: u32) -> bool {
    value >= range.start && value < range.end
}

Derive Copy when every field is Copy, the type is a plain data object with no heap ownership, and it does not implement Iterator.

NEVER put Copy and Iterator on the same type. Copying an iterator and advancing one copy leaves the other untouched and silently yields wrong results. If a Copy type must be iterable, implement IntoIterator and return a separate iterator struct (core::range does this).

Large structs and non-Copy values SHOULD be borrowed unless the function consumes them.

Rust arrays are stack-allocated. A large Copy array copied by value can overflow the stack. Box large buffers, or take a slice. See allocation.md.

Enums sized to their largest variant: a huge payload makes every variant expensive to move. Consider boxing that variant on allocation-conscious code; on heapless code, redesign the layout.

Ownership transitions in names

Follow C-CONV:

Prefix Meaning
into_* consumes self
to_* usually creates an owned value; MAY allocate
as_* borrowed or inexpensive view

Document allocation when a conversion creates owned storage.

Indexes over pointer graphs

Prefer contiguous data and index-based relationships over linked object graphs. Indexes and offsets are easier to serialize, validate, borrow, cache, bound, move across FFI, and execute without allocation.

Use pointer-rich structures only when semantics and a measured workload justify the complexity.

Cow

Cow<'_, T> is valid when the API honestly may borrow or own. It is not a heapless escape hatch. Cow::into_owned() and APIs that silently transition borrowed to owned are forbidden on strict and allocation-free paths.

Early allocation in combinators

or, map_or, unwrap_or, ok_or evaluate the fallback immediately. If the fallback allocates or does work, use the _else form:

// Fallback is a cheap error value: ok_or is fine.
x.ok_or(ParseError::ValueAbsent)

// Fallback allocates: ok_or_else.
x.ok_or_else(|| ParseError::ValueAbsent)

Source: SKILL.md on GitHub

No alerts15d3 checks · Risk SAFE
  • Gen Agent Trust Hub15d

    The skill provides a comprehensive set of Rust engineering standards and best practices for writing and reviewing code. It covers memory allocation, API design, error handling, and performance optimization. No malicious behavior or security risks were identified.

  • Socket15d

    No alerts

  • Snyk15d

    Risk: LOW · No issues

Signed by skilld at d521b51. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 2 weeks ago
Other metadata
metadata
{
  "author": "massimodeluisa",
  "version": "1.0.0",
  "website": "https://www.rust-lang.org/"
}

README badge

README badge for massimodeluisa/rust-best-practices-skill