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
&str
instead ofString
for 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 explicitmatch
onResult
- Use
Option<T>
instead of null-like patterns - Create custom error types with
thiserror
or implementstd::error::Error
- Use
-
Iterator Usage
- Use iterator methods (
map
,filter
,fold
,collect
) instead of explicit loops - Prefer
for
loops overwhile
when iterating - Use
enumerate()
instead of manual indexing - Use
zip()
for parallel iteration
- Use iterator methods (
-
Pattern Matching
- Use
match
for comprehensive pattern matching - Prefer
if let
for simple pattern extractions - Use destructuring in function parameters and let bindings
- Use
matches!
macro for simple boolean checks
- Use
-
Naming Conventions
- Use
snake_case
for functions, variables, and modules - Use
PascalCase
for types and traits - Use
SCREAMING_SNAKE_CASE
for 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
From
andInto
traits for type conversions, but only implementFrom
becauseInto
is 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.rs
andfoo/bar.rs
to create afoo
module 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_static
oronce_cell
for expensive static initialization - Consider using
SmallVec
for 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.,
'article
and'author
,'input
and'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.,
'tcx
in 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
String
where&str
would 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
/thiserror
for 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.