12 Prompts for Rust: Systems Programming, CLI, and WebAssembly
Rust has become one of the most trusted languages for building safe, fast systems software. According to the Stack Overflow 2025 Developer Survey, Rust remains the most admired language for the ninth consecutive year, with 87% of developers expressing interest in continuing to use it. But writing idiomatic Rust—especially for CLI tools, WebAssembly (WASM) targets, or low-level systems code—can be tricky. The following 12 prompts are designed to help you generate production-ready Rust code, debug common pitfalls, and accelerate your workflow. Each prompt includes a specific task, a usage example, and a code snippet to get you started.
1. Safe Memory Management with Ownership and Borrowing
Task: Generate a function that demonstrates Rust’s ownership model with a vector of strings, avoiding unnecessary clones.
Usage example: You have a list of user names and need to pass them to a processing function without copying the entire vector.
Prompt: “Write a Rust function process_names that takes ownership of a Vec<String>, iterates over each name, prints it, and then returns the vector back to the caller. Use borrowing to avoid cloning where possible.”
fn process_names(mut names: Vec<String>) -> Vec<String> {
for name in &names {
println!("Processing: {}", name);
}
names
}
fn main() {
let names = vec!["Alice".to_string(), "Bob".to_string()];
let names = process_names(names);
println!("Names still owned: {:?}", names);
}
This snippet shows how to move ownership into a function and return it, which is a common pattern in systems programming when you need to reuse a resource.
2. Parsing CLI Arguments with clap
Task: Build a minimal CLI tool that accepts a file path and an optional verbosity flag.
Usage example: You are creating a log analyzer that reads a file and optionally prints debug info.
Prompt: “Create a Rust CLI using the clap crate (version 4.x) that accepts a required positional argument --file and an optional flag --verbose. Parse the arguments and print them.”
use clap::Parser;
#[derive(Parser)]
#[command(name = "loganalyzer")]
struct Cli {
/// Path to the log file
file: String,
/// Enable verbose output
#[arg(short, long)]
verbose: bool,
}
fn main() {
let cli = Cli::parse();
println!("File: {}, Verbose: {}", cli.file, cli.verbose);
}
This pattern is used in thousands of Rust CLI tools, from ripgrep to bat. The clap crate automatically generates help text and error messages.
3. Error Handling with anyhow and thiserror
Task: Write a function that reads a file and parses it as JSON, returning a user-friendly error.
Usage example: You are building a configuration loader for a WASM module and want clear error messages.
Prompt: “Use anyhow::Result and thiserror to define a custom error enum ConfigError for a function that reads a JSON config file. Return Ok(Config) or an error with context.”
use anyhow::{Context, Result};
use serde::Deserialize;
#[derive(Deserialize)]
struct Config {
host: String,
port: u16,
}
fn load_config(path: &str) -> Result<Config> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("Failed to read config file: {}", path))?;
let config: Config = serde_json::from_str(&content)
.with_context(|| "Failed to parse JSON config")?;
Ok(config)
}
The anyhow crate is widely used in application code, while thiserror is preferred for libraries. Together they make error handling concise and informative.
4. Serialization with serde for WASM Targets
Task: Serialize a struct to JSON in a WebAssembly environment without std I/O.
Usage example: You are building a WASM module that receives a JSON string from JavaScript and returns processed data.
Prompt: “Define a Rust struct Point with fields x and y, derive Serialize and Deserialize, and write a WASM-compatible function serialize_point that takes a JSON string and returns a JSON string with the point’s data.”
use serde::{Serialize, Deserialize};
use wasm_bindgen::prelude::*;
#[derive(Serialize, Deserialize)]
struct Point {
x: f64,
y: f64,
}
#[wasm_bindgen]
pub fn serialize_point(json_input: &str) -> String {
let point: Point = serde_json::from_str(json_input).unwrap();
let output = format!("Point({}, {})", point.x, point.y);
serde_json::to_string(&output).unwrap()
}
This pattern is used in real WASM projects like wasm-bindgen examples and game engines compiling to WebAssembly.
5. Zero-Copy Parsing with nom
Task: Write a parser for a simple CSV line without allocating new strings.
Usage example: You need to parse a large log file line by line with minimal memory overhead.
Prompt: “Use the nom crate to parse a CSV line like "name,age,city" into a tuple (&str, &str, &str). The parser should handle quoted fields with commas inside them. Return a nom::IResult.”
use nom::{
bytes::complete::{tag, take_until},
character::complete::alphanumeric1,
sequence::delimited,
IResult,
};
fn parse_field(input: &str) -> IResult<&str, &str> {
if input.starts_with('"') {
delimited(tag("\""), take_until("\""), tag("\""))(input)
} else {
alphanumeric1(input)
}
}
fn parse_line(input: &str) -> IResult<&str, (&str, &str, &str)> {
let (input, field1) = parse_field(input)?;
let (input, _) = tag(",")(input)?;
let (input, field2) = parse_field(input)?;
let (input, _) = tag(",")(input)?;
let (input, field3) = parse_field(input)?;
Ok((input, (field1, field2, field3)))
}
fn main() {
let result = parse_line("\"Hello, world\",42,City");
println!("{:?}", result);
}
nom is used in production parsers like pest and tree-sitter for Rust, offering excellent performance.
6. Building a REST API Client with reqwest
Task: Fetch JSON data from an API and deserialize it with serde.
Usage example: You want to integrate an external weather API into your Rust CLI tool.
Prompt: “Write an async function get_weather using reqwest that sends a GET request to https://api.weather.com/v1/forecast?lat=...&lon=... and returns a Weather struct. Handle errors with anyhow.”
use anyhow::Result;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct Weather {
temperature: f64,
humidity: f64,
description: String,
}
async fn get_weather(lat: f64, lon: f64) -> Result<Weather> {
let url = format!("https://api.weather.com/v1/forecast?lat={}&lon={}", lat, lon);
let resp = reqwest::get(&url).await?;
let weather: Weather = resp.json().await?;
Ok(weather)
}
#[tokio::main]
async fn main() -> Result<()> {
let weather = get_weather(51.5, -0.13).await?;
println!("{:?}", weather);
Ok(())
}
reqwest is the de facto HTTP client for Rust, used by thousands of projects including cargo itself.
7. Unsafe Code for FFI with C Libraries
Task: Call a C function from Rust using extern and raw pointers.
Usage example: You need to interface with a legacy C library for hardware control.
Prompt: “Write a Rust function that calls a C function int add(int a, int b) defined in a static library. Use unsafe block and extern declaration. Include a test case.”
extern "C" {
fn add(a: i32, b: i32) -> i32;
}
fn safe_add(a: i32, b: i32) -> i32 {
unsafe { add(a, b) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(safe_add(2, 3), 5);
}
}
This is a simplified version of how Rust binds to C libraries like libcurl or OpenSSL.
8. Creating a Custom Iterator for Lazy Evaluation
Task: Implement an iterator that yields Fibonacci numbers indefinitely.
Usage example: You need to generate a sequence of numbers on the fly without storing them all in memory.
Prompt: “Define a struct Fibonacci that implements Iterator<Item = u128>. The iterator should start with 0, 1 and be infinite. Provide a method to reset it.”
struct Fibonacci {
a: u128,
b: u128,
}
impl Fibonacci {
fn new() -> Self {
Fibonacci { a: 0, b: 1 }
}
}
impl Iterator for Fibonacci {
type Item = u128;
fn next(&mut self) -> Option<Self::Item> {
let current = self.a;
self.a = self.b;
self.b = current + self.b;
Some(current)
}
}
fn main() {
let fib = Fibonacci::new();
for (i, val) in fib.take(10).enumerate() {
println!("Fib[{}] = {}", i, val);
}
}
Custom iterators are a cornerstone of Rust’s zero-cost abstractions and are used in data processing pipelines.
9. Concurrency with rayon for Parallel Data Processing
Task: Process a large vector of numbers in parallel using a thread pool.
Usage example: You are analyzing millions of sensor readings and need to compute statistics quickly.
Prompt: “Use the rayon crate to transform a Vec<u64> by squaring each element in parallel. Measure the time with std::time::Instant.”
use rayon::prelude::*;
use std::time::Instant;
fn main() {
let data: Vec<u64> = (0..1_000_000).collect();
let start = Instant::now();
let squares: Vec<u64> = data.par_iter().map(
|x| x * x).collect();
let elapsed = start.elapsed();
println!("Processed {} elements in {:?}", squares.len(), elapsed);
}
rayon is used in production by companies like Dropbox and Mozilla for data-intensive tasks.
10. WebAssembly: Passing Complex Types Between JS and Rust
Task: Send a JavaScript array to Rust, process it, and return a result.
Usage example: You are building a WASM image filter that takes pixel data from the browser.
Prompt: “Write a WASM function compute_average that receives a Vec<f64> from JavaScript, computes the average, and returns it as a f64. Use wasm_bindgen with appropriate type conversions.”
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn compute_average(data: Vec<f64>) -> f64 {
let sum: f64 = data.iter().sum();
sum / data.len() as f64
}
In JavaScript, you call wasm.compute_average(new Float64Array([1.0, 2.0, 3.0])).
11. Testing and Property-Based Testing with proptest
Task: Write a property-based test for a sorting function to ensure it always returns a sorted list of the same length.
Usage example: You need to verify that your custom sort algorithm doesn’t lose elements or produce invalid order.
Prompt: “Use the proptest crate to test a function sort_ascending that sorts a Vec<i32>. The property should check that the output length equals input length and that every consecutive pair is non-decreasing.”
use proptest::prelude::*;
fn sort_ascending(mut vec: Vec<i32>) -> Vec<i32> {
vec.sort();
vec
}
proptest! {
#[test]
fn test_sort_properties(mut vec in any::<Vec<i32>>()) {
let original_len = vec.len();
let sorted = sort_ascending(vec);
assert_eq!(sorted.len(), original_len);
for window in sorted.windows(2) {
assert!(window[0] <= window[1]);
}
}
}
Property-based testing is especially valuable for systems programming where edge cases can cause memory safety issues.
12. Memory Profiling with alloc and Custom Allocators
Task: Write a program that tracks the number of allocations made by a piece of code.
Usage example: You are optimizing a hot loop and want to see how many heap allocations happen.
Prompt: “Create a custom allocator wrapper that counts allocations and deallocations. Use std::alloc::GlobalAlloc and print counts at the end of main.”
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
struct CountingAllocator;
static ALLOC_COUNT: AtomicUsize = AtomicUsize::new(0);
static DEALLOC_COUNT: AtomicUsize = AtomicUsize::new(0);
unsafe impl GlobalAlloc for CountingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
ALLOC_COUNT.fetch_add(1, Ordering::SeqCst);
System.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
DEALLOC_COUNT.fetch_add(1, Ordering::SeqCst);
System.dealloc(ptr, layout)
}
}
#[global_allocator]
static A: CountingAllocator = CountingAllocator;
fn main() {
let v = vec![1, 2, 3]; // triggers allocations
drop(v);
println!("Allocations: {}, Deallocations: {}",
ALLOC_COUNT.load(Ordering::SeqCst),
DEALLOC_COUNT.load(Ordering::SeqCst));
}
This technique is used by production tools like jemalloc and mimalloc to debug memory usage.
Conclusion
These 12 prompts cover the most common scenarios that Rust developers face: safe memory management, CLI argument parsing, error handling, serialization for WASM, parsing, HTTP clients, unsafe FFI, iterators, parallel processing, WASM interop, property-based testing, and memory profiling. Each prompt is designed to be copy-paste ready and can be adapted to your specific project. The Rust ecosystem is vast—crates.io hosts over 150,000 crates as of July 2026—but mastering these core patterns will let you build anything from a simple CLI to a high-performance WASM module. Try one of these prompts in your next Rust project and see how much faster you can write safe, idiomatic code.
Comments