AI Instructor Live Labs Included

Advanced Rust — Unsafe, FFI, and Macros

Below the safe-Rust abstraction — unsafe, raw pointers, C FFI in both directions, declarative macros, and procedural macros.

Advanced
23h 50m
15 Lessons
SMU-RUST-700

About This Course

The final course of the foundational Rust track. You go below the safe-Rust abstraction to learn exactly what unsafe unlocks and what it does not, how to interoperate with C libraries in both directions, and how to write both declarative and procedural macros to generate Rust code at compile time. You will learn when unsafe is the right tool, how to build a safe wrapper around an unsafe primitive, when FFI is the right boundary, and how real crates in the Rust ecosystem use macros to shrink repetitive code. By the end of this course you will be able to write a correct unsafe block and defend its invariants, implement Send and Sync by hand with the right reasoning, call a C library from Rust and expose a Rust library to C, write a non-trivial macro_rules declarative macro, and build a simple #[derive(...)] procedural macro. Prerequisites: Courses 1-6 of the Programming with Rust skill path. Follows the Rust 2024 edition on stable Rust 1.99.

Course Curriculum

15 Lessons
01
AI Lesson
AI Lesson

What unsafe actually unlocks

1h 0m

Rust's unsafe keyword is the compiler's trust-me switch, not an escape hatch from the ownership rules. This lesson teaches exactly which five powers unsafe unlocks (and the ones it does not), what undefined behavior means in a Rust program, and the discipline for wrapping an unsafe primitive in a safe public API. By the end of this lesson you will be able to list the five operations that require unsafe, explain why unsafe is a tool for reasoning rather than a license to ignore the compiler, and recognize a safe-wrapper pattern when you read it in an ecosystem crate.

02
Lab Exercise
Lab Exercise

Writing your first safe wrapper over unsafe code - Lab Exercises

1h 40m 3 Exercises

Build a safe public API around a raw-pointer primitive. You will wrap a raw-pointer-returning function in a safe interface that defends every invariant the primitive requires: non-null pointer, correct alignment, lifetime bound to a borrow, and no concurrent mutation. You will also study a looks-safe wrapper that is actually unsound and learn to spot the aliasing bug. By the end of this lab you will be able to write a safe wrapper around a raw-pointer-returning function, enumerate its invariants in a doc comment, and justify each unsafe block in a sentence.

03
AI Lesson
AI Lesson

Raw pointers, provenance, and NonNull

1h 15m

Raw pointers in Rust are the primitive beneath references, and they obey different aliasing rules. This lesson covers how raw pointers differ from references, when NonNull is the right pointer type, how addr_of! and addr_of_mut! compute a pointer without materializing a reference first, and the Rust 2024 provenance model at a high level. By the end of this lesson you will be able to pick the right pointer type for a situation, use addr_of! where references would be unsound, and read a crate that uses raw pointers without panicking.

04
Lab Exercise
Lab Exercise

Build a safe linked list with raw pointers - Lab Exercises

1h 55m 4 Exercises

Build a singly-linked list from scratch using raw pointers. You will implement push, pop, iteration, and the Drop impl that releases every node without leaking; you will then decide and justify whether to add unsafe impl Send and unsafe impl Sync for your list. By the end of this lab you will be able to build a correct linked data structure with raw pointers, write a Drop impl that handles every ownership case, and tell when unsafe impl Send + Sync is correct for a type that uses interior raw pointers.

05
AI Lesson
AI Lesson

Unsafe trait implementations — Send and Sync by hand

1h 0m

Send and Sync are not just compiler hints — they are safety contracts you can implement for your own types. This lesson covers when a manual Send or Sync implementation is correct, the aliasing contract of raw-pointer-backed types, what GlobalAlloc requires, and how marker-trait inheritance decides whether your type auto-derives. By the end of this lesson you will be able to decide when a type needs a manual Send and Sync, write a doc comment that justifies the implementation, and recognize when the compiler is right or wrong to deny the automatic implementation.

06
Lab Exercise
Lab Exercise

Implement Send and Sync for a lock-free counter - Lab Exercises

1h 35m 3 Exercises

Implement a lock-free counter from atomic primitives and justify its Send + Sync safety in a doc comment. You will measure the counter under concurrent load, write a SAFETY comment for each unsafe implementation, and compare the atomic approach to a mutex-protected baseline. By the end of this lab you will be able to build a thread-safe counter without locks, write defensible unsafe Send and Sync blocks, and reason about which concurrency primitive wins for different access patterns.

07
AI Lesson
AI Lesson

FFI with C — extern C, repr(C), bindgen preview

1h 15m

Rust interoperates with C through the extern C block, repr(C) layout, and FFI-safe primitive types. This lesson covers which types pass cleanly across the ABI boundary, how bindgen generates Rust bindings from a C header, how to pass nul-terminated strings between the two languages correctly, and how raw function pointers model C callbacks. By the end of this lesson you will be able to read an extern C block, choose FFI-safe types for a Rust and C boundary, convert between Rust strings and C strings correctly, and describe what bindgen does and when you would reach for it.

08
Lab Exercise
Lab Exercise

Call a C library from Rust - Lab Exercises

1h 55m 4 Exercises

Build a Rust crate that links to a small C library and exposes its functions through a safe wrapper. You will use the cc crate from a build.rs to compile the C code, call the C functions from Rust across an extern C boundary, convert between Rust and C strings, and write a safe Rust API over the C surface. By the end of this lab you will be able to configure a build.rs to compile a C dependency, declare its API in a Rust extern C block, and wrap it in a safe Rust interface with correct string conversion.

09
AI Lesson
AI Lesson

Exposing Rust to C — cdylib, cbindgen, panic boundaries

1h 0m

The other direction of FFI — making Rust callable from C — comes with its own discipline. This lesson covers how a no-mangle extern C function publishes a Rust function to C, how cbindgen generates the corresponding C header, which Rust return types are FFI-safe, and why every public FFI function must install a panic boundary. By the end of this lesson you will be able to expose a Rust function to C, choose between cdylib and staticlib crate types, generate a C header automatically, and defend the panic boundary that every FFI function needs.

10
Lab Exercise
Lab Exercise

Build a cdylib and call it from C - Lab Exercises

2h 0m 4 Exercises

Build a cdylib crate that exposes a public Rust API to C, generate the C header with cbindgen, and write a tiny C driver that links against the dynamic library and calls the Rust function. You will install a panic boundary at every public FFI entry point and verify end-to-end that a C program can load and call your Rust code. By the end of this lab you will be able to configure a cdylib project end to end, generate matching C headers, write a C driver that links against the Rust library, and reason about panic safety on the FFI boundary.

11
AI Lesson
AI Lesson

macro_rules! — matchers, repetition, hygiene

1h 15m

macro_rules! is Rust's declarative macro system — pattern-matching on syntactic fragments, producing new code at parse time. This lesson covers the full matcher syntax, the repetition operators, macro hygiene, and the cargo expand workflow for debugging what your macro actually generated. By the end of this lesson you will be able to write a macro_rules! macro that destructures and repeats, use the correct fragment specifier for a given input shape, and expand your macro to see the generated code.

12
Lab Exercise
Lab Exercise

Write a vec!-like macro and a small DSL - Lab Exercises

2h 0m 4 Exercises

Write a vec!-style declarative macro from scratch, supporting both bracket-list and value-count forms. Then build a tiny HTML-like DSL macro that nests tags syntactically. You will debug both macros with cargo expand and write tests that exercise every pattern. By the end of this lab you will be able to write a non-trivial macro_rules! macro, choose the right fragment specifier for each matcher position, and use cargo expand to debug macro output.

13
AI Lesson
AI Lesson

Procedural macros — function-like, derive, attribute

1h 15m

Procedural macros are Rust programs that run at compile time and transform a token stream into another token stream. This lesson covers the three proc-macro flavors, the standard crates in the proc-macro stack, the Cargo.toml declaration, and the mental model of parsing input tokens, inspecting them, and emitting output. By the end of this lesson you will be able to recognize each proc-macro flavor on sight, read a proc-macro crate, and describe the role of each tool in the standard stack.

14
Lab Exercise
Lab Exercise

Write a simple derive(Builder) procedural macro - Lab Exercises

2h 0m 4 Exercises

Write a derive(Builder) procedural macro that generates a type-safe builder for any struct it is applied to. You will parse the struct definition with the syn crate, emit the builder type and setter methods with the quote crate, and verify your derive macro produces compilable code against a consumer crate. By the end of this lab you will be able to write a working derive macro, use syn to parse Rust syntax, use quote to emit Rust code, and verify your output with a consumer test.

15
Lab Exercise
Lab Exercise

Capstone — FFI-safe plugin system - Lab Exercises

2h 45m 5 Exercises

The final capstone of the foundational Rust track ties unsafe, FFI, and macros into one shippable artifact — a plugin system. A host crate loads cdylib plugins at runtime, each plugin implements an FFI-safe interface across the dynamic-library boundary, a declarative macro collapses plugin boilerplate, and a derive macro generates plugin registration metadata. By the end of this lab you will have shipped a working plugin host that dynamically loads a plugin binary and calls into it across a stable FFI boundary — the closest in-course approximation to the shape of a real-world Rust system.

This course includes:

  • 24/7 AI Instructor Support
  • Live Lab Environments
  • 8 Hands-on Lessons
Skill Level Advanced
Total Duration 23h 50m