This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
{{crate_name}} is a Rust crate built with modern tooling, strict type safety, and zero-cost abstractions.
src/
├── lib.rs # Library entry point and public API
├── main.rs # Binary entry point (optional)
├── error.rs # Error types (if separated)
└── ... # Additional modules
tests/
└── integration_test.rs # Integration tests
benches/ # Benchmarks (with criterion)
examples/ # Example programs
This project uses Cargo as the build system.
# Build the project
cargo build
# Build with optimizations
cargo build --release
# Run tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run specific test
cargo test test_name
# Run benchmarks
cargo bench
# Run linting
cargo clippy --all-targets --all-features
# Format code
cargo fmt
# Check formatting
cargo fmt -- --check
# Generate documentation
cargo doc --open
# Check supply chain security
cargo deny check
# Run with MIRI (undefined behavior detection)
cargo +nightly miri test
# Run all checks (lint + format + test + doc + deny)
cargo fmt -- --check && cargo clippy --all-targets --all-features -- -D warnings && cargo test && cargo doc --no-deps && cargo deny checkThis project uses clippy with pedantic and nursery lints, and rustfmt for formatting.
- Line length: 100 characters
- Edition: 2024
- MSRV: 1.80
- Unsafe code: Forbidden unless explicitly justified
- Panics: Not allowed in library code (
unwrap,expect,panic!)
Always use Result types for fallible operations. Never panic in library code:
// Good - Returns Result
pub fn parse(input: &str) -> Result<Value, ParseError> {
if input.is_empty() {
return Err(ParseError::EmptyInput);
}
// parsing logic
Ok(value)
}
// Bad - Panics
pub fn parse(input: &str) -> Value {
input.parse().unwrap() // Never do this in library code
}Use thiserror for custom error types:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("invalid input: {0}")]
InvalidInput(String),
#[error("operation failed")]
OperationFailed {
#[source]
source: std::io::Error,
},
}All public items must have documentation with examples:
/// Processes the input data according to the configuration.
///
/// # Arguments
///
/// * `input` - The data to process.
/// * `config` - Processing configuration.
///
/// # Returns
///
/// The processed result.
///
/// # Errors
///
/// Returns [`Error::InvalidInput`] if the input is malformed.
///
/// # Examples
///
/// ```rust
/// use {{crate_name}}::{process, Config};
///
/// let result = process("data", &Config::default())?;
/// assert!(!result.is_empty());
/// # Ok::<(), {{crate_name}}::Error>(())
/// ```
pub fn process(input: &str, config: &Config) -> Result<Output, Error> {
// implementation
}Prefer borrowing over ownership:
// Good - borrows
pub fn process(data: &[u8]) -> Vec<u8> { ... }
// Avoid - takes ownership unnecessarily
pub fn process(data: Vec<u8>) -> Vec<u8> { ... }Use Cow for flexible string handling:
use std::borrow::Cow;
pub fn normalize(s: &str) -> Cow<'_, str> {
if s.contains(' ') {
Cow::Owned(s.replace(' ', "_"))
} else {
Cow::Borrowed(s)
}
}Use builder pattern for complex configuration:
#[derive(Debug, Clone, Default)]
pub struct Config {
timeout: Duration,
retries: u32,
}
impl Config {
#[must_use]
pub const fn new() -> Self {
Self {
timeout: Duration::from_secs(30),
retries: 3,
}
}
#[must_use]
pub const fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
#[must_use]
pub const fn with_retries(mut self, retries: u32) -> Self {
self.retries = retries;
self
}
}- Unit tests: Inside
src/*.rswith#[cfg(test)]modules - Integration tests:
tests/directory - Doc tests: Examples in documentation
- Property tests: Use
proptestfor property-based testing
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_success_case() {
let result = function_under_test(valid_input);
assert_eq!(result, expected_output);
}
#[test]
fn test_error_case() {
let result = function_under_test(invalid_input);
assert!(matches!(result, Err(Error::InvalidInput(_))));
}
}use proptest::prelude::*;
proptest! {
#[test]
fn property_holds(input in any::<i64>()) {
prop_assert!(predicate(input));
}
}Clippy is configured to deny:
unwrap_used,expect_used,panic- Use Result insteadtodo,unimplemented- Complete implementationdbg_macro,print_stdout,print_stderr- Use proper logging
This project uses cargo-deny to audit dependencies:
- Advisories: Deny crates with known vulnerabilities
- Licenses: Only allow permissive licenses (MIT, Apache-2.0, BSD)
- Bans: Block specific problematic crates
- Sources: Only allow crates.io
- Zero-cost abstractions: Prefer compile-time over runtime overhead
- Explicit over implicit: No hidden allocations or side effects
- Error propagation: Use
?operator, avoid.unwrap() - Const by default: Use
const fnwhere possible - Minimal dependencies: Only add what's truly needed
- Documentation-driven: Public API documented with examples
- Use
#[must_use]for functions returning values that should not be ignored - Prefer
&stroverStringin function parameters - Use
Vec::with_capacity()when size is known - Avoid allocations in hot paths
- Profile before optimizing
The CI pipeline includes:
- Format check:
cargo fmt -- --check - Lint:
cargo clippy --all-targets --all-features - Test:
cargo test --all-features - Documentation:
cargo doc --no-deps - Supply chain:
cargo deny check - MSRV check: Verify minimum supported Rust version
- Coverage: Generate code coverage reports