Introduction
Welcome to the final chapter! You've learned unsafe Rust, FFI, macros, compiler internals, embedded programming, OS development, memory allocators, SIMD, and WebAssembly. Now it's time to combine everything into three master projects that demonstrate production-ready Rust development.
- Production-quality code with proper error handling
- Comprehensive testing and benchmarking
- Clear documentation and examples
- Performance optimization where it matters
- Proper project structure and modularity
Project 1: KV Storage Engine
Overview
Build a high-performance key-value storage engine with ACID guarantees, similar to RocksDB or LevelDB. This project combines low-level I/O, memory management, and advanced data structures.
Core Components
// Core types
pub struct Storage {
memtable: MemTable,
sstables: Vec,
wal: WriteAheadLog,
compaction: CompactionManager,
}
pub struct MemTable {
data: SkipList, Vec>,
size: AtomicUsize,
}
pub struct SSTable {
path: PathBuf,
index: BTreeMap, u64>,
bloom_filter: BloomFilter,
}
impl Storage {
pub fn open(path: impl AsRef) -> Result {
let wal = WriteAheadLog::open(path.as_ref().join("wal"))?;
let memtable = MemTable::from_wal(&wal)?;
let sstables = SSTable::load_all(path.as_ref())?;
Ok(Storage {
memtable,
sstables,
wal,
compaction: CompactionManager::new(),
})
}
pub fn put(&mut self, key: Vec, value: Vec) -> Result<()> {
// Write to WAL first
self.wal.append(&key, &value)?;
// Update memtable
self.memtable.insert(key, value);
// Check if memtable is full
if self.memtable.size() > MEMTABLE_SIZE {
self.flush_memtable()?;
}
Ok(())
}
pub fn get(&self, key: &[u8]) -> Result
use std::ptr::NonNull;
use std::mem;
const MAX_LEVEL: usize = 16;
pub struct SkipList {
head: NonNull>,
level: usize,
len: usize,
}
struct Node {
key: Option,
value: Option,
forward: [Option>>; MAX_LEVEL],
}
impl SkipList {
pub fn new() -> Self {
let head = Box::new(Node {
key: None,
value: None,
forward: [None; MAX_LEVEL],
});
SkipList {
head: unsafe { NonNull::new_unchecked(Box::into_raw(head)) },
level: 0,
len: 0,
}
}
pub fn insert(&mut self, key: K, value: V) {
let mut update = [None; MAX_LEVEL];
let mut current = self.head;
// Find insertion point
for i in (0..=self.level).rev() {
unsafe {
while let Some(next) = current.as_ref().forward[i] {
if next.as_ref().key.as_ref().unwrap() < &key {
current = next;
} else {
break;
}
}
update[i] = Some(current);
}
}
let level = self.random_level();
if level > self.level {
for i in (self.level + 1)..=level {
update[i] = Some(self.head);
}
self.level = level;
}
let new_node = Box::new(Node {
key: Some(key),
value: Some(value),
forward: [None; MAX_LEVEL],
});
let new_node_ptr = unsafe { NonNull::new_unchecked(Box::into_raw(new_node)) };
for i in 0..=level {
unsafe {
if let Some(update_node) = update[i] {
new_node_ptr.as_mut().forward[i] = update_node.as_ref().forward[i];
update_node.as_mut().forward[i] = Some(new_node_ptr);
}
}
}
self.len += 1;
}
pub fn get(&self, key: &K) -> Option<&V> {
let mut current = self.head;
for i in (0..=self.level).rev() {
unsafe {
while let Some(next) = current.as_ref().forward[i] {
match next.as_ref().key.as_ref() {
Some(k) if k < key => current = next,
Some(k) if k == key => return next.as_ref().value.as_ref(),
_ => break,
}
}
}
}
None
}
fn random_level(&self) -> usize {
let mut level = 0;
while level < MAX_LEVEL - 1 && rand::random::() < 0.5 {
level += 1;
}
level
}
}
Key Features
- Write-Ahead Logging (WAL) for durability
- LSM-tree structure with compaction
- Bloom filters for fast negative lookups
- Skip list for in-memory indexing
- Concurrent access with proper locking
Project 2: Programming Language Compiler
Overview
Design and implement a complete compiler for a small programming language. This project showcases parsing, type checking, optimization, and code generation.
pub struct Compiler {
source: String,
tokens: Vec,
ast: Option,
typed_ast: Option,
ir: Option,
}
impl Compiler {
pub fn new(source: String) -> Self {
Compiler {
source,
tokens: Vec::new(),
ast: None,
typed_ast: None,
ir: None,
}
}
pub fn compile(&mut self) -> Result {
// 1. Lexical Analysis
self.tokens = Lexer::new(&self.source).tokenize()?;
// 2. Syntax Analysis
self.ast = Some(Parser::new(&self.tokens).parse()?);
// 3. Semantic Analysis
let type_checker = TypeChecker::new();
self.typed_ast = Some(type_checker.check(self.ast.as_ref().unwrap())?);
// 4. IR Generation
let ir_gen = IRGenerator::new();
self.ir = Some(ir_gen.generate(self.typed_ast.as_ref().unwrap())?);
// 5. Optimization
let optimizer = Optimizer::new();
self.ir = Some(optimizer.optimize(self.ir.take().unwrap())?);
// 6. Code Generation
let codegen = CodeGenerator::new();
let assembly = codegen.generate(self.ir.as_ref().unwrap())?;
Ok(assembly)
}
}
// AST Definition
#[derive(Debug, Clone)]
pub enum Expr {
Number(i64),
String(String),
Variable(String),
Binary {
op: BinaryOp,
left: Box,
right: Box,
},
Call {
func: String,
args: Vec,
},
If {
condition: Box,
then_branch: Box,
else_branch: Option>,
},
}
#[derive(Debug, Clone)]
pub enum Stmt {
Let {
name: String,
value: Expr,
},
Function {
name: String,
params: Vec<(String, Type)>,
return_type: Type,
body: Vec,
},
Return(Expr),
Expr(Expr),
}
// Type System
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
Int,
String,
Bool,
Function {
params: Vec,
return_type: Box,
},
Unknown,
}
pub struct TypeChecker {
env: HashMap,
}
impl TypeChecker {
pub fn check_expr(&mut self, expr: &Expr) -> Result {
match expr {
Expr::Number(_) => Ok(Type::Int),
Expr::String(_) => Ok(Type::String),
Expr::Variable(name) => {
self.env.get(name)
.cloned()
.ok_or_else(|| format!("Undefined variable: {}", name).into())
}
Expr::Binary { op, left, right } => {
let left_type = self.check_expr(left)?;
let right_type = self.check_expr(right)?;
if left_type != right_type {
return Err(format!(
"Type mismatch: {:?} vs {:?}",
left_type, right_type
).into());
}
Ok(left_type)
}
Expr::Call { func, args } => {
let func_type = self.env.get(func)
.ok_or_else(|| format!("Undefined function: {}", func))?;
if let Type::Function { params, return_type } = func_type {
if args.len() != params.len() {
return Err("Argument count mismatch".into());
}
for (arg, param_type) in args.iter().zip(params.iter()) {
let arg_type = self.check_expr(arg)?;
if &arg_type != param_type {
return Err(format!(
"Argument type mismatch: expected {:?}, got {:?}",
param_type, arg_type
).into());
}
}
Ok((**return_type).clone())
} else {
Err("Not a function".into())
}
}
_ => Ok(Type::Unknown),
}
}
}
use inkwell::context::Context;
use inkwell::builder::Builder;
use inkwell::module::Module;
use inkwell::values::FunctionValue;
pub struct LLVMCodegen<'ctx> {
context: &'ctx Context,
module: Module<'ctx>,
builder: Builder<'ctx>,
}
impl<'ctx> LLVMCodegen<'ctx> {
pub fn new(context: &'ctx Context) -> Self {
let module = context.create_module("main");
let builder = context.create_builder();
LLVMCodegen {
context,
module,
builder,
}
}
pub fn compile_function(&self, func: &Function) -> FunctionValue<'ctx> {
let i64_type = self.context.i64_type();
let fn_type = i64_type.fn_type(&[], false);
let function = self.module.add_function(&func.name, fn_type, None);
let basic_block = self.context.append_basic_block(function, "entry");
self.builder.position_at_end(basic_block);
// Compile function body
let return_value = self.compile_expr(&func.body);
self.builder.build_return(Some(&return_value));
function
}
fn compile_expr(&self, expr: &Expr) -> IntValue<'ctx> {
match expr {
Expr::Number(n) => {
self.context.i64_type().const_int(*n as u64, false)
}
Expr::Binary { op, left, right } => {
let left_val = self.compile_expr(left);
let right_val = self.compile_expr(right);
match op {
BinaryOp::Add => self.builder.build_int_add(left_val, right_val, "add"),
BinaryOp::Sub => self.builder.build_int_sub(left_val, right_val, "sub"),
BinaryOp::Mul => self.builder.build_int_mul(left_val, right_val, "mul"),
BinaryOp::Div => self.builder.build_int_signed_div(left_val, right_val, "div"),
}
}
_ => panic!("Unsupported expression"),
}
}
pub fn print_ir(&self) {
self.module.print_to_stderr();
}
pub fn jit_compile_and_run(&self, func_name: &str) -> i64 {
let ee = self.module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
let func = unsafe { ee.get_function:: i64>(func_name).unwrap() };
unsafe { func.call() }
}
}
Key Features
- Complete lexer, parser, and type checker
- Multiple optimization passes
- LLVM backend for code generation
- JIT compilation support
- Error reporting with source locations
Project 3: Microkernel Operating System
Overview
Build a minimal microkernel-based operating system with process management, memory management, and IPC (Inter-Process Communication).
#![no_std]
#![no_main]
mod process;
mod memory;
mod ipc;
mod drivers;
mod syscall;
use process::ProcessManager;
use memory::MemoryManager;
use ipc::MessageQueue;
pub struct Kernel {
process_manager: ProcessManager,
memory_manager: MemoryManager,
message_queue: MessageQueue,
}
impl Kernel {
pub fn new() -> Self {
Kernel {
process_manager: ProcessManager::new(),
memory_manager: MemoryManager::new(),
message_queue: MessageQueue::new(),
}
}
pub fn boot(&mut self) {
println!("Booting microkernel...");
// Initialize memory management
self.memory_manager.init();
// Start init process
let init_pid = self.process_manager.create_process(
init_process,
ProcessPriority::High,
);
// Enter scheduler
self.run_scheduler();
}
fn run_scheduler(&mut self) -> ! {
loop {
if let Some(process) = self.process_manager.next_ready() {
// Switch to process
self.switch_to_process(process);
} else {
// Idle
x86_64::instructions::hlt();
}
}
}
fn switch_to_process(&mut self, process: &mut Process) {
// Save current context
// Load process context
// Jump to process
}
}
// System call interface
#[no_mangle]
pub extern "C" fn syscall_handler(
syscall_num: usize,
arg1: usize,
arg2: usize,
arg3: usize,
) -> isize {
match syscall_num {
0 => sys_exit(arg1),
1 => sys_write(arg1, arg2, arg3),
2 => sys_read(arg1, arg2, arg3),
3 => sys_open(arg1, arg2),
4 => sys_close(arg1),
5 => sys_fork(),
6 => sys_exec(arg1, arg2),
7 => sys_wait(arg1),
8 => sys_send_message(arg1, arg2, arg3),
9 => sys_recv_message(arg1, arg2, arg3),
_ => -1,
}
}
// IPC implementation
pub struct Message {
sender: ProcessId,
data: [u8; 256],
len: usize,
}
pub struct MessageQueue {
queues: HashMap>,
}
impl MessageQueue {
pub fn send(&mut self, to: ProcessId, msg: Message) -> Result<()> {
let queue = self.queues.entry(to).or_insert_with(VecDeque::new);
if queue.len() >= MAX_MESSAGES {
return Err(Error::QueueFull);
}
queue.push_back(msg);
Ok(())
}
pub fn receive(&mut self, from: ProcessId) -> Option {
self.queues.get_mut(&from)?.pop_front()
}
}
Key Features
- Microkernel architecture with minimal kernel
- Process scheduling and context switching
- Virtual memory management
- Message-based IPC
- System call interface
- Basic device drivers
Best Practices for Production Code
🔑 Production-Ready Guidelines
- Error Handling: Use Result types, never panic in library code
- Testing: Unit tests, integration tests, property-based tests
- Documentation: Rustdoc comments on all public APIs
- Performance: Profile before optimizing, benchmark critical paths
- Safety: Minimize unsafe code, document invariants
- API Design: Follow Rust conventions, make invalid states unrepresentable
- Versioning: Semantic versioning, changelog
- CI/CD: Automated testing, linting, formatting
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_operations() {
let mut db = Storage::open("test.db").unwrap();
db.put(b"key1".to_vec(), b"value1".to_vec()).unwrap();
assert_eq!(db.get(b"key1").unwrap(), Some(b"value1".to_vec()));
}
#[test]
fn test_concurrent_access() {
use std::sync::Arc;
use std::thread;
let db = Arc::new(Storage::open("concurrent.db").unwrap());
let mut handles = vec![];
for i in 0..10 {
let db = Arc::clone(&db);
let handle = thread::spawn(move || {
for j in 0..100 {
let key = format!("key-{}-{}", i, j);
let value = format!("value-{}-{}", i, j);
db.put(key.into_bytes(), value.into_bytes()).unwrap();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
#[bench]
fn bench_put(b: &mut Bencher) {
let mut db = Storage::open("bench.db").unwrap();
b.iter(|| {
db.put(b"key".to_vec(), b"value".to_vec()).unwrap();
});
}
}
// Property-based testing
use proptest::prelude::*;
proptest! {
#[test]
fn prop_get_after_put(key in any::>(), value in any::>()) {
let mut db = Storage::open("prop.db").unwrap();
db.put(key.clone(), value.clone()).unwrap();
assert_eq!(db.get(&key).unwrap(), Some(value));
}
}
🎉 Congratulations! 🎉
You've completed the WIA-RUST-ADVANCED course!
You've mastered unsafe Rust, FFI, macros, compiler internals, embedded programming, OS development, memory allocators, SIMD, WebAssembly, and built production-ready systems. You're now equipped to tackle the most challenging Rust projects and contribute to cutting-edge systems programming.
弘益人間 (홍익인간) · Benefit All Humanity
Next Steps
✅ Continue Your Journey:
- Contribute to Open Source: Join Rust projects on GitHub
- Build Your Own Projects: Apply what you've learned
- Stay Updated: Follow Rust RFCs and language evolution
- Teach Others: Share your knowledge with the community
- Explore Specializations: Async, networking, graphics, etc.
- Read the Source: Study standard library and compiler code
- The Rustonomicon - Advanced unsafe Rust
- Async Book - Asynchronous programming
- Writing an OS in Rust - OS development blog
- Rustc Dev Guide - Compiler internals
- Rust and WebAssembly Book - WASM programming
Final Words
Rust is more than a programming language - it's a paradigm shift in how we think about systems programming. The skills you've gained here will serve you well not just in Rust, but in any language or domain you choose to explore.
Remember: the journey of mastery never ends. Keep learning, keep building, and keep pushing the boundaries of what's possible. The Rust community is here to support you every step of the way.
Happy coding, and may your programs be forever memory-safe! 🦀