contents

Front matter

preface

acknowledgments

about this book

about the author

about the cover illustration

1 Feelin’ Rusty

1.1 What’s Rust?

1.2 What’s unique about Rust?

Rust is safe

Rust is modern

Rust is pure open source

Rust vs. other popular languages

1.3 When should you use Rust?

Rust use cases

1.4 Tools you’ll need

Part 1 Pro Rust

2 Project management with Cargo

2.1 Cargo tour

Basic usage

Creating a new application or library

Building, running, and testing

Switching between toolchains

2.2 Dependency management

Handling the Cargo.lock file

2.3 Feature flags

2.4 Patching dependencies

Indirect dependencies

Best practices for dependency patching

2.5 Publishing crates

CI/CD integration

2.6 Linking to C libraries

2.7 Binary distribution

Cross compilation

Building statically linked binaries

2.8 Documenting Rust projects

Code examples in documentation

2.9 Modules

2.10 Workspaces

2.11 Custom building scripts

2.12 Rust projects in embedded environments

Memory allocation

3 Rust tooling

3.1 Overview of Rust tooling

3.2 Using rust-analyzer for Rust IDE integration

Magic completions

3.3 Using rustfmt to keep code tidy

Installing rustfmt

Configuring rustfmt

3.4 Using Clippy to improve code quality

Installing Clippy

Clippy’s lints

Configuring Clippy

Automatically applying Clippy’s suggestions

Using Clippy in CI/CD

3.5 Reducing compile times with sccache

Installing sccache

Configuring sccache

3.6 Integration with IDEs, including Visual Studio Code

3.7 Using toolchains: Stable vs. nightly

Nightly-only features

Using nightly on published crates

3.8 Additional tools: cargo-update, cargo-expand, cargo-fuzz, cargo-watch, cargo-tree

Keeping packages up to date date with cargo-update

Debugging macros with cargo-expand

Testing libFuzzer

Iterating with cargo-watch

Examining dependencies with cargo-tree

Part 2 Core data

4 Data structures

4.1 Demystifying String, str, &str, and &'static str

String vs str

Using strings effectively

4.2 Understanding slices and arrays

4.3 Vectors

Diving deeper into Vec

Wrapping vectors

Types related to vectors

4.4 Maps

Custom hashing functions

Creating hashable types

4.5 Rust types: Primitives, structs, enums, and aliases

Using primitive types

Using tuples

Using structs

Using enums

Using aliases

4.6 Error handling with Result

4.7 Converting types with From/Into

TryFrom and TryInto

Best practices for type conversion using From and Into

4.8 Handling FFI compatibility with Rust’s types

5 Working with memory

5.1 Memory management: Heap and stack

5.2 Understanding ownership: Copies, borrowing, references, and moves

5.3 Deep copying

5.4 Avoiding copies

5.5 To box or not to box: Smart pointers

5.6 Reference counting

5.7 Clone on write

5.8 Custom allocators

Writing a custom allocator

Creating a custom allocator for protected memory

5.9 Smart pointers summarized

Part 3 Correctness

6 Unit testing

6.1 How testing is different in Rust

6.2 Review of built-in testing features

6.3 Testing frameworks

6.4 What not to test: Why the compiler knows better than you

6.5 Handling parallel test special cases and global state

6.6 Thinking about refactoring

6.7 Refactoring tools

Reformatting

Renaming

Relocating

Rewriting

6.8 Code coverage

6.9 Dealing with a changing ecosystem

7 Integration testing

7.1 Comparing integration and unit testing

7.2 Integration testing strategies

7.3 Built-in integration testing vs. external integration testing

7.4 Integration testing libraries and tooling

Using assert_cmd to test CLI applications

Using proptest with integration tests

Other integration testing tools

7.5 Fuzz testing

Part 4 Asynchronous Rust

8 Async Rust

8.1 Runtimes

8.2 Thinking asynchronously

8.3 Futures: Handling async task results

Defining a runtime with #[tokio::main]

8.4 The async and .await keywords: When and where to use them

8.5 Concurrency and parallelism with async

8.6 Implementing an async observer

8.7 Mixing sync and async

8.8 When to avoid using async

8.9 Tracing and debugging async code

8.10 Dealing with async when testing

9 Building an HTTP REST API service

9.1 Choosing a web framework

9.2 Creating an architecture

9.3 API design

9.4 Libraries and tools

9.5 Application scaffolding

main()

init_tracing()

init_dbpool()

9.6 Data modeling

SQL schema

Interfacing with our data

9.7 Declaring the API routes

9.8 Implementing the API routes

9.9 Error handling

9.10 Running the service

10 Building an HTTP REST API CLI

10.1 Deciding which tools and libraries to use

10.2 Designing the CLI

10.3 Declaring the commands

10.4 Implementing the commands

10.5 Implementing requests

10.6 Handling errors gracefully

10.7 Testing our CLI

Part 5 Optimizations

11 Optimizations

11.1 Zero-cost abstractions

11.2 Vectors

Vector memory allocation

Vector iterators

Fast copies with Vec and slices

11.3 SIMD

11.4 Parallelization with Rayon

11.5 Using Rust to accelerate other languages

11.6 Where to go from here

11.7 Installing tools for this book

Installing tools on macOS using Homebrew

Installing tools on Linux systems

Installing rustup on Linux- or UNIX-based systems

Installing tools on Windows

11.8 Managing rustc and other Rust components with rustup

Installing rustc and other components

Switching default toolchains with rustup

Updating Rust components

Installing HTTPie

appendix

index