Instruction file imported from wty92911/simple_proxy (
.cursor/rules/rust.mdc). Copyright stays with the author.
description: globs: /*.rs,/Cargo.toml alwaysApply: false
Rust Programming Guidelines
Basic Principles
- Use English for all code and documentation.
- Leverage Rust's strong type system and compile-time checks.
- Create appropriate types and structs/enums.
- Use rustdoc style comments to document public items.
- Don't leave blank lines within a function.
- Follow Rust's ownership and borrowing rules.
Nomenclature
- Use
snake_casefor functions, methods, variables, modules, and packages. - Use
UpperCamelCase(PascalCase) for types, traits, and enum variants. - Use
SCREAMING_SNAKE_CASEfor constants and static variables. - Use
snake_casefor file and directory names. - Use
UPPERCASEfor environment variables. - Avoid magic numbers and define constants.
- Start each function with a verb.
- Use verbs for boolean variables. Example:
is_loading,has_error,can_delete, etc. - Use complete words instead of abbreviations and ensure correct spelling.
- Except for standard abbreviations like API, URL, etc.
- Except for well-known abbreviations:
i,j,kfor loopserrfor errorsctxfor contextsreq,resfor request/response parameters
Functions
- Write short functions with a single purpose. Less than 20 lines.
- Name functions with a verb and something else.
- If it returns a boolean, use
is_xorhas_x,can_x, etc. - Avoid nesting blocks by:
- Early returns with pattern matching.
- Guard clauses.
- Extraction to helper functions.
- Use iterator methods (
map,filter,fold, etc.) instead of explicit loops when appropriate. - Use closures for simple operations.
- Use named functions for non-simple operations.
- Use Option's default parameters with
unwrap_or,unwrap_or_else, orunwrap_or_default. - Reduce function parameters using structs
- Use a struct to pass multiple parameters.
- Use a struct or tuple to return multiple results.
- Consider using the builder pattern for complex object construction.
- Use a single level of abstraction.
Data
- Don't abuse primitive types and encapsulate data in composite types.
- Use structs and enums to model your domain.
- Prefer immutability with
letoverlet mut. - Use
constfor compile-time constants. - Use
staticsparingly and preferconstwhen possible. - Use
Option<T>for possibly null values. - Use
Result<T, E>for operations that might fail. - Leverage the type system to make impossible states unrepresentable.
Structs and Traits
- Follow SOLID principles.
- Prefer composition over inheritance (via traits).
- Define behavior with traits.
- Write small structs with a single purpose.
- Less than 200 lines.
- Less than 10 public methods.
- Less than 10 fields.
- Implement the appropriate traits for your types (
Debug,Clone,PartialEq,Displayetc.). - If need to convert this struct from/to another, implement
From,TryFromwhenenver possible. - Prefer private fields with public accessor methods when appropriate.
- Use associated functions for constructors (
new,from_*, etc.).
Error Handling
- Use
Result<T, E>for functions that can fail. - Define custom error types for complex error handling.
- Use
?operator for propagating errors. - Consider using error handling crates like
anyhoworthiserror. - Provide context when converting between error types.
- Use meaningful error messages.
Memory Management
- Leverage Rust's ownership system and borrowing rules.
- Use references (
&Tand&mut T) rather than taking ownership when possible. - use
AtomicXXXif the shared data has an equivalentAtomicXXX. - Use
Rc<T>orArc<T>for shared ownership. - Use
RefCell<T>orMutex<T>for interior mutability. - For shared hash map, use papaya (read heavy) or dashmap.
- Avoid using
unsafecode unless absolutely necessary. - When using
unsafe, document why it's necessary and how safety is maintained.
Testing
- Follow the Arrange-Act-Assert convention for tests.
- Name test variables clearly.
- Follow the convention:
input_x,mock_x,actual_x,expected_x, etc. - Write unit tests for each public function.
- Use test doubles to simulate dependencies.
- Write integration tests in the
tests/directory. - Use property-based testing when appropriate.
- Use the
#[test]attribute for test functions. - Use the
#[cfg(test)]attribute for test modules.
Project Structure
- Use modular architecture
- Organize code into logical modules:
src/lib.rsfor library cratessrc/main.rsfor single binary cratessrc/bin/for multiple binariestests/for integration testsexamples/for example codebenches/for benchmarks
- Use the Cargo build system.
- Use workspaces for multi-crate projects.
- Split code into modules and sub-modules.
- Create a
coremodule for foundational components. - Create a
utilsmodule for utility functions.
Standard Library
- Use the Rust Standard Library whenever possible.
- Use
Stringand&strappropriately. - Use
Vec<T>,HashMap<K, V>,HashSet<T>, etc. for collections. - Use
Option<T>for optional values. - Use
Result<T, E>for fallible operations. - Use
std::pathandstd::fsfor file operations. - Use
std::timefor time-related operations.
Concurrency
- Use
std::threadfor thread-based concurrency. - Use channels (
std::sync::mpsc) for message passing. - Use
Arc<T>for sharing data between threads. - Use
Mutex<T>orRwLock<T>for shared mutable state. - Use
rayonfor parallel computations. - Avoid data races by proper synchronization.
Asynchronous
- Use multithreaded
tokiofor future based concurrency. - use tokio channels for message passing.
Dependencies
- Be conservative with dependencies.
- Evaluate a crate before adding it as a dependency.
- Consider maintenance status, documentation, and community support.
- Use semantic versioning in Cargo.toml.
- Regularly update dependencies for security and bug fixes.
- Consider using workspace-level dependency management.
