| description |
|---|
Rustify is a tool that turns Rust code into idiomatic Rust. |
Idiomatic coding means following the conventions of a given language. It is the most concise, convenient, and common way of accomplishing a task in that language, rather than forcing it to work in a way the author is familiar with from a different language.
Rust idiomatic code follows established patterns and conventions that make code:
- Safe: Leverages Rust's ownership system to prevent common bugs
- Readable: Follows naming conventions and community standards
- Maintainable: Uses proper error handling and clear structure
-
Ownership & Borrowing
- Prefer borrowing (
&T) over owned values when possible - Use
&strinstead ofStringfor function parameters - Return owned values from functions that create new data
- Use
Cow<str>for flexible string handling
- Prefer borrowing (
-
Error Handling
- Use
Result<T, E>for fallible operations - Prefer
?operator over explicitmatchonResult - Use
Option<T>instead of null-like patterns - Create custom error types with
thiserroror implementstd::error::Error
- Use
-
Iterator Usage
- Use iterator methods (
map,filter,fold,collect) instead of explicit loops - Prefer
forloops overwhilewhen iterating - Use
enumerate()instead of manual indexing - Use
zip()for parallel iteration
- Use iterator methods (
-
Pattern Matching
- Use
matchfor comprehensive pattern matching - Prefer
if letfor simple pattern extractions - Use destructuring in function parameters and let bindings
- Use
matches!macro for simple boolean checks
- Use
-
Naming Conventions
- Use
snake_casefor functions, variables, and modules - Use
PascalCasefor types and traits - Use
SCREAMING_SNAKE_CASEfor constants - Use descriptive names that express intent
- Choose lifetime names that are relevant to the surrounding context and improve clarity
- Use
-
Memory Management
- Avoid unnecessary
clone()calls - Use
Vec::with_capacity()when size is known - Prefer
&[T]over&Vec<T>for function parameters - Use
Box<T>for heap allocation when needed
- Avoid unnecessary
-
Trait Usage
- Implement standard traits (
Debug,Clone,PartialEq,Eq,Hash) when appropriate - Use trait objects (
dyn Trait) for dynamic dispatch - Prefer generic functions over trait objects when possible
- Use
FromandIntotraits for type conversions, but only implementFrombecauseIntois automatically implemented
- Implement standard traits (
-
Struct and Enum Design
- Use
#[derive(...)]for common traits - Prefer tuple structs for simple wrappers
- Use
#[non_exhaustive]for public enums that might grow - Make fields private and provide accessor methods
- Use
-
Module Organization
- Do not use
mod.rs, that is an outdated convention. Use the newer Rust edition module convention. For example, usefoo.rsandfoo/bar.rsto create afoomodule with a submodulebar. - Re-export important types at crate root
- Use
pub(crate)for internal APIs - Group related functionality in modules
- Do not use
-
Performance Patterns
- Use
String::push_str()instead of repeated concatenation - Prefer
format!over string concatenation for complex formatting - Use
lazy_staticoronce_cellfor expensive static initialization - Consider using
SmallVecfor small collections
- Use
-
Lifetime Naming
- Choose lifetime names that are meaningful in the context of the function or struct they're used in
- Single-letter lifetimes (
'a,'b) are perfectly fine for simple cases and small functions - Use descriptive names when they improve clarity, especially in complex scenarios:
- For long-lived common owners: names that indicate the source (e.g.,
'provider,'context,'arena) - For multiple borrow sources: names that disambiguate origins (e.g.,
'articleand'author,'inputand'output) - Domain-specific names that make sense in your code's context
- For long-lived common owners: names that indicate the source (e.g.,
- Look to established conventions in the Rust ecosystem for inspiration (e.g.,
'tcxin rustc) - Prioritize readability over brevity when lifetime relationships are complex
Analyze the provided context and, if it contains Rust code, apply the following steps to make it more idiomatic:
-
Identify non-idiomatic patterns in the code with specific examples
-
Suggest specific improvements with clear explanations of why each change is better
-
Provide corrected code examples showing the idiomatic version side-by-side
-
Explain the benefits of each suggestion (safety, performance, readability, maintainability)
-
Prioritize suggestions by impact:
- 🔴 High Priority: Safety issues, major performance problems
- 🟡 Medium Priority: Readability improvements, minor performance gains
- 🟢 Low Priority: Style consistency, conventions
-
Check for common anti-patterns:
- Using
unwrap()instead of proper error handling, or instead of usingexpect() - Unnecessary
clone()calls - Using
Stringwhere&strwould suffice - Manual loops instead of iterators
- Not using the
?operator for error propagation
- Using
-
Suggest appropriate crates when they would make code more idiomatic, but only when it would make sense to do so:
anyhow/thiserrorfor error handling
Focus on practical improvements that align with Rust's philosophy of "zero-cost abstractions" and "memory safety without garbage collection." Always explain the reasoning behind suggestions to help the user understand Rust idioms better.