Overview of Type-Driven Development, Error-handling, and Testing
masteractix-web, and following testing best practices.repository·master·Indexed 20 days ago
https://github.com/rust-lang-ua/rustcampA structured certification program for developers to become proficient Rust programmers. The curriculum includes foundational vocabulary on memory models and type systems, hands-on tasks covering traits (Default, Clone, Copy), smart pointers (Box, Rc, Arc), pinning (Pin, Unpin), and interior mutability (Cell, RefCell, Mutex, RwLock).
actix-web, and following testing best practices.This chapter covers essential patterns for managing database schema evolution and handling external dependencies in a Rust application. Specifically, it addresses:
sqlx to manage and execute SQL migrations.The Rustcamp curriculum is organized into several progressive tasks covering core concepts, idioms, the ecosystem, backend development, and a capstone project.
Curriculum Structure:
This section covers the fundamental security requirements for building web applications, specifically focusing on:
actix-web routes to protect specific endpoints.This task covers the fundamental concepts of asynchronous programming in Rust. To master this section, you should be able to explain and understand the following core topics:
Future Trait: Its purpose, how it works in Rust, its zero-cost semantics, and how it differs from futures in other languages.async/.await Syntax: How these keywords desugar into Futures and why they are necessary for ergonomics.Future.Waker: Its role, how it works, and why it is required for the async lifecycle.Futures (cooperative multitasking) and its trade-offs.When implementing these concepts, you will likely interact with these libraries:
tokio, async-std, actix-rt, glommio.futures, futures-lite, async-trait.actix, riker, quickwit-actors, bastion.A sealed trait is a publicly accessible trait that cannot be implemented outside its definition place (the specific module or crate).
Sealing allows library authors to evolve their API without breaking downstream code. Because you control all possible implementations, you can safely:
#[doc(hidden)]).Sealing relies on tricking Rust's visibility rules. By making the trait require a supertrait that is not publicly exported, you ensure that no code outside your crate can satisfy the requirement to implement the main trait. It does not change the type system's semantics; it is a visibility-based restriction.
Box<T> is a smart pointer that owns heap-allocated data. It is used to:
&T or &mut T) which require managing lifetimes, Box provides ownership of heap data.Box<str> or Box<[T]> can be used when an owned slice is needed but the size is not intended to be resized (unlike String or Vec<T>).// Example of using Box for heap allocation
let x = Box::new(5); // 5 is now on the heap
let s: Box<str> = "hello".into(); // Fixed-size heap stringThread synchronization in Rust is achieved through three primary patterns:
std::sync::atomic module (or the atomic crate).std::sync module (e.g., Mutexes).std::sync::mpsc module.For more optimized or feature-rich synchronization, the crossbeam crate (specifically crossbeam-channel) is a highly recommended enhancement over the standard library's MPSC implementation.
Both sets of traits have similar signatures, but they serve different semantic purposes:
AsRef / AsMut: Used when a type can be represented as a reference to another type (e.g., one type contains another). It is more flexible and can be implemented even if the types are not semantically identical.Borrow / BorrowMut: Used when the implementor type is semantically equivalent to the implemented type, differing only in storage. Crucially, Borrow requires that Hash, Eq, and Ord implementations for the borrowed value are identical to those of the owned value.When to use which:
Borrow<T> when generic code relies on identical behavior (like Eq or Hash) between owned and borrowed versions.AsRef<T> when you simply need to work with any type that can provide a reference to a related type.To ensure your code breaks at compile-time whenever a new enum variant is added, avoid using the wildcard pattern _ or match-anything bindings in match expressions. By explicitly listing every variant, the compiler will signal an error if a new variant is introduced but not handled, preventing logic bugs (like incorrect permission assignments).
// BAD: Using wildcard `_` prevents compile-time errors when new roles are added
fn grant_permissions(role: &Role) -> Permissions {
match role {
Role::Reporter => Permissions::Read,
Role::Developer => Permissions::Read & Permissions::Edit,
_ => Permissions::All,
}
}
// GOOD: Explicitly matching all variants ensures compile-time safety
fn grant_permissions(role: &Role) -> Permissions {
match role {
Role::Reporter => Permissions::Read,
Role::Developer => Permissions::Read & Permissions::Edit,
Role::Admin => Permissions::All,
}
}The config crate allows you to create hierarchical, typed configuration structures following 12-factor app principles. It enables merging configuration from multiple sources in a specific order.
Supported sources include:
Config instancesFormat trait.set methodKey features include live watching/re-reading of files, deep access via path syntax, and serde deserialization.