Rust in Action introduces the Rust programming language by exploring numerous systems programming concepts and techniques.You'll be learning Rust by delving into how computers work under the hood.
You'll find yourself playing with persistent storage, memory, networking and even tinkering with CPU instructions. The book takes you through using Rust to extend other applications and teaches you tricks to write blindingly fast code. You'll also discover parallel and concurrent programming.
Purchase of the print book includes a free eBook in PDF, Kindle, and ePub formats from Manning Publications.
Author(s): TS McNamara
Edition: 1
Publisher: Manning Publications
Year: 2020
Language: English
Pages: 400
Tags: Rust, System Programming, Concurrency
Rust in Action MEAP V15
Copyright
Welcome
Brief contents
Chapter 1: Introducing Rust
1.1 How is Rust used?
1.2 What is it like to advocate for Rust at work?
1.3 Installing Rust
1.4 A taste of the language
1.4.1 CHEATING YOUR WAY TO "HELLO, WORLD!"
1.4.2 YOUR FIRST RUST PROGRAM
1.5 Downloading the book’s source code
1.6 What does Rust look and feel like?
1.7 What is Rust?
1.7.1 GOAL OF RUST: SAFETY
1.7.2 GOAL OF RUST: PRODUCTIVITY
1.7.3 GOAL OF RUST: CONTROL
1.8 Rust’s Big Features
1.8.1 PERFORMANCE
1.8.2 CONCURRENCY
1.8.3 MEMORY EFFICIENCY
1.9 Downsides of Rust
1.9.1 CYCLIC DATA STRUCTURES
1.9.2 COMPILE TIMES
1.9.3 STRICTNESS
1.9.4 SIZE OF THE LANGUAGE
1.9.5 HYPE
1.10 Where does Rust fit best?
1.10.1 COMMAND-LINE UTILITIES
1.10.2 DATA PROCESSING
1.10.3 EXTENDING AN APPLICATION
1.10.4 RESOURCE-CONSTRAINED ENVIRONMENTS, SUCH AS MICRO-CONTROLLERS
1.10.5 SERVER-SIDE APPLICATIONS
1.10.6 DESKTOP APPLICATIONS
1.10.7 DESKTOP
1.10.8 MOBILE
1.10.9 WEB
1.10.10 SYSTEMS PROGRAMMING
1.11 Rust’s hidden feature: its community
1.12 Rust phrase book
1.13 Summary
Chapter 2: Language Foundations
2.1 Create a running program
2.1.1 COMPILING SINGLE FILES
2.1.2 COMPILING LARGER PROJECTS
2.2 A glance at Rust’s syntax
2.2.1 DEFINING AND CALLING FUNCTIONS
2.3 Numbers
2.3.1 INTEGERS AND DECIMAL (FLOATING POINT) NUMBERS
2.3.2 INTEGERS WITH BASE 2, BASE 8 AND BASE 16 NOTATION
2.3.3 COMPARING NUMBERS
IMPOSSIBLE TO COMPARE DIFFERENT TYPES
FLOATING POINT TRIP HAZARDS
2.3.4 RATIONAL, COMPLEX NUMBERS AND OTHER NUMERIC TYPES
2.4 Iteration
2.4.1 CREATING ITERATORS THAT SUPPORT FOR LOOPS
2.5 Flow control
2.5.1 FOR: THE CENTRAL PILLAR OF ITERATION
REFERENCES ARE USUALLY WHAT YOU WANT
ANONYMOUS LOOPS
AVOID MANAGING AN INDEX VARIABLE
2.5.2 CONTINUE: SKIPPING THE REST OF THE CURRENT ITERATION
2.5.3 WHILE: LOOPING UNTIL A CONDITION CHANGES ITS STATE
USING WHILE TO STOP ITERATING ONCE A DURATION HAS BEEN REACHED
AVOID WHILE TO LOOP ENDLESSLY
2.5.4 LOOP: THE BASIS FOR RUST’S LOOPING CONSTRUCTS
2.5.5 BREAK: ABORTING A LOOP
BREAK FROM NESTED LOOPS
2.5.6 IF, IF ELSE, AND ELSE: CONDITION TESTING
CONDITIONAL TESTS RETURN VALUES
2.5.7 MATCH: TYPE-AWARE PATTERN MATCHING
2.6 Defining functions
2.7 Project: Rendering the Mandelbrot set
2.8 Advanced function definitions
2.8.1 EXPLICIT LIFETIME ANNOTATIONS
2.8.2 GENERIC FUNCTIONS
2.9 Creating grep-lite
2.10 Making lists of things with arrays, slices and vectors
2.10.1 ARRAYS
2.10.2 SLICES
2.10.3 VECTORS
2.11 Including Third Party Code
2.11.1 ADDING SUPPORT FOR REGULAR EXPRESSIONS
2.11.2 GENERATING CRATES' DOCUMENTATION LOCALLY
2.11.3 MANAGING RUST TOOLCHAINS WITH RUSTUP
2.12 Supporting Command Line Arguments
2.13 Reading From Files
2.14 Reading from STDIN
2.15 Summary
Chapter 3: Compound Data Types
3.1 Using plain functions to experiment with an API
3.2 Modelling files with struct
3.3 Adding Methods to a struct with impl
3.3.1 SIMPLIFYING OBJECT CREATION BY IMPLEMENTING A NEW() METHOD
3.4 Returning errors
3.4.1 MODIFYING A KNOWN GLOBAL VARIABLE
3.4.2 MAKING USE OF THE RESULT RETURN TYPE
3.5 Defining and making use of enum
3.5.1 USING AN ENUM TO MANAGE INTERNAL STATE
3.6 Defining Common Behavior with Traits
3.6.1 CREATING A READ TRAIT
3.6.2 IMPLEMENTING STD::FMT::DISPLAY FOR YOUR OWN TYPES
3.7 Exposing your types to the world
3.7.1 PROTECTING PRIVATE DATA
3.8 Creating In-line Documentation
3.8.1 USING RUSTDOC TO RENDER DOCS FOR A SINGLE SOURCE FILE
3.8.2 USING CARGO TO RENDER DOCS FOR A CRATE AND ITS DEPENDENCIES
3.9 Summary
Chapter 4: Lifetimes, Ownership and Borrowing
4.1 “Implementing” a Mock CubeSat Ground Station
4.1.1 ENCOUNTERING OUR FIRST LIFETIME ISSUE
4.1.2 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.4 How Ownership Moves
4.5 Resolving Ownership Issues
4.5.1 USE REFERENCES WHERE FULL OWNERSHIP IS NOT REQUIRED
4.5.2 USE FEWER LONG-LIVED VALUES
4.5.3 DUPLICATE THE VALUE
IMPLEMENTING COPY
USING CLONE AND COPY
4.5.4 WRAP DATA WITHIN SPECIALTY TYPES
4.6 Summary
Chapter 5: Data in Depth
5.1 Bit Patterns and Types
5.2 Life of an integer
5.2.1 UNDERSTANDING ENDIANNESS
5.3 Decimal Numbers
5.3.1 ABOUT FLOATING POINT
5.3.2 LOOKING INSIDE AN F32
5.3.3 ABOUT THE SIGN BIT
5.3.4 ABOUT THE EXPONENT
5.3.5 ABOUT THE MANTISSA
5.3.6 REPRESENTING DECIMAL NUMBERS IN A SINGLE BYTE WITH A FIXED-POINT NUMBER FORMAT
5.4 Generating f32 values between 0 and 1 from random bytes
5.5 Implementing a CPU in Software to Establish that Functions are also Data
5.5.1 CPU 1: “THE ADDER”
GLOSSARY OF TERMS RELATED TO CPU EMULATION
DEFINING THE CPU
LOADING VALUES INTO REGISTERS
UNDERSTANDING THE EMULATOR’S MAIN LOOP
HOW TO INTERPRET CHIP-8 OPCODES
5.5.2 FIRST WORKING EMULATOR
5.5.3 CPU 2: “THE MULTIPLIER”
EXPANDING THE CPU TO SUPPORT MEMORY
READING OPCODES FROM MEMORY
HANDLING INTEGER OVERFLOW
SECOND WORKING EMULATOR
5.5.4 CPU 3: ADDING FUNCTIONS
EXPANDING THE CPU TO INCLUDE SUPPORT FOR A STACK
IMPLEMENTING CALL AND RETURN
THIRD WORKING EMULATOR
5.5.5 CPU 4: ADDING THE REST
5.6 Summary
Chapter 6: Memory
6.1 Pointers
6.2 Exploring Rust’s reference and pointer types
6.2.1 RAW POINTERS IN RUST
6.2.2 RUST’S POINTER ECOSYSTEM
6.2.3 SMART POINTER BUILDING BLOCKS
6.3 Providing programs with memory for their data
6.3.1 THE STACK
6.3.2 THE HEAP
WHAT IS THE HEAP?
6.3.3 WHAT IS DYNAMIC MEMORY ALLOCATION?
6.4 Virtual Memory
6.4.1 BACKGROUND
6.4.2 STEP 1: HAVING A PROCESS SCAN ITS OWN MEMORY
6.4.3 TRANSLATING VIRTUAL ADDRESSES TO PHYSICAL ADDRESSES
6.4.4 STEP 2: WORKING WITH THE OPERATING SYSTEM TO SCAN AN ADDRESS SPACE
6.4.5 STEP 3: READING AND WRITING BYTES TO PROCESSES' MEMORY
6.5 Wrap up
Chapter 7: Files & Storage
7.1 What is a file format?
7.2 Creating your own file formats for data storage with serde
7.2.1 WRITING DATA TO DISK WITH SERDE & THE BINCODE FORMAT
7.3 Implementing a hexdump Clone
7.4 File operations in Rust
7.4.1 OPENING A FILE IN RUST AND CONTROLLING ITS FILE MODE
7.4.2 INTERACTING WITH THE FILE SYSTEM IN A TYPE-SAFE MANNER WITH STD::FS::PATH
7.5 Implementing a key-value store with a log-structured, append-only storage architecture
7.5.1 THE KEY-VALUE MODEL
7.5.2 INTRODUCING ACTIONKV V0.1: AN IN-MEMORY KEY-VALUE STORE WITH A COMMAND LINE INTERFACE
7.6 actionkv v0.1 front-end code
7.6.1 TAILORING WHAT IS COMPILED WITH CONDITIONAL COMPILATION
7.7 Understanding the core of actionkv: the libactionkv crate
7.7.1 INITIALIZING THE ACTIONKV STRUCT
7.7.2 PROCESSING AN INDIVIDUAL RECORD
7.7.3 WRITING MULTI-BYTE BINARY DATA TO DISK IN A GUARANTEED BYTE ORDER
7.7.4 VALIDATING I/O ERRORS WITH CHECKSUMS
IMPLEMENTING PARITY BIT CHECKING
7.7.5 INSERTING A NEW KEY-VALUE PAIR INTO AN EXISTING DATABASE
7.7.6 LIBACTIONKV FULL CODE LISTING
7.7.7 WORKING WITH KEYS AND VALUES WITH HASHMAP AND BTREEMAP
7.7.8 CREATING A HASHMAP AND POPULATING IT WITH VALUES
7.7.9 RETRIEVING VALUES FROM HASHMAP AND BTREEMAP
7.7.10 HOW TO DECIDE BETWEEN HASHMAP AND BTREEMAP
7.7.11 ADDING DATABASE INDEX TO ACTION_KV V0.2
7.8 Summary
Chapter 8: Networking
8.1 Just enough HTTP
8.2 Generating an HTTP GET request with reqwest
8.3 Trait Objects
8.3.1 WHAT DO TRAIT OBJECTS ENABLE?
8.3.2 WHAT IS A TRAIT OBJECT?
8.3.3 CREATING A TINY ROLE-PLAYING GAME
8.4 TCP
8.4.1 WHAT IS A “PORT NUMBER”?
8.4.2 CONVERTING A HOSTNAME TO AN IP ADDRESS
8.5 Ergonomic Error Handling for Libraries
8.5.1 ISSUE: UNABLE TO RETURN MULTIPLE ERROR TYPES
8.5.2 WRAPPING DOWNSTREAM ERRORS BY DEFINING OUR OWN ERROR TYPE
DEFINE AN ENUM THAT INCLUDES THE UPSTREAM ERRORS AS VARIANTS
ANNOTATE THE ENUM WITH #[DERIVE(DEBUG)]
IMPLEMENT STD::FMT::DISPLAY
IMPLEMENT STD::ERROR::ERROR
USE MAP_ERR() IN YOUR CODE TO CONVERT THE UPSTREAM ERROR TO YOUR OMNIBUS ERROR TYPE
IMPLEMENT STD::CONVERT::FROM TO REMOVE THE NEED TO CALL MAP_ERR()
8.5.3 CHEAT WITH UNWRAP() AND EXPECT()
8.6 MAC addresses
8.6.1 GENERATING 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
8.11 Wrapping Up
Chapter 9: Time and Time Keeping
9.1 Background
9.2 Sources of Time
9.3 Definitions
9.4 Encoding Time
9.4.1 REPRESENTING TIME ZONES
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
9.6.1 REFACTORING THE CLOCK V0.1.0 CODE TO SUPPORT WIDER ARCHITECTURE
9.6.2 FORMATTING THE TIME AS A UNIX TIMESTAMP OR A FORMATTED STRING ACCORDING TO ISO 8601, RFC 2822, AND RFC 3339
9.6.3 PROVIDING A FULL COMMAND-LINE INTERFACE
9.6.4 THE FULL CLOCK V0.1.1 CODE LISTING
9.7 clock v0.1.2: Setting the time
9.7.1 COMMON BEHAVIOR
9.7.2 SETTING THE TIME IN OPERATING SYSTEMS THAT USE LIBC
LIBC IS TYPE-HEAVY AS IT USES MANY ALIASES
NON-WINDOWS CLOCK CODE
9.7.3 SETTING THE TIME ON MS WINDOWS
WINDOWS API INTEGER TYPES
REPRESENTING THE TIME IN WINDOWS
WINDOWS CLOCK CODE
9.7.4 CLOCK V0.1.2 FULL CODE LISTING
9.8 Improving error handling
9.9 clock v0.1.3 Resolving differences between clocks with the Network Time Protocol (NTP)
9.9 clock v0.1.3 Resolving differences between clocks with the Network Time Protocol (NTP)
9.9.1 SENDING NTP REQUESTS AND INTERPRETING RESPONSES
9.9.2 ADJUSTING THE LOCAL TIME AS A RESULT OF THE SERVER’S RESPONSE
9.9.3 CONVERTING BETWEEN TIME REPRESENTATIONS THAT USE DIFFERENT PRECISIONS AND EPOCHS
9.9.4 CLOCK V0.1.3 FULL CODE LISTING
9.10 Summary
Chapter 10: Processes, Threads and Containers
10.1 Anonymous Functions
10.2 Spawning Threads
10.2.1 WHAT DOES IT MEAN TO "JOIN" THREADS?
10.2.2 CREATING MORE THREADS TAKES ALMOST NO TIME AT ALL
10.2.3 EFFECT OF SPAWNING MANY THREADS
YIELDING CONTROL WITH THREAD::YIELD_NOW()
10.2.4 SHARED VARIABLE
10.3 Closures (||{}) vs functions and methods (fn)
10.4 Procedurally generated avatars from a multi-threaded parser and code generator
10.4.1 HOW TO RUN RENDER-HEX AND ITS INTENDED OUTPUT
10.4.2 SINGLE-THREADED RENDER-HEX OVERVIEW
INPUT PARSING
INTERPRET INSTRUCTIONS
GENERATING AN SVG
SOURCE CODE FOR THE SINGLE-THREADED VERSION OF RENDER-HEX
10.4.3 SPAWNING A THREAD PER LOGICAL TASK
USING A FUNCTIONAL PROGRAMMING STYLE
USING A PARALLEL ITERATOR
10.4.4 USING A THREAD POOL AND TASK QUEUE
ONE-WAY COMMUNICATION
WHAT CAN BE SENT THROUGH A CHANNEL?
TWO-WAY COMMUNICATION
IMPLEMENTING A TASK QUEUE
10.5 Concurrency and task virtualization
10.5.1 THREADS
10.5.2 WHAT IS A CONTEXT SWITCH?
10.5.3 PROCESSES
10.5.4 WEB ASSEMBLY
10.5.5 CONTAINERS
10.5.6 WHY USE AN OPERATING SYSTEM AT ALL?
10.6 What you have learned
Chapter 11: Kernel
11.1 A fledgling operating system (FledgeOS)
11.1.1 SETTING UP A DEVELOPMENT ENVIRONMENT FOR DEVELOPING AN OPERATING SYSTEM KERNEL
11.1.2 FLEDGEOS PROJECT STRUCTURE
11.1.3 A MINIMAL OPERATING SYSTEM KERNEL
11.1.4 PANIC HANDLING
11.1.5 WRITING TO THE SCREEN WITH VGA-COMPATIBLE TEXT MODE
11.1.6 _START(), THE "MAIN()" FUNCTION FOR FLEDGEOS
11.1.7 BEING POWER CONSCIOUS BY INTERACTING WITH THE CPU DIRECTLY
11.1.8 HANDLING EXCEPTIONS PROPERLY, ALMOST
11.2 Nice output
11.2.1 CONTROLLING THE IN-MEMORY REPRESENTATION OF ENUMS
11.2.2 WHY USE ENUMS?
11.2.3 CREATING A TYPE THAT CAN “PRINT” TO THE VGA FRAME BUFFER
11.2.4 PRINTING TO THE SCREEN
11.2.5 FULL CODE LISTING OF FLEDGEOS WITH PRINTING ENABLED
11.3 Implementing a panic handler that reports the error to the user
11.3.1 RE-IMPLEMENTING PANIC() BY MAKING USE OF CORE::FMT::WRITE
11.3.2 IMPLEMENTING CORE::FMT::WRITE
11.3.3 FULL CODE LISTING FOR FLEDGEOS WITH USER-FRIENDLY PANIC HANDLING
11.4 Summing Up
Chapter 12: Signals, Interrupts and Exceptions
12.1 Disambiguating several related terms
12.2 Avoiding writing code by relying on the default signal handling behavior
12.2.1 USING SIGSTOP AND SIGCONT TO SUSPEND AND RESUME A PROGRAM’S OPERATION
12.2.2 LISTING ALL SIGNALS SUPPORTED BY THE OPERATING SYSTEM
12.3 Handling signals with custom actions
12.3.1 GLOBAL VARIABLES IN RUST
12.3.2 USING A GLOBAL VARIABLE TO INDICATE THAT SHUTDOWN HAS BEEN INITIATED
12.4 Sending application-defined signals
12.4.1 UNDERSTANDING FUNCTION POINTERS AND THEIR SYNTAX
12.5 Ignoring signals
12.6 Shutting down from deeply nested call stacks
12.6.1 SETTING UP INTRINSICS IN A PROGRAM
WHAT IS AN INTRINSIC FUNCTION?
WHAT IS LLVM?
12.6.2 CASTING A POINTER TO ANOTHER TYPE
12.6.3 RUNNING THE LINUX-SPECIFIC CODE FROM LISTING 12.23 IN OTHER OPERATING SYSTEMS VIA DOCKER
12.6.4 COMPILING THE CODE
12.7 A note on applying these techniques to platforms without signals
12.8 Revising exceptions
12.9 Summary