rust-systems-programming

Master Rust's memory safety guarantees, ownership model, and systems programming patterns for building reliable, high-performance software. Use when building systems software, performance-critical applications, or learning Rust idioms.

coppermare/skillverse1 installsMITSynced Aug 27

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI

Agent Skills format with YAML frontmatter. Claude Code reads it as-is.

---
name: "rust-systems-programming"
description: "Master Rust's memory safety guarantees, ownership model, and systems programming patterns for building reliable, high-performance software. Use when building systems software, performance-critical applications, or learning Rust idioms."
license: "MIT"
---

# Rust Systems Programming

Master Rust's unique approach to memory safety through ownership, borrowing, and lifetimes while building high-performance systems software without garbage collection overhead.

## When to Use This Skill

- Building systems software (OS components, drivers, embedded)
- Developing performance-critical applications
- Creating memory-safe concurrent programs
- Writing CLI tools and utilities
- Building WebAssembly applications
- Implementing network services and protocols
- Refactoring C/C++ code for safety

## Core Concepts

### 1. Ownership

**The Foundation of Rust's Memory Safety**

```rust
fn main() {
    // Each value has exactly one owner
    let s1 = String::from("hello");

    // Ownership moves to s2, s1 is no longer valid
    let s2 = s1;
    // println!("{}", s1); // Error: value borrowed after move

    // Clone for deep copy
    let s3 = s2.clone();
    println!("s2: {}, s3: {}", s2, s3);

    // Transfer ownership to function
    takes_ownership(s3);
    // s3 is no longer valid here

    // Primitives implement Copy trait
    let x = 5;
    let y = x; // Copy, not move
    println!("x: {}, y: {}", x, y);
}

fn takes_ownership(s: String) {
    println!("{}", s);
} // s is dropped here
```

### 2. Borrowing and References

**Access Without Ownership Transfer**

```rust
fn main() {
    let s = String::from("hello");

    // Immutable borrow
    let len = calculate_length(&s);
    println!("Length of '{}' is {}", s, len);

    // Mutable borrow
    let mut s2 = String::from("hello");
    change(&mut s2);
    println!("{}", s2);
}

fn calculate_length(s: &String) -> usize {
    s.len()
} // s goes out of scope but doesn't drop the value

fn change(s: &mut String) {
    s.push_str(", world");
}

// Borrowing rules:
// 1. At any time, you can have EITHER one mutable reference OR any number of immutable references
// 2. References must always be valid
```

### 3. Lifetimes

**Ensuring Reference Validity**

```rust
// Lifetime annotation ensures returned reference lives long enough
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

// Struct with references needs lifetime annotation
struct ImportantExcerpt<'a> {
    part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }

    // Lifetime elision rules apply
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().unwrap();
    let excerpt = ImportantExcerpt {
        part: first_sentence,
    };
    println!("{}", excerpt.part);
}
```

## Essential Patterns

### Pattern 1: Error Handling with Result

```rust
use std::fs::File;
use std::io::{self, Read};

// Custom error type
#[derive(Debug)]
enum AppError {
    IoError(io::Error),
    ParseError(String),
    NotFound(String),
}

impl From<io::Error> for AppError {
    fn from(error: io::Error) -> Self {
        AppError::IoError(error)
    }
}

// Using Result for error handling
fn read_config(path: &str) -> Result<String, AppError> {
    let mut file = File::open(path)?; // ? propagates errors
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

// Combining Results
fn process_file(path: &str) -> Result<i32, AppError> {
    let contents = read_config(path)?;
    let number: i32 = contents
        .trim()
        .parse()
        .map_err(|_| AppError::ParseError("Invalid number".to_string()))?;
    Ok(number * 2)
}

fn main() {
    match process_file("config.txt") {
        Ok(result) => println!("Result: {}", result),
        Err(e) => eprintln!("Error: {:?}", e),
    }
}
```

### Pattern 2: Traits and Generics

```rust
use std::fmt::Display;

// Define a trait
trait Summary {
    fn summarize(&self) -> String;

    // Default implementation
    fn summarize_author(&self) -> String {
        String::from("(unknown author)")
    }
}

struct Article {
    headline: String,
    content: String,
    author: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{}, by {}", self.headline, self.author)
    }

    fn summarize_author(&self) -> String {
        format!("@{}", self.author)
    }
}

// Generic function with trait bounds
fn notify<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

// Multiple trait bounds
fn complex_notify<T: Summary + Display>(item: &T) {
    println!("{}", item);
}

// where clause for cleaner syntax
fn some_function<T, U>(t: &T, u: &U) -> i32
where
    T: Display + Summary,
    U: Clone + Summary,
{
    println!("{}", t.summarize());
    0
}

// Returning types that implement traits
fn returns_summarizable() -> impl Summary {
    Article {
        headline: String::from("Breaking"),
        content: String::from("Content here"),
        author: String::from("Author"),
    }
}
```

### Pattern 3: Smart Pointers

```rust
use std::cell::RefCell;
use std::rc::Rc;

// Box<T> - heap allocation
fn box_example() {
    let b = Box::new(5);
    println!("b = {}", b);

    // Recursive types
    enum List {
        Cons(i32, Box<List>),
        Nil,
    }

    use List::{Cons, Nil};
    let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}

// Rc<T> - reference counting for multiple ownership
fn rc_example() {
    let a = Rc::new(5);
    println!("count after creating a = {}", Rc::strong_count(&a));

    let b = Rc::clone(&a);
    println!("count after creating b = {}", Rc::strong_count(&a));

    {
        let c = Rc::clone(&a);
        println!("count after creating c = {}", Rc::strong_count(&a));
    }

    println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}

// RefCell<T> - interior mutability
fn refcell_example() {
    let data = RefCell::new(5);

    // Borrow mutably at runtime
    *data.borrow_mut() += 1;

    println!("data = {:?}", data.borrow());
}

// Combining Rc and RefCell for multiple owners with mutability
fn combined_example() {
    let value = Rc::new(RefCell::new(5));

    let a = Rc::clone(&value);
    let b = Rc::clone(&value);

    *value.borrow_mut() += 10;

    println!("a = {:?}", a.borrow());
    println!("b = {:?}", b.borrow());
}
```

### Pattern 4: Concurrency

```rust
use std::sync::{Arc, Mutex, mpsc};
use std::thread;

// Spawning threads
fn basic_threads() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from spawned thread", i);
            thread::sleep(std::time::Duration::from_millis(1));
        }
    });

    handle.join().unwrap();
}

// Move closures for ownership transfer
fn move_closure() {
    let v = vec![1, 2, 3];

    let handle = thread::spawn(move || {
        println!("vector: {:?}", v);
    });

    handle.join().unwrap();
}

// Message passing with channels
fn channels() {
    let (tx, rx) = mpsc::channel();

    let tx1 = tx.clone();
    thread::spawn(move || {
        let vals = vec!["hi", "from", "thread"];
        for val in vals {
            tx1.send(val.to_string()).unwrap();
            thread::sleep(std::time::Duration::from_millis(100));
        }
    });

    thread::spawn(move || {
        let vals = vec!["more", "messages"];
        for val in vals {
            tx.send(val.to_string()).unwrap();
            thread::sleep(std::time::Duration::from_millis(100));
        }
    });

    for received in rx {
        println!("Got: {}", received);
    }
}

// Shared state with Mutex and Arc
fn shared_state() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}
```

### Pattern 5: Async/Await

```rust
use tokio;

// Async function
async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

// Concurrent execution
async fn fetch_multiple() {
    let urls = vec![
        "https://api.example.com/1",
        "https://api.example.com/2",
        "https://api.example.com/3",
    ];

    let futures: Vec<_> = urls.iter().map(|url| fetch_data(url)).collect();
    let results = futures::future::join_all(futures).await;

    for result in results {
        match result {
            Ok(data) => println!("Got: {}", &data[..100.min(data.len())]),
            Err(e) => eprintln!("Error: {}", e),
        }
    }
}

// Tokio runtime
#[tokio::main]
async fn main() {
    fetch_multiple().await;
}
```

### Pattern 6: Builder Pattern

```rust
#[derive(Debug)]
struct Server {
    host: String,
    port: u16,
    max_connections: u32,
    timeout: u64,
}

#[derive(Default)]
struct ServerBuilder {
    host: Option<String>,
    port: Option<u16>,
    max_connections: Option<u32>,
    timeout: Option<u64>,
}

impl ServerBuilder {
    fn new() -> Self {
        ServerBuilder::default()
    }

    fn host(mut self, host: impl Into<String>) -> Self {
        self.host = Some(host.into());
        self
    }

    fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }

    fn max_connections(mut self, max: u32) -> Self {
        self.max_connections = Some(max);
        self
    }

    fn timeout(mut self, timeout: u64) -> Self {
        self.timeout = Some(timeout);
        self
    }

    fn build(self) -> Result<Server, &'static str> {
        Ok(Server {
            host: self.host.ok_or("host is required")?,
            port: self.port.unwrap_or(8080),
            max_connections: self.max_connections.unwrap_or(100),
            timeout: self.timeout.unwrap_or(30),
        })
    }
}

fn main() {
    let server = ServerBuilder::new()
        .host("localhost")
        .port(3000)
        .max_connections(500)
        .build()
        .unwrap();

    println!("{:?}", server);
}
```

## Best Practices

### 1. Prefer References Over Ownership

```rust
// BAD: Unnecessary ownership transfer
fn process_bad(data: String) {
    println!("{}", data);
}

// GOOD: Borrow when you don't need ownership
fn process_good(data: &str) {
    println!("{}", data);
}
```

### 2. Use Iterators and Closures

```rust
// Functional style with iterators
let numbers = vec![1, 2, 3, 4, 5];

let sum: i32 = numbers
    .iter()
    .filter(|&x| x % 2 == 0)
    .map(|x| x * 2)
    .sum();

println!("Sum of doubled evens: {}", sum);
```

### 3. Handle All Error Cases

```rust
// Use ? operator for propagation
fn read_file(path: &str) -> Result<String, std::io::Error> {
    std::fs::read_to_string(path)
}

// Use expect() with meaningful messages
let file = File::open("config.txt")
    .expect("Failed to open config.txt - ensure file exists");
```

### 4. Leverage the Type System

```rust
// Newtype pattern for type safety
struct UserId(u64);
struct OrderId(u64);

fn process_user(id: UserId) {
    // Can't accidentally pass OrderId
}
```

## Common Pitfalls

- **Fighting the Borrow Checker**: Work with it, not against it
- **Overusing Clone**: Expensive operation, prefer borrowing
- **Ignoring Results**: Always handle potential errors
- **Unnecessary Mutability**: Prefer immutable by default
- **Lifetime Annotation Anxiety**: Compiler often helps with elision
- **Blocking in Async**: Use async-aware operations

## Resources

- The Rust Programming Language (The Book)
- Rust by Example
- Rustlings exercises
- Rust API Guidelines
- Asynchronous Programming in Rust

More General & Other skills

← All General & Other skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY