Chapter 24: Unfinished projects, continued
Introduces the final chapter’s three unfinished projects for readers to continue after finishing the book.
After this chapter you will be able to
- Axum Framework Choice. Justify the choice of Axum for this small project using the section’s framework comparison and compilation-unit counts.
- Axum routes and server. Explain how the example starts an Axum router, assigns paths to GET handlers, and serves it at a local address.
- Path extraction and handlers. Describe what Path<String> supplies to a handler and what kind of handler Axum requires here.
- Game state in handlers. Explain why the request handler cannot directly use the game in main(), and distinguish Axum’s .with_state() approach from the section’s static shortcut.
- Static game app setup. Explain why the app can be made into a static item: the methods used to set it up are const fn and do not require an allocation.
- Guess handling through static GAME. Trace a server guess through get_res_from_static(): it receives the String, locks the Mutex for mutable access to static GAME, calls take_guess(), and returns the resulting String as the route’s output.
- Building the server response String. Describe how the game’s output changes from println! calls to a returned String: use format! instead of printing, add information with push_str(), and return the completed String for the user to see.
- Mutable Axum game state. Explain why replacing the global static with Axum's .with_state() calls for Arc<Mutex> when the game needs to change values in the state struct.
- Separate games for players. Explain the problem with the server holding one game when several people visit, and describe either proposed way to give players separate games.
- Laser pointer project concept. Describe the proposed pet toy and explain what would make its moving dot interesting.
- Minimal app startup structure. Describe how the app struct, its update method, and eframe::run_native fit together, including the purpose of CreationContext.
- Screen coordinates and rectangles. Explain where the x- and y-axes begin and how Pos2 and Rect represent locations and screen areas in egui.
- Positions versus pixel offsets. Distinguish a Vec2 from a Pos2 using what their x and y values mean in this section.
- Event-independent app updates. Explain how the app can keep updating when the mouse is not hovering over it.
- Changing invisible target. Describe the section’s approach to making the pointer move in varied directions.
- Invisible target visualization. Explain that the laser pointer moves using an invisible random target and that drawing the target could help test and refine its movement.
- Current directory and paths. Explain what std::env::current_dir() returns and how PathBuf supports navigation through file and directory paths.
- Directory entries and information. Trace how std::fs::read_dir() leads from a directory to entries and the information available on each entry.
- Directory button navigation. Explain how the app uses buttons and a PathBuf to move into a directory or back to its parent.
- Clicked File Path Construction. Explain how to obtain a clicked file’s address without changing current_dir: build a PathBuf from the current directory and filename using an array or Vec.
- File Content Side Panel. Describe how the app decides when to display file content and how it keeps that display from changing size: store it in file_content, show a SidePanel when the string is nonempty, and use screen_rect() to set widths.
- Navigator interface gaps. Describe the navigator’s current interface limitations and suggest corresponding improvements: scrolling long file lists, hiding the right-hand panel, and saving edited file text while tracking changes.
What it builds on
- Const functions (chapter 16) · The earlier introduction to const functions
- Mutex (chapter 10) · The earlier introduction to Mutex
- Result (chapter 5) · Result represents an operation that may succeed or fail.
- Iterators (chapter 8) · An iterator supplies a sequence of items.
Section by section
Introduction
Introduces the final chapter’s three unfinished projects for readers to continue after finishing the book.
24.1 Web server word-guessing game
The section introduces a web-based word-guessing game and explains why the project will use Axum.
- Web-Based Guessing Game: Explain why this word-guessing project will run over a web server rather than on the command line.
Why it matters: The web-server setting is what makes this project different from a basic guessing game. - Axum Framework Choice: Justify the choice of Axum for this small project using the section’s framework comparison and compilation-unit counts.
Why it matters: This explains the practical reason behind the framework used for the project.
Key terms: word-guessing game, web server, command line, Rocket, Actix Web, Axum, Tokio, compilation units
24.1.1 Setup and first code
This section explains how to start a small local Axum server, connect GET routes to async handlers, extract a path value, and try the routes in a browser.
- Axum routes and server: Explain how the example starts an Axum router, assigns paths to GET handlers, and serves it at a local address.
Why it matters: These are the pieces that make the example’s URLs respond to requests. - Path extraction and handlers: Describe what Path<String> supplies to a handler and what kind of handler Axum requires here.
Why it matters: It explains how a value entered in a URL becomes input the game’s handler can use. - Local route checks: Describe how the section checks the first server and what those checks establish.
Why it matters: Trying the URLs verifies the starting server before the guessing game is added.
Key terms: axum::Router::new(), .route(), get, localhost, port, .serve(), extractors, Path<String>, async fn, async closures
24.1.2 Developing the code
The section develops the guessing game locally, then explains how an Axum request handler can access the game when the game and web server are joined.
- Local game development: Explain why the guessing game is run on the command line before it is joined to the web server.
Why it matters: Working on the game separately makes the later integration easier to reason about. - Game state in handlers: Explain why the request handler cannot directly use the game in main(), and distinguish Axum’s .with_state() approach from the section’s static shortcut.
Why it matters: The handler needs access to the game, and the choice of how to provide it affects testing as the project grows.
Key terms: guessing game, command line, web server, Path<String>, GameApp, .with_state(), static
24.1.3 Further development and cleanup
The section finishes adapting the word-guessing game for a web server by storing the app as a static item, passing guesses to it, and returning the game’s output as a String.
- Static game app setup: Explain why the app can be made into a static item: the methods used to set it up are const fn and do not require an allocation.
Why it matters: This explains why the game app can be kept as a static item for the server. - Guess handling through static GAME: Trace a server guess through get_res_from_static(): it receives the String, locks the Mutex for mutable access to static GAME, calls take_guess(), and returns the resulting String as the route’s output.
Why it matters: This connects an incoming server guess to the stored game and the response sent back. - Building the server response String: Describe how the game’s output changes from println! calls to a returned String: use format! instead of printing, add information with push_str(), and return the completed String for the user to see.
Why it matters: Returning the assembled text lets the server show the game’s result to the user.
Key terms: static item, const fn, allocation, get_res_from_static(), Mutex, static GAME, take_guess(), route, println!, format!
24.1.4 Over to you
Suggests ways to improve the finished web guessing game, especially its state handling and support for multiple players.
- Mutable Axum game state: Explain why replacing the global static with Axum's .with_state() calls for Arc<Mutex> when the game needs to change values in the state struct.
Why it matters: It explains the state-handling change suggested for the existing game. - Separate games for players: Explain the problem with the server holding one game when several people visit, and describe either proposed way to give players separate games.
Why it matters: It identifies why the current game needs a way to distinguish one player's play from another's.
Key terms: global static, .with_state(), Arc<Mutex>, single game, axum_sessions, session per user, random suffix
24.2 Laser pointer
Introduces a pet-oriented laser-pointer project: a moving red dot in an egui GUI, made more interesting by varying its direction and speed.
- Laser pointer project concept: Describe the proposed pet toy and explain what would make its moving dot interesting.
Why it matters: It gives you the purpose and basic behavior of the project before you build it.
Key terms: egui crate, GUI, laser pointer, random directions, random speeds
24.2.1 Setup and first code
Introduces the pieces needed to launch a minimal egui app and describes what its first window does.
- egui and eframe roles: Explain how egui draws widgets and why an egui app also uses eframe.
Why it matters: This separates drawing the interface from running the app. - Minimal app startup structure: Describe how the app struct, its update method, and eframe::run_native fit together, including the purpose of CreationContext.
Why it matters: These are the pieces needed to understand how the example becomes a running app. - First app launch and interaction: State what happens after running cargo run and what the displayed example lets the user do.
Why it matters: The visible window confirms that the minimal app has launched and responds to input.
Key terms: egui, eframe, widgets, closure, App trait, update(), eframe::run_native(), CreationContext, app struct, cargo run
24.2.2 Developing the code
This section explains egui’s screen coordinates and position types, then describes how the developing laser pointer behaves.
- Screen coordinates and rectangles: Explain where the x- and y-axes begin and how Pos2 and Rect represent locations and screen areas in egui.
Why it matters: These coordinates make the laser pointer’s location on the screen understandable. - Positions versus pixel offsets: Distinguish a Vec2 from a Pos2 using what their x and y values mean in this section.
Why it matters: The distinction keeps a screen location from being confused with an amount of movement. - Laser pointer behavior: Describe the laser pointer’s visible behavior when the mouse hovers over the screen and approaches it.
Why it matters: This describes the behavior the reader should expect from the project at this stage.
Key terms: Pos2, Rect, x-axis, y-axis, Vec2, laser pointer, mouse pointer
24.2.3 Further development and cleanup
The section explains how to make the laser pointer move erratically without requiring mouse-hover events.
- Event-independent app updates: Explain how the app can keep updating when the mouse is not hovering over it.
Why it matters: The pointer cannot move on its own if updates depend on mouse hover. - Changing invisible target: Describe the section’s approach to making the pointer move in varied directions.
Why it matters: A changing destination gives the pointer a simple basis for varied movement. - Randomly changing speeds: Describe the range of speeds planned for the laser pointer and why they vary.
Why it matters: Varying the pace helps make the pointer’s movement engaging rather than repetitive.
Key terms: request_repaint(), .update(), hover event, invisible target, random movement, Speed, CrazyFast
24.2.4 Over to you
Suggests ways to extend the laser pointer by visualizing its movement target and offering different movement styles.
- Invisible target visualization: Explain that the laser pointer moves using an invisible random target and that drawing the target could help test and refine its movement.
Why it matters: Seeing the target could make movement problems easier to spot. - Selectable movement styles: Explain why the user might be offered movement settings, using the section’s examples of a pointer that stays still and one that moves quickly.
Why it matters: Movement choices would let the app suit cats with different preferences.
Key terms: laser pointer, invisible random target, settings, types of movement
24.3 Directory and file navigator
Introduces the final unfinished project: a directory and file navigator that will use egui to build a more complete UI.
24.3.1 Setup and first code
Introduces standard-library types and methods for finding the current directory, navigating paths, and reading directory entries.
- Current directory and paths: Explain what std::env::current_dir() returns and how PathBuf supports navigation through file and directory paths.
Why it matters: A directory navigator needs a way to represent its location and move through paths. - Directory entries and information: Trace how std::fs::read_dir() leads from a directory to entries and the information available on each entry.
Why it matters: These types provide the directory contents that a file navigator needs to display. - Fallible filesystem operations: Explain why the section shows Result types when obtaining and reading directories.
Why it matters: Recognizing possible failure helps explain the Result types in the navigator's filesystem code.
Key terms: std::env::current_dir(), Result<PathBuf>, PathBuf, .push(), .pop(), std::fs::read_dir(), Result<ReadDir>, ReadDir, io::Result<DirEntry>, DirEntry
24.3.2 Developing the code
This section assembles a basic egui file navigator, shows how directory buttons change the current path, and identifies its remaining limitations.
- Directory button navigation: Explain how the app uses buttons and a PathBuf to move into a directory or back to its parent.
Why it matters: The PathBuf is what lets the buttons change which directory the app shows. - Entry appearance and behavior: Describe how the app displays directories and files, including what happens when each is clicked.
Why it matters: The colors help distinguish entries, but the display does not imply that file clicks work yet. - Remaining unwrap crash risk: Explain why this version of the app can still crash when a button is clicked.
Why it matters: The working navigation is not yet reliable when a system error occurs.
Key terms: PathBuf, .push(), .pop(), .., RichText, directories, files, .unwrap(), system error
24.3.3 Further development and cleanup
The section explains how to build a clicked file’s path without changing the current directory and how to show its contents in a stable side panel.
- Clicked File Path Construction: Explain how to obtain a clicked file’s address without changing current_dir: build a PathBuf from the current directory and filename using an array or Vec.
Why it matters: The app can locate the clicked file while keeping its navigation directory unchanged. - File Content Side Panel: Describe how the app decides when to display file content and how it keeps that display from changing size: store it in file_content, show a SidePanel when the string is nonempty, and use screen_rect() to set widths.
Why it matters: This lets the navigator show a file’s contents without an unnecessarily shifting display.
Key terms: current_dir, PathBuf, array, Vec, file_content, SidePanel, CentralPanel, TextEdit, screen_rect(), .min_width()
24.3.4 Over to you
The section identifies unfinished parts of the directory and file navigator and suggests ways to improve its interface, code structure, and error reporting.
- Navigator interface gaps: Describe the navigator’s current interface limitations and suggest corresponding improvements: scrolling long file lists, hiding the right-hand panel, and saving edited file text while tracking changes.
Why it matters: These gaps give you concrete directions for making the navigator easier and safer to use. - Code structure and error visibility: Explain why the section suggests moving deeply nested `if let` work into an app method and offering an optional display of error information.
Why it matters: These changes could make the app’s code easier to follow and its errors available to users who want them.
Key terms: scroll bar, panel on the right, typing area, whether text has been changed, if let, Result, DirectoryContent, Dir, File, Other
24.4 Summary
Concepts explained in this chapter
- AxumAxum is a Rust web framework for building HTTP services with routing, request extraction, and asynchronous handlers.
- serverA server is a program that listens for client requests and provides responses over a network.
- HTTP GETHTTP GET is a request method for retrieving a resource or representation from a server.
- async/awaitasync is a Rust language construct for defining computations that produce futures and can suspend while awaiting asynchronous results.
- unwrapunwrap is a Rust method that extracts a contained success or present value and panics when the value represents failure or absence.
- result typeResult is a Rust enum type representing either a successful value or an error from an operation that may fail.
- RustRust is a compiled systems programming language emphasizing memory safety, performance, and explicit control over low-level data representation.
- futureA Future is a Rust abstraction representing an asynchronous computation whose result may become available later and which can be polled for readiness.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
