Rust for JavaScript Developers
- A Practical Guide to Systems Programming for the Web Developer
Introduction
- Who This Book Is For
- What This Book Covers
- How to Read This Book
- A Note on Code Examples
- Let’s Get Started
Part I: Getting Started
Why Rust?
- What Rust Offers That JavaScript Does Not
- Where Rust Fits in the Software Landscape
- Why JavaScript Developers Are Well-Positioned to Learn Rust
- The Learning Curve Is Real
- What This Book Will Not Do
Setting Up Your Environment
- Installing Rust with rustup
- Tour of the Rust Toolchain
- Editor Setup
- Your First Rust Program
- Project Structure as It Grows
- Summary
Thinking in Rust: A Mental Model Shift
- Interpreted vs Compiled
- Dynamic Typing vs Static Typing
- Garbage Collection vs Ownership
- The Compiler as Your Pair Programmer
- A Side-by-Side: The Same Program
- What to Expect Going Forward
Part II: The Language Fundamentals
Variables, Types, and Functions
- Variables and Mutability
- Scalar Types
- Type Inference
- Type Annotations
- Functions
- Shadowing
- Constants and Statics
- Tuples
- Arrays
- Quick Reference: JS Types to Rust Types
- Summary
Strings and Text
- Why Strings Are More Complex in Rust
- String vs &str
- Creating Strings
- Concatenation
- Common String Operations
- Converting Between String and &str
- The format! Macro
- UTF-8 Encoding
- Practical Patterns
- Summary
Ownership and Borrowing
- The Three Ownership Rules
- Move Semantics
- Borrowing with References
- The Borrowing Rules
- Lifetimes
- Practical Patterns
- Common Ownership Errors and How to Fix Them
- How This Compares to JavaScript
- Summary
Control Flow and Pattern Matching
- if/else Expressions
- Loops
- Pattern Matching with match
- if let: Concise Pattern Matching
- while let: Loop Until Pattern Fails
- let-else: Handle the Failure Case
- Destructuring: Beyond match
- Comparison: JS Destructuring vs Rust Pattern Matching
- Summary
Structs and Implementations
- Defining Structs
- Creating Instances
- Mutability
- Tuple Structs
- Unit Structs
- The impl Block: Adding Methods
- The Builder Pattern
- Deriving Common Traits
- Printing and Displaying Structs
- Comparison: JS Classes vs Rust Structs
- Summary
Enums and Option/Result
- Basic Enums
- Enums with Data
- Methods on Enums
- The Option Enum: Rust’s Answer to null
- The Result Enum: Rust’s Answer to try/catch
- Chaining with map, and_then, unwrap_or
- Converting Between Option and Result
- Practical Example: Parsing a Config File
- Comparison: JS Error Handling vs Rust
- Summary
Collections
- Vec: Dynamic Arrays
- HashMap: Key-Value Maps
- HashSet: Unique Collections
- BTreeMap and BTreeSet
- Choosing the Right Collection
- Practical Example: Word Frequency Counter
- Quick Reference: JS Collections vs Rust Collections
- Summary
Iterators and Closures
- Closures
- Iterators
- Building Custom Iterators
- Practical Example: Data Pipeline
- Quick Reference: JS Array Methods vs Rust Iterators
- Summary
Part III: The Type System in Depth
Traits
- Defining a Trait
- Implementing a Trait
- Default Method Implementations
- Traits as Parameters
- Trait Bounds
- Common Standard Library Traits
- Trait Objects and Dynamic Dispatch
- Returning Traits from Functions
- Implementing External Traits for Your Types (and Vice Versa)
- Comparison: TypeScript Interfaces vs Rust Traits
- Summary
Generics
- Why Generics
- Generic Functions
- Generic Structs
- Generic Enums
- Generic Implementations
- Constraining Generics with Trait Bounds
- Multiple Trait Bounds
- Monomorphization: Zero-Cost Generics
- Turbofish Syntax
- Common Patterns
- Comparison: TypeScript Generics vs Rust Generics
- Summary
Error Handling in Depth
- Designing Error Types
- The thiserror Crate
- The anyhow Crate
- Error Propagation Patterns
- When to Panic vs When to Return an Error
- Practical Example: A CLI Application’s Error Handling
- Comparison: JS Error Handling vs Rust Error Handling
- Summary
Smart Pointers and Interior Mutability
- Box: Heap Allocation
- Rc: Reference Counting
- Arc: Atomic Reference Counting
- RefCell: Interior Mutability
- Cell: Interior Mutability for Copy Types
- Mutex: Thread-Safe Interior Mutability
- Weak: Breaking Reference Cycles
- Choosing the Right Smart Pointer
- Comparison to JavaScript
- Summary
Part IV: Organising and Scaling Rust Code
Modules, Crates, and Packages
- The Hierarchy
- Modules
- File-Based Module Structure
- Crates: Library and Binary
- Workspaces: Monorepos
- Comparison: JS Modules vs Rust Modules
- Summary
Cargo in Depth
- Cargo.toml: The Manifest
- Semantic Versioning
- Adding Dependencies
- Features: Conditional Compilation
- Build Profiles
- Build Scripts
- Publishing to crates.io
- Useful Cargo Subcommands
- Cargo Workspaces for Monorepos
- Comparison: package.json vs Cargo.toml
- Summary
Testing
- Unit Tests
- Assertion Macros
- Testing for Panics
- Tests That Return Result
- Ignoring Tests
- Test Organisation
- Documentation Tests
- Test Filtering and Running
- Mocking and Test Doubles
- Property-Based Testing with proptest
- Benchmarking with criterion
- Comparison: Jest/Vitest vs Rust Testing
- Summary
Part V: Concurrency and Async
Fearless Concurrency
- Threads
- The Send and Sync Traits
- Shared State with Mutex and Arc
- Message Passing with Channels
- Rayon: Easy Data Parallelism
- Common Concurrency Patterns
- Comparison: JS Concurrency vs Rust Concurrency
- Summary
Async Rust
- async/await: The Familiar Parts
- Futures vs Promises
- The Tokio Runtime
- Spawning Async Tasks
- Selecting Between Futures
- Async Channels
- Common Pitfalls
- Streams: Async Iterators
- Practical Example: Concurrent HTTP Requests
- Comparison: JS Async vs Rust Async
- Summary
Part VI: Real-World Rust
Building a CLI Application
- Project Setup with Cargo
- Understanding Clap and Argument Parsing
- Reading Files
- Implementing the Search Logic
- Coloured Terminal Output
- Error Handling and User-Friendly Messages
- Working with stdin and stdout
- Complete minigrep Implementation
- Key Differences from Node.js
- Building for Distribution
- Exercises
Building a Web Server
- The Rust Web Ecosystem
- Why Axum?
- Routing and Handlers
- JSON Serialization and Deserialization
- Middleware and Layers
- Shared State with Arc
- Full Project: Building a Task Manager REST API
- Advanced Extractors
- Error Handling
- Comparison: Axum vs. Express/Fastify
- Performance Considerations
- Deploying a Web Server
- Wrapping Up
Working with Databases
- The Rust Database Ecosystem
- Why SQLx Stands Out
- Setting Up SQLx
- Connecting to Databases
- Migrations with sqlx-cli
- Query Building and Execution
- Advanced Queries
- Transactions
- Connection Pooling
- Mapping Rows to Structs
- Inserting and Updating Data
- Compile-Time Query Verification
- Comparing to JavaScript ORMs
- Advanced Patterns
- Database-Specific Features
- Error Handling
- Summary
Serialization and Deserialization with Serde
- Why Serde is Everywhere
- The Fundamentals: Derive Serialize and Deserialize
- Working with JSON: serde_json
- Working with Other Formats: TOML and YAML
- Customising Serialization with Attributes
- Custom Serialization and Deserialization
- Handling Optional Fields
- Working with Enums
- Advanced Patterns
- Serde Attributes: Quick Reference
- Real-World Example: API Client
- Comparison with JavaScript
- Conclusion
Part VII: Rust and WebAssembly
Introduction to WebAssembly
- What is WebAssembly?
- Why Rust developers should care
- How WebAssembly Works
- When to use WebAssembly (and when not to)
- The Rust-to-Wasm Pipeline
- Tools Overview
- A Quick Example: Hello World in Wasm
- Performance Characteristics
- Next Steps
Building Wasm Modules with Rust
- Setting Up a Rust Wasm Project
- Writing Wasm Functions with wasm-bindgen
- Exposing Different Data Types to JavaScript
- Working with the DOM from Rust
- Calling JavaScript from Rust
- Handling Errors Across the Boundary
- Debugging Wasm Modules
- Building a Full Project: High-Performance Text Processing Module
- Performance Considerations
- Summary
Integrating Wasm into JavaScript Projects
- Loading Wasm in the Browser
- Loading Wasm in Node.js
- Bundler Integration
- Performance Profiling: When is Wasm Faster?
- Memory Management Across the Boundary
- Packaging and Distributing Wasm Modules
- Real-World Patterns and Best Practices
- Summary Comparison Table
Part VIII: Advanced Topics
Unsafe Rust
- Understanding Unsafe
- What You Can Do in Unsafe Blocks
- Raw Pointers
- Unsafe Functions and Methods
- Mutable Statics
- Unsafe Traits
- Union Fields
- When Unsafe is Justified
- Writing Safe Abstractions Over Unsafe Code
- Guidelines for Unsafe Code
- Unsafe in Practice
Macros
- What Are Macros and Why Does Rust Use Them So Heavily?
- Declarative Macros with macro_rules!
- Writing Your Own Declarative Macros
- Procedural Macros: An Overview
- Common Macro Patterns in the Ecosystem
- When to Use Macros vs. Generics vs. Traits
- Debugging Macros with cargo expand
- Comparing to JavaScript Metaprogramming
- Practical Advice: Most People Use Macros More Than They Write
- Summary
Performance and Optimisation
- Debug Mode vs Release Mode
- Release Profile Configuration
- Profiling: Understanding Where Time Goes
- Common Performance Patterns
- Compiler Optimisation Hints
- Binary Size Reduction
- Rust Ahead-of-Time vs JavaScript’s JIT Model
- Practical Optimisation Workflow
- When to Care About Performance
- Summary
Appendix A: Rust Cheat Sheet for JavaScript Developers
- Variables and Types
- Functions
- Control Flow
- Error Handling
- Strings
- Collections and Iterators
- Structs and Classes
- Modules and Imports
- Async
- Common Patterns
- Operator Quick Reference
Appendix B: Cargo Commands Reference
- Project Setup
- Building
- Dependencies
- Testing
- Code Quality
- Publishing
- Workspace Commands
- Useful Third-Party Cargo Subcommands
- Environment Variables
- Quick Comparison: npm vs Cargo
Appendix C: Recommended Crates
- Serialization and Data Formats
- Web and HTTP
- Async Runtime
- Database
- Command-Line Tools
- Error Handling
- Logging and Tracing
- Testing
- Date, Time, and UUIDs
- Cryptography and Security
- Configuration
- WebAssembly
- Concurrency and Parallelism
- File and Path Handling
- Regular Expressions
- Choosing Crates
Appendix D: Further Resources
- Official Resources
- Interactive Learning
- Intermediate and Advanced
- WebAssembly
- Community
- Blogs and Video
- Books
- Staying Current