Awesome-omni-skill rust-clone-optimization
Use when optimizing Rust code to remove unnecessary .clone() calls, when asked to improve memory efficiency, or when reviewing code for excessive cloning
install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/devops/rust-clone-optimization" ~/.claude/skills/diegosouzapw-awesome-omni-skill-rust-clone-optimization && rm -rf "$T"
manifest:
skills/devops/rust-clone-optimization/SKILL.mdsource content
Rust Clone Optimization
Overview
Remove unnecessary
.clone() calls by using borrowing, reordering, or minimal structural changes. Prioritize simple solutions over clever ones.
When to Use
- Asked to "remove clones" or "optimize memory"
- Reviewing Rust code for efficiency
- Seeing many
calls in hot paths.clone()
When NOT to use:
/Arc::clone()
- these are cheap, intentionalRc::clone()- Cold paths with small data - optimization not worth complexity
- Prototyping phase - correctness before performance
Analysis Hierarchy
Try techniques in this order. Stop at the first that works.
1. REORDER → Move usage before the value is needed elsewhere 2. BORROW → Pass &T or &str instead of owned 3. COW → Cow<'_, str> for "sometimes owned" 4. STRUCTURAL → Change struct to hold references (last resort)
Never jump to step 4 before exhausting 1-3.
Quick Reference
| Clone Pattern | First Try | Example |
|---|---|---|
| Clone then move original | Reorder: use clone target first | Move after using |
| Check if caller accepts | not |
| Clone to avoid borrow conflict | Reorder operations | Extract data before mutable borrow |
| Clone in struct field assignment | Check if fits | |
| Clone inside loop | Clone once outside | |
Technique 1: Reorder
Before:
let username = login_state.username.clone(); let password = login_state.password.clone(); state.modal = Modal::LoginPending; // Invalidates login_state api.send(ApiCommand::Login { username, password });
After:
// Send BEFORE changing modal - no clone needed let cmd = ApiCommand::Login { username: login_state.username.clone(), // Still need if Login takes owned password: login_state.password.clone(), }; state.modal = Modal::LoginPending; api.send(cmd);
Check: Does
ApiCommand::Login need owned String? If it accepts &str, remove clones entirely.
Technique 2: Borrow
Before:
fn process(name: String) { println!("{}", name); } let task_name = task.name.clone(); process(task_name);
After:
fn process(name: &str) { println!("{}", name); } // Accept reference process(&task.name); // No clone
When to use: Function only reads the value, doesn't store it.
Technique 3: Cow
Before:
struct Form { name: String, // Always owned } // Must clone even for borrowed data form.name = borrowed_str.to_string();
After:
use std::borrow::Cow; struct Form<'a> { name: Cow<'a, str>, // Borrowed OR owned } // No clone for borrowed form.name = Cow::Borrowed(borrowed_str); // Clone only when needed form.name = Cow::Owned(compute_name());
When to use: Struct sometimes gets owned data, sometimes borrowed. Adds lifetime parameter.
Technique 4: Structural (Last Resort)
Change struct to hold references:
// Before: owns data struct EntryForm { task_name: String } // After: borrows data struct EntryForm<'a> { task_name: &'a str }
Costs:
- Adds lifetime parameters throughout
- May require significant refactoring
- Can complicate APIs
Only use when: Hot path with large data AND techniques 1-3 don't apply.
Common Mistakes
| Mistake | Why It's Wrong |
|---|---|
Using to avoid clone | Over-engineered; try reordering first |
| Removing Arc/Rc clones | These are O(1), intentional for sharing |
| Adding lifetimes everywhere | Complexity cost often exceeds clone cost |
| Optimizing cold paths | Profile first; don't optimize what doesn't matter |
Audit Process
- Find clones:
in target directoryrg '\.clone\(\)' - Categorize each:
- Arc/Rc → Skip (intentional)
- Hot path → Prioritize
- Cold path → Low priority
- For each hot-path clone:
- Can I reorder? → Do it
- Can caller accept
? → Change signature&T - Need "sometimes owned"? → Use
Cow - None work? → Consider if optimization is worth structural change
- Verify:
after each changecargo test
Checklist
- Identified Arc/Rc clones (skip these)
- Prioritized by hot path vs cold path
- Tried reordering before other techniques
- Checked if callers can accept references
- Only used Cow/structural changes when simpler options failed
- Ran tests after changes
- Kept changes minimal - no over-engineering