0%

Rust in Action is a hands-on guide to systems programming with Rust. Written for inquisitive programmers, it presents real-world use cases that go far beyond syntax and structure. You’ll explore Rust implementations for file manipulation, networking, and kernel-level programming and discover awesome techniques for parallelism and concurrency. Along the way, you’ll master Rust’s unique borrow checker model for memory management without a garbage collector.

Table of Contents

  1. inside front cover
  2. Rust in Action
  3. Copyright
  4. dedication
  5. contents
  6. front matter
    1. preface
    2. acknowledgments
    3. about this book
    4. Who should read this book
    5. How this book is organized: A roadmap
    6. About the code
    7. liveBook discussion forum
    8. Other online resources
    9. about the author
    10. about the cover illustration
  7. 1 Introducing Rust
    1. 1.1 Where is Rust used?
    2. 1.2 Advocating for Rust at work
    3. 1.3 A taste of the language
    4. 1.3.1 Cheating your way to “Hello, world!”
    5. 1.3.2 Your first Rust program
    6. 1.4 Downloading the book’s source code
    7. 1.5 What does Rust look and feel like?
    8. 1.6 What is Rust?
    9. 1.6.1 Goal of Rust: Safety
    10. 1.6.2 Goal of Rust: Productivity
    11. 1.6.3 Goal of Rust: Control
    12. 1.7 Rust’s big features
    13. 1.7.1 Performance
    14. 1.7.2 Concurrency
    15. 1.7.3 Memory efficiency
    16. 1.8 Downsides of Rust
    17. 1.8.1 Cyclic data structures
    18. 1.8.2 Compile times
    19. 1.8.3 Strictness
    20. 1.8.4 Size of the language
    21. 1.8.5 Hype
    22. 1.9 TLS security case studies
    23. 1.9.1 Heartbleed
    24. 1.9.2 Goto fail;
    25. 1.10 Where does Rust fit best?
    26. 1.10.1 Command-line utilities
    27. 1.10.2 Data processing
    28. 1.10.3 Extending applications
    29. 1.10.4 Resource-constrained environments
    30. 1.10.5 Server-side applications
    31. 1.10.6 Desktop applications
    32. 1.10.7 Desktop
    33. 1.10.8 Mobile
    34. 1.10.9 Web
    35. 1.10.10 Systems programming
    36. 1.11 Rust’s hidden feature: Its community
    37. 1.12 Rust phrase book
    38. Summary
  8. Part 1 Rust language distinctives
  9. 2 Language foundations
    1. 2.1 Creating a running program
    2. 2.1.1 Compiling single files with rustc
    3. 2.1.2 Compiling Rust projects with cargo
    4. 2.2 A glance at Rust’s syntax
    5. 2.2.1 Defining variables and calling functions
    6. 2.3 Numbers
    7. 2.3.1 Integers and decimal (floating-point) numbers
    8. 2.3.2 Integers with base 2, base 8, and base 16 notation
    9. 2.3.3 Comparing numbers
    10. 2.3.4 Rational, complex numbers, and other numeric types
    11. 2.4 Flow control
    12. 2.4.1 For: The central pillar of iteration
    13. 2.4.2 Continue: Skipping the rest of the current iteration
    14. 2.4.3 While: Looping until a condition changes its state
    15. 2.4.4 Loop: The basis for Rust’s looping constructs
    16. 2.4.5 Break: Aborting a loop
    17. 2.4.6 If, if else, and else: Conditional branching
    18. 2.4.7 Match: Type-aware pattern matching
    19. 2.5 Defining functions
    20. 2.6 Using references
    21. 2.7 Project: Rendering the Mandelbrot set
    22. 2.8 Advanced function definitions
    23. 2.8.1 Explicit lifetime annotations
    24. 2.8.2 Generic functions
    25. 2.9 Creating grep-lite
    26. 2.10 Making lists of things with arrays, slices, and vectors
    27. 2.10.1 Arrays
    28. 2.10.2 Slices
    29. 2.10.3 Vectors
    30. 2.11 Including third-party code
    31. 2.11.1 Adding support for regular expressions
    32. 2.11.2 Generating the third-party crate documentation locally
    33. 2.11.3 Managing Rust toolchains with rustup
    34. 2.12 Supporting command-line arguments
    35. 2.13 Reading from files
    36. 2.14 Reading from stdin
    37. Summary
  10. 3 Compound data types
    1. 3.1 Using plain functions to experiment with an API
    2. 3.2 Modeling files with struct
    3. 3.3 Adding methods to a struct with impl
    4. 3.3.1 Simplifying object creation by implementing new()
    5. 3.4 Returning errors
    6. 3.4.1 Modifying a known global variable
    7. 3.4.2 Making use of the Result return type
    8. 3.5 Defining and making use of an enum
    9. 3.5.1 Using an enum to manage internal state
    10. 3.6 Defining common behavior with traits
    11. 3.6.1 Creating a Read trait
    12. 3.6.2 Implementing std::fmt::Display for your own types
    13. 3.7 Exposing your types to the world
    14. 3.7.1 Protecting private data
    15. 3.8 Creating inline documentation for your projects
    16. 3.8.1 Using rustdoc to render docs for a single source file
    17. 3.8.2 Using cargo to render docs for a crate and its dependencies
    18. Summary
  11. 4 Lifetimes, ownership, and borrowing
    1. 4.1 Implementing a mock CubeSat ground station
    2. 4.1.1 Encountering our first lifetime issue
    3. 4.1.2 Special behavior of primitive types
    4. 4.2 Guide to the figures in this chapter
    5. 4.3 What is an owner? Does it have any responsibilities?
    6. 4.4 How ownership moves
    7. 4.5 Resolving ownership issues
    8. 4.5.1 Use references where full ownership is not required
    9. 4.5.2 Use fewer long-lived values
    10. 4.5.3 Duplicate the value
    11. 4.5.4 Wrap data within specialty types
    12. Summary
  12. Part 2 Demystifying systems programming
  13. 5 Data in depth
    1. 5.1 Bit patterns and types
    2. 5.2 Life of an integer
    3. 5.2.1 Understanding endianness
    4. 5.3 Representing decimal numbers
    5. 5.4 Floating-point numbers
    6. 5.4.1 Looking inside an f32
    7. 5.4.2 Isolating the sign bit
    8. 5.4.3 Isolating the exponent
    9. 5.4.4 Isolate the mantissa
    10. 5.4.5 Dissecting a floating-point number
    11. 5.5 Fixed-point number formats
    12. 5.6 Generating random probabilities from random bytes
    13. 5.7 Implementing a CPU to establish that functions are also data
    14. 5.7.1 CPU RIA/1: The Adder
    15. 5.7.2 Full code listing for CPU RIA/1: The Adder
    16. 5.7.3 CPU RIA/2: The Multiplier
    17. 5.7.4 CPU RIA/3: The Caller
    18. 5.7.5 CPU 4: Adding the rest
    19. Summary
  14. 6 Memory
    1. 6.1 Pointers
    2. 6.2 Exploring Rust’s reference and pointer types
    3. 6.2.1 Raw pointers in Rust
    4. 6.2.2 Rust’s pointer ecosystem
    5. 6.2.3 Smart pointer building blocks
    6. 6.3 Providing programs with memory for their data
    7. 6.3.1 The stack
    8. 6.3.2 The heap
    9. 6.3.3 What is dynamic memory allocation?
    10. 6.3.4 Analyzing the impact of dynamic memory allocation
    11. 6.4 Virtual memory
    12. 6.4.1 Background
    13. 6.4.2 Step 1: Having a process scan its own memory
    14. 6.4.3 Translating virtual addresses to physical addresses
    15. 6.4.4 Step 2: Working with the OS to scan an address space
    16. 6.4.5 Step 3: Reading from and writing to process memory
    17. Summary
  15. 7 Files and storage
    1. 7.1 What is a file format?
    2. 7.2 Creating your own file formats for data storage
    3. 7.2.1 Writing data to disk with serde and the bincode format
    4. 7.3 Implementing a hexdump clone
    5. 7.4 File operations in Rust
    6. 7.4.1 Opening a file in Rust and controlling its file mode
    7. 7.4.2 Interacting with the filesystem in a type-safe manner with std::fs::Path
    8. 7.5 Implementing a key-value store with a log-structured, append-only storage architecture
    9. 7.5.1 The key-value model
    10. 7.5.2 Introducing actionkv v1: An in-memory key-value store with a command-line interface
    11. 7.6 Actionkv v1: The front-end code
    12. 7.6.1 Tailoring what is compiled with conditional compilation
    13. 7.7 Understanding the core of actionkv: The libactionkv crate
    14. 7.7.1 Initializing the ActionKV struct
    15. 7.7.2 Processing an individual record
    16. 7.7.3 Writing multi-byte binary data to disk in a guaranteed byte order
    17. 7.7.4 Validating I/O errors with checksums
    18. 7.7.5 Inserting a new key-value pair into an existing database
    19. 7.7.6 The full code listing for actionkv
    20. 7.7.7 Working with keys and values with HashMap and BTreeMap
    21. 7.7.8 Creating a HashMap and populating it with values
    22. 7.7.9 Retrieving values from HashMap and BTreeMap
    23. 7.7.10 How to decide between HashMap and BTreeMap
    24. 7.7.11 Adding a database index to actionkv v2.0
    25. Summary
  16. 8 Networking
    1. 8.1 All of networking in seven paragraphs
    2. 8.2 Generating an HTTP GET request with reqwest
    3. 8.3 Trait objects
    4. 8.3.1 What do trait objects enable?
    5. 8.3.2 What is a trait object?
    6. 8.3.3 Creating a tiny role-playing game: The rpg project
    7. 8.4 TCP
    8. 8.4.1 What is a port number?
    9. 8.4.2 Converting a hostname to an IP address
    10. 8.5 Ergonomic error handling for libraries
    11. 8.5.1 Issue: Unable to return multiple error types
    12. 8.5.2 Wrapping downstream errors by defining our own error type
    13. 8.5.3 Cheating with unwrap() and expect()
    14. 8.6 MAC addresses
    15. 8.6.1 Generating MAC addresses
    16. 8.7 Implementing state machines with Rust’s enums
    17. 8.8 Raw TCP
    18. 8.9 Creating a virtual networking device
    19. 8.10 “Raw” HTTP
    20. Summary
  17. 9 Time and timekeeping
    1. 9.1 Background
    2. 9.2 Sources of time
    3. 9.3 Definitions
    4. 9.4 Encoding time
    5. 9.4.1 Representing time zones
    6. 9.5 clock v0.1.0: Teaching an application how to tell the time
    7. 9.6 clock v0.1.1: Formatting timestamps to comply with ISO 8601 and email standards
    8. 9.6.1 Refactoring the clock v0.1.0 code to support a wider architecture
    9. 9.6.2 Formatting the time
    10. 9.6.3 Providing a full command-line interface
    11. 9.6.4 clock v0.1.1: Full project
    12. 9.7 clock v0.1.2: Setting the time
    13. 9.7.1 Common behavior
    14. 9.7.2 Setting the time for operating systems that use libc
    15. 9.7.3 Setting the time on MS Windows
    16. 9.7.4 clock v0.1.2: The full code listing
    17. 9.8 Improving error handling
    18. 9.9 clock v0.1.3: Resolving differences between clocks with the Network Time Protocol (NTP)
    19. 9.9.1 Sending NTP requests and interpreting responses
    20. 9.9.2 Adjusting the local time as a result of the server’s response
    21. 9.9.3 Converting between time representations that use different precisions and epochs
    22. 9.9.4 clock v0.1.3: The full code listing
    23. Summary
  18. 10 Processes, threads, and containers
    1. 10.1 Anonymous functions
    2. 10.2 Spawning threads
    3. 10.2.1 Introduction to closures
    4. 10.2.2 Spawning a thread
    5. 10.2.3 Effect of spawning a few threads
    6. 10.2.4 Effect of spawning many threads
    7. 10.2.5 Reproducing the results
    8. 10.2.6 Shared variables
    9. 10.3 Differences between closures and functions
    10. 10.4 Procedurally generated avatars from a multithreaded parser and code generator
    11. 10.4.1 How to run render-hex and its intended output
    12. 10.4.2 Single-threaded render-hex overview
    13. 10.4.3 Spawning a thread per logical task
    14. 10.4.4 Using a thread pool and task queue
    15. 10.5 Concurrency and task virtualization
    16. 10.5.1 Threads
    17. 10.5.2 What is a context switch?
    18. 10.5.3 Processes
    19. 10.5.4 WebAssembly
    20. 10.5.5 Containers
    21. 10.5.6 Why use an operating system (OS) at all?
    22. Summary
  19. 11 Kernel
    1. 11.1 A fledgling operating system (FledgeOS)
    2. 11.1.1 Setting up a development environment for developing an OS kernel
    3. 11.1.2 Verifying the development environment
    4. 11.2 Fledgeos-0: Getting something working
    5. 11.2.1 First boot
    6. 11.2.2 Compilation instructions
    7. 11.2.3 Source code listings
    8. 11.2.4 Panic handling
    9. 11.2.5 Writing to the screen with VGA-compatible text mode
    10. 11.2.6 _start(): The main() function for FledgeOS
    11. 11.3 fledgeos-1: Avoiding a busy loop
    12. 11.3.1 Being power conscious by interacting with the CPU directly
    13. 11.3.2 fledgeos-1 source code
    14. 11.4 fledgeos-2: Custom exception handling
    15. 11.4.1 Handling exceptions properly, almost
    16. 11.4.2 fledgeos-2 source code
    17. 11.5 fledgeos-3: Text output
    18. 11.5.1 Writing colored text to the screen
    19. 11.5.2 Controlling the in-memory representation of enums
    20. 11.5.3 Why use enums?
    21. 11.5.4 Creating a type that can print to the VGA frame buffer
    22. 11.5.5 Printing to the screen
    23. 11.5.6 fledgeos-3 source code
    24. 11.6 fledgeos-4: Custom panic handling
    25. 11.6.1 Implementing a panic handler that reports the error to the user
    26. 11.6.2 Reimplementing panic() by making use of core::fmt::Write
    27. 11.6.3 Implementing core::fmt::Write
    28. 11.6.4 fledge-4 source code
    29. Summary
  20. 12 Signals, interrupts, and exceptions
    1. 12.1 Glossary
    2. 12.1.1 Signals vs. interrupts
    3. 12.2 How interrupts affect applications
    4. 12.3 Software interrupts
    5. 12.4 Hardware interrupts
    6. 12.5 Signal handling
    7. 12.5.1 Default behavior
    8. 12.5.2 Suspend and resume a program’s operation
    9. 12.5.3 Listing all signals supported by the OS
    10. 12.6 Handling signals with custom actions
    11. 12.6.1 Global variables in Rust
    12. 12.6.2 Using a global variable to indicate that shutdown has been initiated
    13. 12.7 Sending application-defined signals
    14. 12.7.1 Understanding function pointers and their syntax
    15. 12.8 Ignoring signals
    16. 12.9 Shutting down from deeply nested call stacks
    17. 12.9.1 Introducing the sjlj project
    18. 12.9.2 Setting up intrinsics in a program
    19. 12.9.3 Casting a pointer to another type
    20. 12.9.4 Compiling the sjlj project
    21. 12.9.5 sjlj project source code
    22. 12.10 A note on applying these techniques to platforms without signals
    23. 12.11 Revising exceptions
    24. Summary
  21. index
34.239.170.244