| name | rust-development |
| description | Rust language expertise for writing safe, performant, production-quality Rust code. Primary language for the Loom project. Use for Rust development, ownership patterns, error handling, async/await, cargo management, CLI tools, and serialization. |
Cargo and Project Structure
[package]
name = "myproject"
version = "0.1.0"
edition = "2021"
rust-version = "1.75"
[dependencies]
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
anyhow = "1.0"
[dev-dependencies]
criterion = "0.5"
mockall = "0.12"
[features]
default = []
full = ["feature-a", "feature-b"]
feature-a = []
feature-b = ["dep:optional-dep"]
[[bench]]
name = "my_benchmark"
harness = false
Workspace Structure
myworkspace/
├── Cargo.toml # Workspace root
├── crates/
│ ├── core/
│ │ ├── Cargo.toml
│ │ └── src/
│ ├── api/
│ │ ├── Cargo.toml
│ │ └── src/
│ └── cli/
│ ├── Cargo.toml
│ └── src/
Key Concepts
Ownership, Borrowing, and Lifetimes
fn take_ownership(s: String) {
println!("{}", s);
}
fn main() {
let s = String::from("hello");
take_ownership(s);
}
fn borrow(s: &String) {
println!("{}", s);
}
fn borrow_mut(s: &mut String) {
s.push_str(" world");
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
struct Parser<'a> {
input: &'a str,
position: usize,
}
impl<'a> Parser<'a> {
fn new(input: &'a str) -> Self {
Parser { input, position: 0 }
}
fn peek(&self) -> Option<char> {
self.input[self.position..].chars().next()
}
}
impl Config {
fn get(&self, key: &str) -> Option<&str> {
self.map.get(key).map(|s| s.as_str())
}
}
Error Handling
use std::error::Error;
use std::fmt;
use std::io;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("IO error: {0}")]
Io(#[from] io::Error),
#[error("Parse error at line {line}: {message}")]
Parse { line: usize, message: String },
#[error("Not found: {0}")]
NotFound(String),
#[error("Validation failed: {0}")]
Validation(String),
}
use anyhow::{Context, Result, bail, ensure};
fn read_config(path: &str) -> Result<Config> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("Failed to read config from {}", path))?;
let config: Config = serde_json::from_str(&content)
.context("Failed to parse config JSON")?;
ensure!(!config.name.is_empty(), "Config name cannot be empty");
if config.port == 0 {
bail!("Invalid port number");
}
Ok(config)
}
fn process_file(path: &str) -> Result<Vec<Record>, AppError> {
let content = std::fs::read_to_string(path)?;
let records = parse_records(&content)?;
Ok(records)
}
fn find_user(users: &[User], name: &str) -> Option<&User> {
users.iter().find(|u| u.name == name)
}
fn get_user_email(users: &[User], name: &str) -> Option<String> {
users
.iter()
.find(|u| u.name == name)
.and_then(|u| u.email.clone())
}
fn require_user(users: &[User], name: &str) -> Result<&User, AppError> {
users
.iter()
.find(|u| u.name == name)
.ok_or_else(|| AppError::NotFound(format!("User: {}", name)))
}
Traits and Generics
trait Repository<T> {
fn get(&self, id: &str) -> Option<&T>;
fn save(&mut self, item: T) -> Result<(), Box<dyn Error>>;
fn exists(&self, id: &str) -> bool {
self.get(id).is_some()
}
}
fn process<T: Clone + Debug>(item: &T) {
let cloned = item.clone();
println!("{:?}", cloned);
}
fn merge<T, U, V>(a: T, b: U) -> V
where
T: IntoIterator<Item = V>,
U: IntoIterator<Item = V>,
V: Ord + Clone,
{
let mut result: Vec<V> = a.into_iter().chain(b.into_iter()).collect();
result.sort();
result.dedup();
result.into_iter().next().unwrap()
}
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
struct InMemoryRepo<T> {
items: HashMap<String, T>,
}
impl<T: Clone> Repository<T> for InMemoryRepo<T> {
fn get(&self, id: &str) -> Option<&T> {
self.items.get(id)
}
fn save(&mut self, item: T) -> Result<(), Box<dyn Error>> {
Ok(())
}
}
impl<T: Display> ToString for T {
fn to_string(&self) -> String {
format!("{}", self)
}
}
Iterators
fn process_users(users: Vec<User>) -> Vec<String> {
users
.into_iter()
.filter(|u| u.active)
.map(|u| u.email)
.filter_map(|email| email)
.collect()
}
struct Counter {
current: usize,
max: usize,
}
impl Iterator for Counter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.max {
let val = self.current;
self.current += 1;
Some(val)
} else {
None
}
}
}
fn examples(numbers: Vec<i32>) {
let sum: i32 = numbers.iter().fold(0, |acc, x| acc + x);
let has_positive = numbers.iter().any(|&x| x > 0);
let all_positive = numbers.iter().all(|&x| x > 0);
let first_even = numbers.iter().find(|&&x| x % 2 == 0);
let (evens, odds): (Vec<_>, Vec<_>) = numbers.iter().partition(|&&x| x % 2 == 0);
for (index, value) in numbers.iter().enumerate() {
println!("{}: {}", index, value);
}
let other = vec![1, 2, 3];
let pairs: Vec<_> = numbers.iter().zip(other.iter()).collect();
}
Anti-Patterns
Avoid These Practices
fn process(items: &Vec<String>) {
for item in items.clone() {
println!("{}", item);
}
}
fn process(items: &[String]) {
for item in items {
println!("{}", item);
}
}
fn parse_config(s: &str) -> Config {
serde_json::from_str(s).unwrap()
}
fn parse_config(s: &str) -> Result<Config, serde_json::Error> {
serde_json::from_str(s)
}
struct Node {
value: i32,
children: Vec<Rc<RefCell<Node>>>,
}
struct Arena {
nodes: Vec<Node>,
}
struct Node {
value: i32,
children: Vec<usize>,
}
fn build_message(parts: &[&str]) -> String {
let mut result = String::new();
for part in parts {
result = result + part + ", ";
}
result
}
fn build_message(parts: &[&str]) -> String {
parts.join(", ")
}
fn parse(s: &str) -> Result<Data, Box<dyn Error>> {
}
fn parse(s: &str) -> Result<Data, ParseError> {
}
unsafe fn get_unchecked(slice: &[i32], index: usize) -> i32 {
*slice.get_unchecked(index)
}
fn get_unchecked(slice: &[i32], index: usize) -> i32 {
debug_assert!(index < slice.len());
unsafe { *slice.get_unchecked(index) }
}
let _ = fs::remove_file("temp.txt");
fs::remove_file("temp.txt").ok();
fs::remove_file("temp.txt")?;