1.2 Advocating for Rust at work
Cheating your way to “Hello, world!”
1.4 Downloading the book’s source code
1.5 What does Rust look and feel like?
1.6 What is Rust?
1.10 Where does Rust fit best?
Resource-constrained environments
1.11 Rust’s hidden feature: Its community
1.12 Rust phrase book
Part 1 Rust language distinctives
2.1 Creating a running program
Compiling single files with rustc
Compiling Rust projects with cargo
Defining variables and calling functions
2.3 Numbers
Integers and decimal (floating-point) numbers
Integers with base 2, base 8, and base 16 notation
Rational, complex numbers, and other numeric types
2.4 Flow control
For: The central pillar of iteration
Continue: Skipping the rest of the current iteration
While: Looping until a condition changes its state
Loop: The basis for Rust’s looping constructs
If, if else, and else: Conditional branching
Match: Type-aware pattern matching
2.6 Using references
2.7 Project: Rendering the Mandelbrot set
2.8 Advanced function definitions
2.10 Making lists of things with arrays, slices, and vectors
2.11 Including third-party code
Adding support for regular expressions
Generating the third-party crate documentation locally
Managing Rust toolchains with rustup
2.12 Supporting command-line arguments
2.13 Reading from files
2.14 Reading from stdin
3.1 Using plain functions to experiment with an API
3.2 Modeling files with struct
3.3 Adding methods to a struct with impl
Simplifying object creation by implementing new()
3.4 Returning errors
Modifying a known global variable
Making use of the Result return type
3.5 Defining and making use of an enum
Using an enum to manage internal state
3.6 Defining common behavior with traits
Implementing std::fmt::Display for your own types
3.7 Exposing your types to the world
3.8 Creating inline documentation for your projects
Using rustdoc to render docs for a single source file
Using cargo to render docs for a crate and its dependencies
4 Lifetimes, ownership, and borrowing
4.1 Implementing a mock CubeSat ground station
Encountering our first lifetime issue
Special behavior of primitive types
4.2 Guide to the figures in this chapter
4.3 What is an owner? Does it have any responsibilities?
4.5 Resolving ownership issues
Use references where full ownership is not required
Wrap data within specialty types
Part 2 Demystifying systems programming
5.3 Representing decimal numbers
Dissecting a floating-point number
5.5 Fixed-point number formats
5.6 Generating random probabilities from random bytes
5.7 Implementing a CPU to establish that functions are also data
Full code listing for CPU RIA/1: The Adder
6 Memory
6.1 Pointers
6.2 Exploring Rust’s reference and pointer types
6.3 Providing programs with memory for their data
What is dynamic memory allocation?
Analyzing the impact of dynamic memory allocation
6.4 Virtual memory
Step 1: Having a process scan its own memory
Translating virtual addresses to physical addresses
Step 2: Working with the OS to scan an address space
Step 3: Reading from and writing to process memory
7.2 Creating your own file formats for data storage
Writing data to disk with serde and the bincode format
7.3 Implementing a hexdump clone
Opening a file in Rust and controlling its file mode
Interacting with the filesystem in a type-safe manner with std::fs::Path
7.5 Implementing a key-value store with a log-structured, append-only storage architecture
Introducing actionkv v1: An in-memory key-value store with a command-line interface
7.6 Actionkv v1: The front-end code
Tailoring what is compiled with conditional compilation
7.7 Understanding the core of actionkv: The libactionkv crate
Initializing the ActionKV struct
Processing an individual record
Writing multi-byte binary data to disk in a guaranteed byte order
Validating I/O errors with checksums
Inserting a new key-value pair into an existing database
The full code listing for actionkv
Working with keys and values with HashMap and BTreeMap
Creating a HashMap and populating it with values
Retrieving values from HashMap and BTreeMap
How to decide between HashMap and BTreeMap
Adding a database index to actionkv v2.0
8.1 All of networking in seven paragraphs
8.2 Generating an HTTP GET request with reqwest
8.3 Trait objects
Creating a tiny role-playing game: The rpg project
8.4 TCP
Converting a hostname to an IP address
8.5 Ergonomic error handling for libraries
Issue: Unable to return multiple error types
Wrapping downstream errors by defining our own error type
Cheating with unwrap() and expect()
8.6 MAC addresses
8.7 Implementing state machines with Rust’s enums
8.8 Raw TCP
8.9 Creating a virtual networking device
8.10 “Raw” HTTP
9.1 Background
9.2 Sources of time
9.3 Definitions
9.4 Encoding time
9.5 clock v0.1.0: Teaching an application how to tell the time
9.6 clock v0.1.1: Formatting timestamps to comply with ISO 8601 and email standards
Refactoring the clock v0.1.0 code to support a wider architecture
Providing a full command-line interface
9.7 clock v0.1.2: Setting the time
Setting the time for operating systems that use libc
Setting the time on MS Windows
clock v0.1.2: The full code listing
9.9 clock v0.1.3: Resolving differences between clocks with the Network Time Protocol (NTP)
Sending NTP requests and interpreting responses
Adjusting the local time as a result of the server’s response
Converting between time representations that use different precisions and epochs
clock v0.1.3: The full code listing
10 Processes, threads, and containers
10.1 Anonymous functions
10.2 Spawning threads
Effect of spawning a few threads
Effect of spawning many threads
10.3 Differences between closures and functions
10.4 Procedurally generated avatars from a multithreaded parser and code generator
How to run render-hex and its intended output
Single-threaded render-hex overview
Spawning a thread per logical task
Using a thread pool and task queue
10.5 Concurrency and task virtualization
Why use an operating system (OS) at all?
11 Kernel
11.1 A fledgling operating system (FledgeOS)
Setting up a development environment for developing an OS kernel
Verifying the development environment
11.2 Fledgeos-0: Getting something working
Writing to the screen with VGA-compatible text mode
_start(): The main() function for FledgeOS
11.3 fledgeos-1: Avoiding a busy loop
Being power conscious by interacting with the CPU directly
11.4 fledgeos-2: Custom exception handling
Handling exceptions properly, almost
Writing colored text to the screen
Controlling the in-memory representation of enums
Creating a type that can print to the VGA frame buffer
11.6 fledgeos-4: Custom panic handling
Implementing a panic handler that reports the error to the user
Reimplementing panic() by making use of core::fmt::Write
12 Signals, interrupts, and exceptions
12.1 Glossary
12.2 How interrupts affect applications
12.3 Software interrupts
12.4 Hardware interrupts
12.5 Signal handling
Suspend and resume a program’s operation
Listing all signals supported by the OS
12.6 Handling signals with custom actions
Using a global variable to indicate that shutdown has been initiated
12.7 Sending application-defined signals
Understanding function pointers and their syntax
12.8 Ignoring signals
12.9 Shutting down from deeply nested call stacks
Setting up intrinsics in a program
Casting a pointer to another type
12.10 A note on applying these techniques to platforms without signals
12.11 Revising exceptions