rust-style

star 6

General Rust conventions for Pluto. Use it once for understanding the codebase better.

NethermindEth By NethermindEth schedule Updated 6/16/2026

name: rust-style description: General Rust conventions for Pluto. Use it once for understanding the codebase better.

Quality Gate

Run from pluto/ before declaring any work done:

cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features
cargo deny check

All must pass clean.


Error Handling

Define module-local error enums with thiserror:

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("message: {0}")]
    Variant(String),

    #[error(transparent)]
    Underlying(#[from] OtherError),
}

pub type Result<T> = std::result::Result<T, Error>;

Rules:

  • errors.New("msg") → enum variant with #[error("msg")] (match strings exactly)
  • errors.Wrap(err, "...")#[from] / #[source] where appropriate
  • Every field/payload in an error variant must appear in its #[error("...")] format string. If a field is not surfaced in the error message, either include it or remove it from the variant. Dead payload (captured but never displayed) is not allowed.
  • Always propagate with ?; never swallow errors with .ok() or filter_map in production code
  • No unwrap(), expect(), panic!() outside of test code
  • No anyhow in library crates; use typed errors everywhere

Arithmetic

All arithmetic must be checked — arithmetic_side_effects = "deny" is enforced:

// Bad
let x = a + b;

// Good
let x = a.checked_add(b).ok_or(Error::Overflow)?;

Casts

Never use as for numeric type conversions — use fallible conversions with try_from:

// Bad - will cause clippy errors
let x = value as u32;
let y = some_usize as u64;

// Good - use try_from with proper error handling
let x = u32::try_from(value)?;
let y = u64::try_from(some_usize).expect("message explaining why this is safe");

Rules:

  • Always use TryFrom/try_from for numeric conversions between different types
  • Handle conversion failures explicitly (either with ? or expect with justification)
  • The only acceptable use of expect is when the conversion is guaranteed to succeed (e.g., usize to u64 on 64-bit platforms)
  • Clippy will error on unchecked as casts: cast_possible_truncation, cast_possible_wrap, cast_sign_loss

Async / Tokio

  • Prefer async/await for I/O and network-bound code; use Tokio as the runtime.
  • In async contexts, use tokio::fs / tokio::io instead of blocking std::fs / std::io.
  • If you must call blocking or CPU-heavy code from async (crypto, large serialization, filesystem walks), isolate it with tokio::task::spawn_blocking.
  • Prefer Tokio sync primitives (tokio::sync::*) over std::sync::* when tasks may .await.
  • Use tokio::time for timeouts, sleeps, and intervals (avoid std::thread::sleep).

Code Style

  • Naming: modules/functions snake_case, types PascalCase, constants SCREAMING_SNAKE_CASE.
  • Formatting: prefer named arguments in formatting macros:
    • format!("hello {name}")
    • format!("hello {}", name)
  • Documentation:
    • Prefer copying doc comments from Go and adapting to Rust conventions (avoid “Type is a …”).
    • Avoid leaving TODOs in merged code. If a short-lived internal note is necessary, use // TODO: and remove before PR merge.

Generalized Parameter Types

Prefer generic parameters over concrete types when a function only needs the behavior of a trait. This mirrors the standard library's own conventions and makes functions callable with a wider range of inputs without extra allocations.

Instead of Prefer Accepts
&str impl AsRef<str> &str, String, &String, …
&Path impl AsRef<Path> &str, String, PathBuf, &Path, …
&[u8] impl AsRef<[u8]> &[u8], Vec<u8>, arrays, …
&Vec<T> impl AsRef<[T]> Vec<T>, slices, arrays, …
String (owned, read-only) impl Into<String> &str, String, …

Examples:

// accepts &str, String, PathBuf, &Path, …
fn read_file(path: impl AsRef<std::path::Path>) -> std::io::Result<String> {
    std::fs::read_to_string(path.as_ref())
}

// accepts &str, String, &String, …
fn print_message(msg: impl AsRef<str>) {
    println!(“{}”, msg.as_ref());
}

// accepts &[u8], Vec<u8>, arrays, …
fn hash_bytes(data: impl AsRef<[u8]>) -> [u8; 32] {
    sha256(data.as_ref())
}

Rules:

  • Call .as_ref() once at the top of the function and bind it to a local variable when the value is used in multiple places.
  • Do not use impl AsRef<T> if the function immediately converts to an owned type anyway — use impl Into<T> (or just accept the owned type) in that case.
  • Applies to public and private functions alike; the gain is ergonomics, not just API surface.

Testing

  • Translate Go tests to Rust where applicable; keep similar test names for cross-reference.
  • Reuse the same fixtures/golden files when possible.
  • Use #[tokio::test] for async tests.
  • Use test-case for repeated/parameterized tests (including async):
#[cfg(test)]
mod tests {
    use test_case::test_case;

    #[test_case(1, 2 ; "small")]
    #[test_case(10, 20 ; "large")]
    fn adds(a: u64, b: u64) {
        let _ = (a, b);
    }

    #[test_case("a" ; "case_a")]
    #[test_case("b" ; "case_b")]
    #[tokio::test]
    async fn async_cases(input: &str) {
        let _ = input;
    }
}
  • For hashing/serialization parity, generate Go-derived test vectors and hardcode them as Rust fixtures.

Pluto-Specific Checklist

Apply when reviewing or porting code:

  • Ordering::SeqCst is justified; prefer Relaxed/AcqRel for standalone flags.
  • Error::Io wraps std::io::Error (not String) to preserve ErrorKind.
  • New public functions accept impl AsRef<[u8]> / impl AsRef<str> rather than concrete slice refs where appropriate.
  • No unwrap() / expect() / panic!() outside test code.
  • All arithmetic uses checked ops (checked_add, checked_mul, …).
  • Tests mirror the Go test names and shapes where applicable.
  • use declarations appear before all other items in each file.
  • No dead payload in error variants (every captured field appears in the #[error("...")] string).
Install via CLI
npx skills add https://github.com/NethermindEth/pluto --skill rust-style
Repository Details
star Stars 6
call_split Forks 2
navigation Branch main
article Path SKILL.md
More from Creator
NethermindEth
NethermindEth Explore all skills →