Preface |
|
xv | |
Acknowledgments |
|
xvii | |
About This Book |
|
xix | |
About The Author |
|
xxii | |
About The Cover Illustration |
|
xxiii | |
|
|
1 | (28) |
|
|
2 | (1) |
|
1.2 Advocating for Rust at work |
|
|
3 | (1) |
|
1.3 A taste of the language |
|
|
4 | (4) |
|
Cheating your way to "Hello, world!" |
|
|
5 | (2) |
|
|
7 | (1) |
|
1.4 Downloading the book's source code |
|
|
8 | (1) |
|
1.5 What does Rust look and feel like? |
|
|
8 | (3) |
|
|
11 | (8) |
|
|
12 | (4) |
|
Goal of Rust: Productivity |
|
|
16 | (2) |
|
|
18 | (1) |
|
|
19 | (1) |
|
|
19 | (1) |
|
|
20 | (1) |
|
|
20 | (1) |
|
|
20 | (1) |
|
|
20 | (1) |
|
|
20 | (1) |
|
|
21 | (1) |
|
|
21 | (1) |
|
|
21 | (1) |
|
1.9 TLS security case studies |
|
|
21 | (2) |
|
|
21 | (1) |
|
|
22 | (1) |
|
1.10 Where does Rust fit best? |
|
|
23 | (3) |
|
|
23 | (1) |
|
|
24 | (1) |
|
|
24 | (1) |
|
Resource-constrained environments |
|
|
24 | (1) |
|
|
25 | (1) |
|
|
25 | (1) |
|
|
25 | (1) |
|
|
25 | (1) |
|
|
26 | (1) |
|
|
26 | (1) |
|
1.11 Rust's hidden feature: Its community |
|
|
26 | (1) |
|
|
26 | (3) |
|
PART 1 RUST LANGUAGE DISTINCTIVES |
|
|
29 | (106) |
|
|
31 | (46) |
|
2.1 Creating a running program |
|
|
33 | (1) |
|
Compiling single files with rustc |
|
|
33 | (1) |
|
Compiling Rust projects with cargo |
|
|
33 | (1) |
|
2.2 A glance at Rust's syntax |
|
|
34 | (2) |
|
Defining variables and calling functions |
|
|
35 | (1) |
|
|
36 | (9) |
|
Integers and decimal (floating-point) numbers |
|
|
36 | (1) |
|
Integers with base 2, base 8, and base 16 notation |
|
|
37 | (1) |
|
|
38 | (5) |
|
Rational, complex numbers, and other numeric types |
|
|
43 | (2) |
|
|
45 | (7) |
|
For: The central pillar of iteration |
|
|
45 | (2) |
|
Continue: Skipping the rest of the current iteration |
|
|
47 | (1) |
|
While: Looping until a condition changes its state |
|
|
47 | (1) |
|
Loop: The basis for Rust's looping constructs |
|
|
48 | (1) |
|
|
48 | (1) |
|
If, if else, and else: Conditional branching |
|
|
49 | (2) |
|
Match: Type-aware pattern matching |
|
|
51 | (1) |
|
|
52 | (1) |
|
|
53 | (1) |
|
2.7 Project: Rendering the Mandelbrot set |
|
|
54 | (2) |
|
2.8 Advanced function definitions |
|
|
56 | (4) |
|
Explicit lifetime annotations |
|
|
56 | (2) |
|
|
58 | (2) |
|
|
60 | (3) |
|
2.10 Making lists of things with arrays, slices, and vectors |
|
|
63 | (4) |
|
|
64 | (1) |
|
|
65 | (1) |
|
|
66 | (1) |
|
2.11 Including third-party code |
|
|
67 | (3) |
|
Adding support for regular expressions |
|
|
68 | (1) |
|
Generating the third-party crate documentation locally |
|
|
69 | (1) |
|
Managing Rust toolchains with rustup |
|
|
70 | (1) |
|
2.12 Supporting command-line arguments |
|
|
70 | (2) |
|
|
72 | (2) |
|
|
74 | (3) |
|
|
77 | (30) |
|
3.1 Using plain functions to experiment with an API |
|
|
78 | (2) |
|
3.2 Modeling files with struct |
|
|
80 | (4) |
|
3.3 Adding methods to a struct with impl |
|
|
84 | (3) |
|
Simplifying object creation by implementing new() |
|
|
84 | (3) |
|
|
87 | (8) |
|
Modifying a known global variable |
|
|
87 | (5) |
|
Making use of the Result return type |
|
|
92 | (3) |
|
3.5 Defining and making use of an enum |
|
|
95 | (3) |
|
Using an enum to manage internal state |
|
|
96 | (2) |
|
3.6 Defining common behavior with traits |
|
|
98 | (4) |
|
|
98 | (1) |
|
Implementing std::fmt::Display for your own types |
|
|
99 | (3) |
|
3.7 Exposing your types to the world |
|
|
102 | (1) |
|
|
102 | (1) |
|
3.8 Creating inline documentation for your projects |
|
|
103 | (4) |
|
Using rustdoc to render docs for a single source file |
|
|
104 | (1) |
|
Using cargo to render docs for a crate and its dependencies |
|
|
104 | (3) |
|
4 Lifetimes, Ownership, And Borrowing |
|
|
107 | (28) |
|
4.1 Implementing a mock CubeSat ground station |
|
|
108 | (6) |
|
Encountering our first lifetime issue |
|
|
110 | (2) |
|
Special behavior of primitive types |
|
|
112 | (2) |
|
4.2 Guide to the figures in this chapter |
|
|
114 | (1) |
|
4.3 What is an owner? Does it have any responsibilities? |
|
|
115 | (1) |
|
|
115 | (3) |
|
4.5 Resolving ownership issues |
|
|
118 | (17) |
|
Use references where full ownership is not required |
|
|
119 | (4) |
|
Use fewer long-lived values |
|
|
123 | (5) |
|
|
128 | (3) |
|
Wrap data within specialty types |
|
|
131 | (4) |
|
PART 2 DEMYSTIFYING SYSTEMS PROGRAMMING |
|
|
135 | (284) |
|
|
137 | (38) |
|
5.1 Bit patterns and types |
|
|
137 | (2) |
|
|
139 | (4) |
|
|
142 | (1) |
|
5.3 Representing decimal numbers |
|
|
143 | (1) |
|
5.4 Floating-point numbers |
|
|
144 | (8) |
|
|
144 | (2) |
|
|
146 | (1) |
|
|
146 | (2) |
|
|
148 | (2) |
|
Dissecting a floating-point number |
|
|
150 | (2) |
|
5.5 Fixed-point number formats |
|
|
152 | (5) |
|
5.6 Generating random probabilities from random bytes |
|
|
157 | (1) |
|
5.7 Implementing a CPU to establish that functions are also data |
|
|
158 | (17) |
|
|
159 | (4) |
|
Full code listing for CPU RIA/1: The Adder |
|
|
163 | (1) |
|
CPU RIA/2: The Multiplier |
|
|
164 | (3) |
|
|
167 | (6) |
|
|
173 | (2) |
|
|
175 | (37) |
|
|
176 | (2) |
|
6.2 Exploring Rust's reference and pointer types |
|
|
178 | (9) |
|
|
183 | (2) |
|
|
185 | (1) |
|
Smart pointer building blocks |
|
|
186 | (1) |
|
6.3 Providing programs with memory for their data |
|
|
187 | (15) |
|
|
188 | (2) |
|
|
190 | (4) |
|
What is dynamic memory allocation? |
|
|
194 | (5) |
|
Analyzing the impact of dynamic memory allocation |
|
|
199 | (3) |
|
|
202 | (10) |
|
|
202 | (1) |
|
Step 1 Having a process scan its own memory |
|
|
203 | (2) |
|
Translating virtual addresses to physical addresses |
|
|
205 | (3) |
|
Step 2 Working with the OS to scan an address space |
|
|
208 | (3) |
|
Step 3 Reading from and writing to process memory |
|
|
211 | (1) |
|
|
212 | (39) |
|
7.1 What is a file format? |
|
|
213 | (1) |
|
7.2 Creating your own file formats for data storage |
|
|
214 | (3) |
|
Writing data to disk with serde and the bincode format |
|
|
214 | (3) |
|
7.3 Implementing a hexdump clone |
|
|
217 | (2) |
|
7.4 File operations in Rust |
|
|
219 | (3) |
|
Opening a file in Rust and controlling its file mode |
|
|
219 | (1) |
|
Interacting with the filesystem in a type-safe manner with std::fs::Path |
|
|
220 | (2) |
|
7.5 Implementing a key-value store with a log-structured, append-only storage architecture |
|
|
222 | (2) |
|
|
222 | (1) |
|
Introducing actionkv v1: An in-memory key-value store with a command-line interface |
|
|
222 | (2) |
|
7.6 Actionkv v1: The front-end code |
|
|
224 | (4) |
|
Tailoring what is compiled with conditional compilation |
|
|
226 | (2) |
|
7.7 Understanding the core of actionkv: The libactionkv crate |
|
|
228 | (23) |
|
Initializing the ActionKV struct |
|
|
228 | (2) |
|
Processing an individual record |
|
|
230 | (2) |
|
Writing multi-byte binary data to disk in a guaranteed byte order |
|
|
232 | (2) |
|
Validating I/O errors with checksums |
|
|
234 | (2) |
|
Inserting a new key-value pair into an existing database |
|
|
236 | (1) |
|
The full code listing for actionkv |
|
|
237 | (4) |
|
Working with keys and values with HashMap and BTreeMap |
|
|
241 | (2) |
|
Creating a HashMap and populating it with values |
|
|
243 | (1) |
|
Retrieving values from HashMap and BTreeMap |
|
|
244 | (1) |
|
How to decide between HashMap and BTreeMap |
|
|
245 | (1) |
|
Adding a database index to actionkv v 2.0 |
|
|
246 | (5) |
|
|
251 | (42) |
|
8.1 All of networking in seven paragraphs |
|
|
252 | (2) |
|
8.2 Generating an HTTP GET request with reqwest |
|
|
254 | (2) |
|
|
256 | (4) |
|
What do trait objects enable? |
|
|
256 | (1) |
|
|
256 | (1) |
|
Creating a tiny role-playing game: The rpg project |
|
|
257 | (3) |
|
|
260 | (8) |
|
|
261 | (1) |
|
Converting a hostname to an IP address |
|
|
261 | (7) |
|
8.5 Ergonomic error handling for libraries |
|
|
268 | (9) |
|
Issue: Unable to return multiple error types |
|
|
269 | (3) |
|
Wrapping downstream errors by defining our own error type |
|
|
272 | (5) |
|
Cheating with unwrap() and expect() |
|
|
277 | (1) |
|
|
277 | (4) |
|
|
279 | (2) |
|
8.7 Implementing state machines with Rust's enums |
|
|
281 | (1) |
|
|
282 | (1) |
|
8.9 Creating a virtual networking device |
|
|
282 | (1) |
|
|
283 | (10) |
|
|
293 | (35) |
|
|
294 | (2) |
|
|
296 | (1) |
|
|
296 | (1) |
|
|
297 | (1) |
|
|
298 | (1) |
|
9.5 Clock v0.1.0: Teaching an application how to tell the time |
|
|
298 | (1) |
|
9.6 Clock v0.1.1: Formatting times tamps to comply with ISO 8601 and email standards |
|
|
299 | (6) |
|
Refadoring the clock v0.1.0 code to support a wider architecture |
|
|
300 | (1) |
|
|
301 | (1) |
|
Providing a full command-line interface |
|
|
301 | (2) |
|
Clock v0.1.1: Full project |
|
|
303 | (2) |
|
9.7 Clock v0.1.2: Setting the time |
|
|
305 | (8) |
|
|
306 | (1) |
|
Setting the time for operating systems that use libc |
|
|
306 | (2) |
|
Setting the time on MS Windows |
|
|
308 | (2) |
|
Clock v0.1.2: The full code listing |
|
|
310 | (3) |
|
9.8 Improving error handling |
|
|
313 | (1) |
|
9.9 Clock v0.1.3: Resolving differences between clocks with the Network Time Protocol (NTP) |
|
|
314 | (14) |
|
Sending NTP requests and interpreting responses |
|
|
314 | (2) |
|
Adjusting the local time as a result of the server's response |
|
|
316 | (2) |
|
Converting between time representations that use different precisions and epochs |
|
|
318 | (1) |
|
Clock v0.1.3: The full code listing |
|
|
319 | (9) |
|
10 Processes, Threads, And Containers |
|
|
328 | (37) |
|
|
329 | (1) |
|
|
330 | (10) |
|
|
330 | (1) |
|
|
331 | (1) |
|
Effect of spawning a few threads |
|
|
331 | (2) |
|
Effect of spawning many threads |
|
|
333 | (2) |
|
|
335 | (3) |
|
|
338 | (2) |
|
10.3 Differences between closures and functions |
|
|
340 | (1) |
|
10.4 Procedurally generated avatars from a multithreaded parser and code generator |
|
|
341 | (19) |
|
How to run render-hex and its intended output |
|
|
342 | (1) |
|
Single-threaded render-hex overview |
|
|
342 | (9) |
|
Spawning a thread per logical task |
|
|
351 | (2) |
|
Using a thread pool and task queue |
|
|
353 | (7) |
|
10.5 Concurrency and task visualization |
|
|
360 | (5) |
|
|
362 | (1) |
|
What is a context switch? |
|
|
362 | (1) |
|
|
363 | (1) |
|
|
363 | (1) |
|
|
363 | (1) |
|
Why use an operating system (OS) at all? |
|
|
363 | (2) |
|
|
365 | (25) |
|
11.1 A fledgling operating system (FledgeOS) |
|
|
365 | (3) |
|
Setting up a development environment for developing an OS kernel |
|
|
366 | (1) |
|
Verifying the development environment |
|
|
367 | (1) |
|
11.2 Fledgeos-0: Getting something working |
|
|
368 | (9) |
|
|
368 | (2) |
|
|
370 | (1) |
|
|
370 | (4) |
|
|
374 | (1) |
|
Writing to the screen with VGA-compatible text mode |
|
|
375 | (2) |
|
Start(): The main() function for FledgeOS |
|
|
377 | (1) |
|
11.3 Fledgeos-1: Avoiding a busy loop |
|
|
377 | (2) |
|
Being power conscious by interacting with the CPU directly |
|
|
377 | (1) |
|
|
378 | (1) |
|
11.4 Fledgeos-2: Custom exception handling |
|
|
379 | (2) |
|
Handling exceptions properly, almost |
|
|
379 | (1) |
|
|
380 | (1) |
|
11.5 Fledgeos-3: Text output |
|
|
381 | (4) |
|
Writing colored text to the screen |
|
|
381 | (1) |
|
Controlling the in-memory representation of enums |
|
|
382 | (1) |
|
|
382 | (1) |
|
Creating a type that can print to the VGA frame buffer |
|
|
382 | (1) |
|
|
383 | (1) |
|
|
383 | (2) |
|
11.6 Fledgeos-4: Custom panic handling |
|
|
385 | (5) |
|
Implementing a panic handler that reports the error to the user |
|
|
385 | (1) |
|
Reimplementing panic() by making use of core::fmt::Write |
|
|
385 | (1) |
|
Implementing core::fmt::Write |
|
|
386 | (1) |
|
|
387 | (3) |
|
12 Signals, Interrupts, And Exceptions |
|
|
390 | (29) |
|
|
391 | (2) |
|
|
391 | (2) |
|
12.2 How interrupts affect applications |
|
|
393 | (2) |
|
|
395 | (1) |
|
|
395 | (1) |
|
|
395 | (5) |
|
|
395 | (2) |
|
Suspend and resume a program's operation |
|
|
397 | (2) |
|
Listing all signals supported by the OS |
|
|
399 | (1) |
|
12.6 Handling signals with custom actions |
|
|
400 | (5) |
|
|
401 | (1) |
|
Using a global variable to indicate that shutdown has been initiated |
|
|
402 | (3) |
|
12.7 Sending application-defined signals |
|
|
405 | (2) |
|
Understanding function pointers and their syntax |
|
|
405 | (2) |
|
|
407 | (1) |
|
12.9 Shutting down from deeply nested call stacks |
|
|
408 | (9) |
|
Introducing the sjlj project |
|
|
409 | (1) |
|
Setting up intrinsics in a program |
|
|
409 | (3) |
|
Casting a pointer to another type |
|
|
412 | (1) |
|
Compiling the sjlj project |
|
|
413 | (1) |
|
|
414 | (3) |
|
12.10 A note on applying these techniques to platforms without signals |
|
|
417 | (1) |
|
12.11 Revising exceptions |
|
|
417 | (2) |
Index |
|
419 | |