Skip to content

Instantly share code, notes, and snippets.

@ivandardi
Created July 8, 2025 23:36
Show Gist options
  • Save ivandardi/096bfa997c0e0bcab3adf027eda701ce to your computer and use it in GitHub Desktop.
Save ivandardi/096bfa997c0e0bcab3adf027eda701ce to your computer and use it in GitHub Desktop.
Github Copilot instruction file for the `rustify` command
description
Rustify is a tool that turns Rust code into idiomatic Rust.

What "Rust Idiomatic" Means

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

Key Rust Idioms to Check For:

  1. Ownership & Borrowing

    • Prefer borrowing (&T) over owned values when possible
    • Use &str instead of String for function parameters
    • Return owned values from functions that create new data
    • Use Cow<str> for flexible string handling
  2. Error Handling

    • Use Result<T, E> for fallible operations
    • Prefer ? operator over explicit match on Result
    • Use Option<T> instead of null-like patterns
    • Create custom error types with thiserror or implement std::error::Error
  3. Iterator Usage

    • Use iterator methods (map, filter, fold, collect) instead of explicit loops
    • Prefer for loops over while when iterating
    • Use enumerate() instead of manual indexing
    • Use zip() for parallel iteration
  4. 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
  5. 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
  6. 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
  7. 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 and Into traits for type conversions, but only implement From because Into is automatically implemented
  8. 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
  9. Module Organization

    • Do not use mod.rs, that is an outdated convention. Use the newer Rust edition module convention. For example, use foo.rs and foo/bar.rs to create a foo module with a submodule bar.
    • Re-export important types at crate root
    • Use pub(crate) for internal APIs
    • Group related functionality in modules
  10. Performance Patterns

    • Use String::push_str() instead of repeated concatenation
    • Prefer format! over string concatenation for complex formatting
    • Use lazy_static or once_cell for expensive static initialization
    • Consider using SmallVec for small collections
  11. 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
    • Look to established conventions in the Rust ecosystem for inspiration (e.g., 'tcx in rustc)
    • Prioritize readability over brevity when lifetime relationships are complex

Instructions

Analyze the provided context and, if it contains Rust code, apply the following steps to make it more idiomatic:

  1. Identify non-idiomatic patterns in the code with specific examples

  2. Suggest specific improvements with clear explanations of why each change is better

  3. Provide corrected code examples showing the idiomatic version side-by-side

  4. Explain the benefits of each suggestion (safety, performance, readability, maintainability)

  5. Prioritize suggestions by impact:

    • 🔴 High Priority: Safety issues, major performance problems
    • 🟡 Medium Priority: Readability improvements, minor performance gains
    • 🟢 Low Priority: Style consistency, conventions
  6. Check for common anti-patterns:

    • Using unwrap() instead of proper error handling, or instead of using expect()
    • Unnecessary clone() calls
    • Using String where &str would suffice
    • Manual loops instead of iterators
    • Not using the ? operator for error propagation
  7. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment