nix-darwin/config/claude/skills/rust-style/SKILL.md
Rust coding style guide. Apply automatically when writing or modifying Rust code. Enforces for-loops over iterators, let-else for early returns, variable shadowing, newtypes, explicit matching, and minimal comments.
npx skillsauth add nubiv/my-nome rust-styleInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Apply these rules when writing or modifying any Rust code.
for Loops, Not Iterator ChainsWrite for loops with mutable accumulators instead of iterator combinators, unless returning an iterator is the goal.
// DO
let mut results = Vec::new();
for item in items {
if item.is_valid() {
results.push(item.process());
}
}
// DON'T
let results: Vec<_> = items
.iter()
.filter(|item| item.is_valid())
.map(|item| item.process())
.collect();
// DO
let mut total = 0;
for value in values {
total += value.amount();
}
// DON'T
let total: i64 = values.iter().map(|v| v.amount()).sum();
// DO
let mut found = None;
for item in items {
if item.matches(query) {
found = Some(item);
break;
}
}
// DON'T
let found = items.iter().find(|item| item.matches(query));
let ... elseUse let ... else to extract values and exit early on failure. This keeps the happy path unindented.
// DO
let Some(user) = get_user(id) else {
return Err(Error::NotFound);
};
let Ok(session) = user.active_session() else {
return Err(Error::NoSession);
};
// continue with user and session
// DON'T
if let Some(user) = get_user(id) {
if let Ok(session) = user.active_session() {
// deeply nested code
} else {
return Err(Error::NoSession);
}
} else {
return Err(Error::NotFound);
}
// DO
let Some(value) = maybe_value else { continue };
let Ok(parsed) = input.parse::<i32>() else { continue };
// DON'T
if let Some(value) = maybe_value {
if let Ok(parsed) = input.parse::<i32>() {
// ...
}
}
if letUse if let only when the Some/Ok branch is short and there's no else branch.
// ACCEPTABLE: short action, no else
if let Some(callback) = self.on_change {
callback();
}
// DO: use let-else when you need the value
let Some(config) = load_config() else {
return default_config();
};
// DO: use match for multiple cases
match result {
Ok(value) => process(value),
Err(Error::NotFound) => use_default(),
Err(e) => return Err(e),
}
Shadow variables through transformations. Avoid prefixes like raw_, parsed_, trimmed_.
// DO
let input = get_raw_input();
let input = input.trim();
let input = input.to_lowercase();
let input = parse(input)?;
// DON'T
let raw_input = get_raw_input();
let trimmed_input = raw_input.trim();
let lowercase_input = trimmed_input.to_lowercase();
let parsed_input = parse(lowercase_input)?;
// DO
let path = args.path;
let path = path.canonicalize()?;
let path = path.join("config.toml");
// DON'T
let input_path = args.path;
let canonical_path = input_path.canonicalize()?;
let config_path = canonical_path.join("config.toml");
// --- Section ---)Exception: Doc comments (///) on public items are required. See the rustdoc skill.
// DON'T
// Check if user is valid
if user.is_valid() {
// Update the timestamp
user.touch();
}
// --- Helper functions ---
// TODO: refactor this later
fn helper() { }
// Old implementation:
// fn old_way() { }
// DO
if user.is_valid() {
user.touch();
}
fn helper() { }
Wrap strings in newtypes to add semantic meaning and prevent mixing different string types.
// DO
struct UserId(String);
struct Email(String);
fn send_email(to: Email, from: UserId) { }
// DON'T
fn send_email(to: String, from: String) { }
Use enums with meaningful variant names instead of bool parameters.
// DO
enum Visibility {
Public,
Private,
}
fn create_repo(name: &str, visibility: Visibility) { }
// DON'T
fn create_repo(name: &str, is_public: bool) { }
// DO
enum Direction {
Forward,
Backward,
}
fn traverse(dir: Direction) { }
// DON'T
fn traverse(forward: bool) { }
Always match all variants explicitly to get compiler errors when variants are added.
// DO
match status {
Status::Pending => handle_pending(),
Status::Active => handle_active(),
Status::Completed => handle_completed(),
}
// DON'T
match status {
Status::Pending => handle_pending(),
_ => handle_other(),
}
If a wildcard seems necessary, ask the user before using it.
matches! MacroUse full match expressions instead of matches!. Full matches provide better compiler diagnostics when the matched type changes.
// DO
let is_ready = match state {
State::Ready => true,
State::Pending => false,
State::Failed => false,
};
// DON'T
let is_ready = matches!(state, State::Ready);
Destructure structs and tuples explicitly to get compiler errors when fields change.
// DO
let User { id, name, email } = user;
process(id, name, email);
// DON'T
process(user.id, user.name, user.email);
// DO
for Entry { key, value } in entries {
map.insert(key, value);
}
// DON'T
for entry in entries {
map.insert(entry.key, entry.value);
}
When searching or navigating Rust code, always use the LSP tool with rust-analyzer operations:
goToDefinition - Find where a symbol is definedfindReferences - Find all references to a symbolhover - Get type info and documentationdocumentSymbol - Get all symbols in a filegoToImplementation - Find trait implementationsdevelopment
Manage devlogs (session journal entries) under the active repo's `.claude/devlogs/`. Subcommands - `write` creates a new date-stamped entry, `read` loads existing entries into context. Use when the user invokes `/devlog <subcommand>` or asks to write, save, recall, or load today's/recent devlogs.
development
Run MY_WIKI operations (ingest, query, research, lint). Use when the user wants to add sources to the wiki, ask questions against it, research new topics from the web, or audit its quality.
testing
Create and edit Obsidian Flavored Markdown with wikilinks, embeds, callouts, properties, and other Obsidian-specific syntax. Use when working with .md files in Obsidian, or when the user mentions wikilinks, callouts, frontmatter, tags, embeds, or Obsidian notes.
tools
Interact with Obsidian vaults using the Obsidian CLI to read, create, search, and manage notes, tasks, properties, and more. Also supports plugin and theme development with commands to reload plugins, run JavaScript, capture errors, take screenshots, and inspect the DOM. Use when the user asks to interact with their Obsidian vault, manage notes, search vault content, perform vault operations from the command line, or develop and debug Obsidian plugins and themes.