It's time to apply everything you've learned! This final chapter walks through building real-world projects: a CLI tool for command-line interfaces, a web service with async HTTP, and examples of how Rust integrates with the WIA ecosystem. You'll also learn testing strategies and discover resources for continuing your Rust journey.
The best way to solidify your Rust knowledge is to build real projects. The patterns you've learned - ownership, borrowing, error handling, traits, and concurrency - come together in practical applications. Each project demonstrates how these concepts work in production code.
Build a command-line tool to validate files. This demonstrates argument parsing, file I/O, and error handling patterns common in CLI applications.
// Cargo.toml
[package]
name = "wia-validate"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
// src/main.rs
use clap::Parser;
use std::fs;
use std::path::PathBuf;
use anyhow::{Context, Result};
/// A CLI tool to validate files against standards
#[derive(Parser)]
#[command(name = "wia-validate")]
#[command(about = "Validate files against WIA standards")]
#[command(version = "1.0")]
struct Cli {
/// The standard to validate against
#[arg(short, long)]
standard: String,
/// Path to the file to validate
#[arg(short, long)]
file: PathBuf,
/// Enable verbose output
#[arg(short, long, default_value_t = false)]
verbose: bool,
/// Output format (text, json)
#[arg(short, long, default_value = "text")]
output: String,
}
fn main() -> Result<()> {
let cli = Cli::parse();
if cli.verbose {
println!("Validating {} against WIA-{}",
cli.file.display(), cli.standard);
}
let content = fs::read_to_string(&cli.file)
.with_context(|| format!("Failed to read file: {}", cli.file.display()))?;
let result = validate(&content, &cli.standard);
match cli.output.as_str() {
"json" => print_json_result(&result),
_ => print_text_result(&result),
}
if result.is_valid {
Ok(())
} else {
std::process::exit(1);
}
}
struct ValidationResult {
is_valid: bool,
errors: Vec<String>,
warnings: Vec<String>,
}
fn validate(content: &str, standard: &str) -> ValidationResult {
let mut errors = Vec::new();
let mut warnings = Vec::new();
// Example validation rules
if content.is_empty() {
errors.push("File is empty".to_string());
}
if content.len() > 1_000_000 {
warnings.push("File is very large".to_string());
}
ValidationResult {
is_valid: errors.is_empty(),
errors,
warnings,
}
}
fn print_text_result(result: &ValidationResult) {
if result.is_valid {
println!("Valid!");
} else {
println!("Invalid:");
for err in &result.errors {
println!(" - {}", err);
}
}
for warn in &result.warnings {
println!("Warning: {}", warn);
}
}
fn print_json_result(result: &ValidationResult) {
println!("{{\"valid\":{},\"errors\":{:?},\"warnings\":{:?}}}",
result.is_valid, result.errors, result.warnings);
}
# Usage examples cargo run -- --standard AI-CITY --file config.json --verbose cargo run -- -s HOME -f device.yaml -o json
Build an async HTTP API using Axum. This demonstrates async/await, JSON handling, and web service patterns.
// Cargo.toml
[package]
name = "wia-api"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tower-http = { version = "0.5", features = ["cors", "trace"] }
tracing = "0.1"
tracing-subscriber = "0.3"
// src/main.rs
use axum::{
routing::{get, post},
Router, Json,
http::StatusCode,
extract::State,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
// Shared application state
struct AppState {
validations: Mutex<HashMap<String, ValidationRecord>>,
}
#[derive(Clone, Serialize)]
struct ValidationRecord {
id: String,
standard: String,
valid: bool,
timestamp: String,
}
#[derive(Serialize)]
struct HealthResponse {
status: String,
version: String,
}
#[derive(Deserialize)]
struct ValidateRequest {
standard: String,
content: String,
}
#[derive(Serialize)]
struct ValidateResponse {
id: String,
valid: bool,
errors: Vec<String>,
}
async fn health() -> Json<HealthResponse> {
Json(HealthResponse {
status: "healthy".to_string(),
version: "1.0.0".to_string(),
})
}
async fn validate(
State(state): State<Arc<AppState>>,
Json(payload): Json<ValidateRequest>,
) -> (StatusCode, Json<ValidateResponse>) {
let valid = !payload.content.is_empty();
let id = uuid::Uuid::new_v4().to_string();
// Store validation record
let record = ValidationRecord {
id: id.clone(),
standard: payload.standard,
valid,
timestamp: chrono::Utc::now().to_rfc3339(),
};
state.validations.lock().unwrap().insert(id.clone(), record);
let response = ValidateResponse {
id,
valid,
errors: if valid { vec![] } else { vec!["Content is empty".to_string()] },
};
let status = if valid { StatusCode::OK } else { StatusCode::BAD_REQUEST };
(status, Json(response))
}
async fn list_validations(
State(state): State<Arc<AppState>>,
) -> Json<Vec<ValidationRecord>> {
let validations = state.validations.lock().unwrap();
Json(validations.values().cloned().collect())
}
#[tokio::main]
async fn main() {
// Initialize tracing
tracing_subscriber::init();
// Create shared state
let state = Arc::new(AppState {
validations: Mutex::new(HashMap::new()),
});
// Build router
let app = Router::new()
.route("/health", get(health))
.route("/validate", post(validate))
.route("/validations", get(list_validations))
.with_state(state);
// Start server
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();
println!("Server running on http://localhost:3000");
axum::serve(listener, app).await.unwrap();
}
A simplified concurrent control system demonstrating Arc, Mutex, and channels.
use std::sync::{Arc, Mutex, mpsc};
use std::thread;
use std::time::Duration;
pub struct RustCore {
hbm_usage: Arc<Mutex<f64>>,
power_distribution: Arc<PowerDistribution>,
command_tx: mpsc::Sender<Command>,
}
struct PowerDistribution {
ai_compute: Mutex<f64>,
infrastructure: Mutex<f64>,
reserve: Mutex<f64>,
}
enum Command {
AllocateHBM(f64),
SetPower { category: String, value: f64 },
GetStatus,
Shutdown,
}
#[derive(Debug, Clone)]
pub struct CoreStatus {
pub hbm_usage: f64,
pub power_ai: f64,
pub power_infra: f64,
pub power_reserve: f64,
}
impl RustCore {
pub fn new() -> Self {
let (tx, rx) = mpsc::channel();
let core = RustCore {
hbm_usage: Arc::new(Mutex::new(0.0)),
power_distribution: Arc::new(PowerDistribution {
ai_compute: Mutex::new(70.0),
infrastructure: Mutex::new(20.0),
reserve: Mutex::new(10.0),
}),
command_tx: tx,
};
// Spawn background command processor
let hbm = Arc::clone(&core.hbm_usage);
let power = Arc::clone(&core.power_distribution);
thread::spawn(move || {
for cmd in rx {
match cmd {
Command::AllocateHBM(amount) => {
let mut usage = hbm.lock().unwrap();
if *usage + amount <= 100.0 {
*usage += amount;
println!("HBM allocated: {:.1}%", amount);
}
}
Command::SetPower { category, value } => {
match category.as_str() {
"ai" => *power.ai_compute.lock().unwrap() = value,
"infra" => *power.infrastructure.lock().unwrap() = value,
"reserve" => *power.reserve.lock().unwrap() = value,
_ => {}
}
}
Command::Shutdown => break,
_ => {}
}
}
});
core
}
pub fn allocate_hbm(&self, amount: f64) -> Result<(), String> {
let usage = *self.hbm_usage.lock().unwrap();
if usage + amount > 100.0 {
return Err("HBM capacity exceeded".to_string());
}
self.command_tx.send(Command::AllocateHBM(amount)).unwrap();
Ok(())
}
pub fn get_status(&self) -> CoreStatus {
CoreStatus {
hbm_usage: *self.hbm_usage.lock().unwrap(),
power_ai: *self.power_distribution.ai_compute.lock().unwrap(),
power_infra: *self.power_distribution.infrastructure.lock().unwrap(),
power_reserve: *self.power_distribution.reserve.lock().unwrap(),
}
}
}
Rust has excellent built-in testing support. Tests live alongside your code and run with cargo test:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hbm_allocation() {
let core = RustCore::new();
assert!(core.allocate_hbm(50.0).is_ok());
assert!(core.allocate_hbm(40.0).is_ok());
assert!(core.allocate_hbm(20.0).is_err()); // Would exceed 100%
}
#[test]
fn test_status_initial() {
let core = RustCore::new();
let status = core.get_status();
assert_eq!(status.hbm_usage, 0.0);
assert_eq!(status.power_ai, 70.0);
}
#[test]
fn test_validation_empty_content() {
let result = validate("", "AI-CITY");
assert!(!result.is_valid);
assert!(!result.errors.is_empty());
}
#[test]
fn test_validation_valid_content() {
let result = validate("Some content", "AI-CITY");
assert!(result.is_valid);
assert!(result.errors.is_empty());
}
}
// Integration tests go in tests/ directory
// tests/integration_test.rs
#[test]
fn test_full_workflow() {
// Test complete user workflow
}
# Run all tests cargo test # Run with output visible cargo test -- --nocapture # Run specific test cargo test test_hbm_allocation # Run tests matching pattern cargo test allocation
Rust's type system catches many bugs at compile time, but tests are still essential for logic errors and integration testing. Write tests first to clarify requirements, then implement the code to make them pass.
| Resource | Description |
|---|---|
| The Rust Book | doc.rust-lang.org/book - Complete official guide, free online |
| Rustlings | github.com/rust-lang/rustlings - Small exercises to practice concepts |
| Exercism | exercism.org/tracks/rust - Practice problems with mentorship |
| Crates.io | crates.io - Explore the package ecosystem (200k+ crates) |
| This Week in Rust | this-week-in-rust.org - Weekly newsletter of Rust news |
| Rust by Example | doc.rust-lang.org/rust-by-example - Learn by working examples |
| The Rustonomicon | doc.rust-lang.org/nomicon - Advanced/unsafe Rust guide |
Your Rust skills connect to the entire WIA ecosystem. Rust's performance and safety make it ideal for infrastructure components:
#[test]; run with cargo test#[tokio::main]? Why is it needed for async main functions?You've completed Zero-to-Rust! You now understand ownership, borrowing, lifetimes, structs, enums, traits, generics, closures, iterators, and concurrency. More importantly, you understand why Rust makes the design choices it does.
Rust's learning curve is real, but you've climbed it. The concepts that felt strange at first - ownership, the borrow checker, lifetimes - are now your tools for writing safe, fast code.
The Rust community is welcoming and helpful. Don't hesitate to ask questions on forums, Discord, or Stack Overflow. Everyone was a beginner once.
Welcome to the Rust community. Happy coding!
ๅผ็ไบบ้ - Benefit All Humanity