HASH Rust coding style. Use when writing or reviewing Rust code, choosing types, imports, function arguments, or naming.
63
75%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./.agents/skills/rust-coding-style/SKILL.mdderive_more over manual trait implementations#[cfg(feature = "...")] patterncargo clippy with --all-features, --all-targets, and --no-deps from the rootcargo doc --no-deps --all-features for checking documentationrustfmt to format the code#[expect(lint, reason = "...")] over #[allow(lint)]pub)#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, derive_more::Display)]
pub struct UserId(Uuid);impl Future<Output = T> + Send in trait definitions:fn get_data(
&self,
id: String,
) -> impl Future<Output = Result<Data, Report<DataError>>> + Send {
async move {
// Implementation
}
}const whenever possible.impl AsRef<str> instead of &str or &Stringimpl AsRef<Path> instead of &Path or &PathBufimpl IntoIterator<Item = &T> when only iterating over the data&[T] instead of &Vec<T>&mut [T] instead of &mut Vec<T> when the function doesn't need to resize the vectorimpl Into<Cow<T>> instead of Cow<T>impl Into<Arc<T>> instead of Arc<T>impl Into<Rc<T>> instead of Rc<T>impl Into<Box<T>> instead of Box<T>impl Into<Option<_>> as from reading the caller site, it's not visible that None could potentially be passedFrom and IntoFrom implementations over Into implementations. The Rust compiler will automatically derive Into from From, but not vice versa.from method over into for clarity. The from method makes the target type explicit in the code, while into requires type inference.Cow, Arc, Rc, Report, and Box, prefer using explicit constructors (e.g., Cow::from, Arc::new) instead of .into(). This improves readability by clearly indicating the target type.Arc and Rc, always use Arc::clone(&pointer) and Rc::clone(&pointer) instead of pointer.clone(). This explicitly indicates you're cloning the reference, not the underlying data.#[tracing::instrument]tracing macros (e.g., trace!, debug!, info!, warn!, error!) instead of println! or eprintln! for loggingVec in a loop instead of creating a new one in each iteration.For example:
struct UserId(u64); // instead of `type UserId = u64;` or `u64`When suggesting names for variables, functions, or types:
test_, this would otherwise result in test::test_<name> names.Http or Json is acceptable, but Ctx instead of Context is not)users instead of usersList)user instead of userUser)similar_asserts for test assertionsinsta for snapshot teststest_log for better test output (#[test_log::test])tracing macros, not log macrostracing::instrument for function instrumentationuse super::*;, or use crate::module::*;use crate::prelude::*core over alloc over std for imports to minimize dependencies
core for functionality that doesn't require allocationalloc when you need allocation but not OS-specific featuresstd when necessary for OS interactions or when using core/alloc would be unnecessarily complexuse foo::Bar; let x = Bar::new()) over fully qualified paths (let x = foo::Bar::new()) for frequently used typespub use re-exports in module roots to create a clean public APIuse module::Trait as _; when you only need the trait's methods and not the trait name itself
// Good - Importing a trait just for its methods:
use std::io::Read as _;
// Example with trait methods:
fn read_file(file: &mut File) -> Result<String, std::io::Error> {
// Read methods available without importing the Read trait name
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
// Bad - Directly importing trait when only methods are needed:
use std::io::Read;
// Good - Importing trait for implementing it:
use std::io::Write;
impl Write for MyWriter { /* implementation */ }
// Bad - Wildcard import:
mod tests {
use super::*; // Wildcard import
#[test]
fn test_something() {
// Test implementation
}
}
// Good - Explicit imports:
mod tests {
use crate::MyStruct;
use crate::my_function;
#[test]
fn test_something() {
// Test implementation
}
}
// Bad - Local import:
fn process_data() {
use std::collections::HashMap; // Local import
let map = HashMap::new();
// Implementation
}
// Good - Module-level import:
use std::collections::HashMap;
fn process_data() {
let map = HashMap::new();
// Implementation
}
// Bad - Using std when core would suffice:
use std::fmt::Display;
// Good - Using core for non-allocating functionality:
use core::fmt::Display;
// Bad - Using std when alloc would suffice:
use std::collections::BTreeSet;
// Good - Using alloc for allocation without full std dependency:
use alloc::vec::Vec;
// Appropriate - Using std when needed:
use std::fs::File; // OS-specific functionality requires stdexpect() messages should follow the format "should ..." to clearly indicate the expected behaviorFor example:
// Bad:
assert_eq!(result, expected); // This should match the expected value
// Good:
assert_eq!(result, expected, "Values should match expected output");
// Bad:
some_value.expect("The value is not None"); // This should never happen
// Good:
some_value.expect("should contain a valid value");a6f5727
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.