# How Does Rustlings Embed Official Exercises? A Deep Dive into Compile-Time Bundling

> Discover how Rustlings embeds official exercises using compile-time macros. Learn about its innovative approach to bundling exercises for seamless learning within the Rust ecosystem.

- Repository: [The Rust Programming Language/rustlings](https://github.com/rust-lang/rustlings)
- Tags: deep-dive
- Published: 2026-03-05

---

**Rustlings embeds its official exercises using a compile-time procedural macro (`rustlings_macros::include_files!`) that reads [`info.toml`](https://github.com/rust-lang/rustlings/blob/main/info.toml) and generates `include_bytes!` calls for every exercise file, solution, and README, storing them in a static `EmbeddedFiles` struct that is written to disk when users run `rustlings init`.**

The [rust-lang/rustlings](https://github.com/rust-lang/rustlings) repository distributes a self-contained CLI tool that teaches Rust through hands-on exercises. Rather than requiring users to download exercise files separately or clone the entire repository, Rustlings bakes all 100+ exercises directly into the compiled binary. This article explains the mechanical process of how the project achieves this embedding through procedural macros and static byte arrays.

## The Compile-Time Embedding Pipeline

The embedding mechanism operates in two distinct phases: a procedural macro that runs during compilation to bundle files, and a static data structure that holds those files for runtime extraction.

### Stage 1: The `include_files!` Procedural Macro

Located in [[`rustlings-macros/src/lib.rs`](https://github.com/rust-lang/rustlings/blob/main/rustlings-macros/src/lib.rs)](https://github.com/rust-lang/rustlings/blob/main/rustlings-macros/src/lib.rs), the `include_files!` macro executes entirely at build time. It performs the following operations:

1. **Loads the manifest**: Reads the repository's [`info.toml`](https://github.com/rust-lang/rustlings/blob/main/info.toml) using `include_bytes!("../info.toml")`, explicitly filtering out carriage return characters (`\r`) to normalize line endings across platforms.
2. **Parses exercise metadata**: Deserializes the TOML content to extract exercise names and directory structures.
3. **Generates inclusion tokens**: For each exercise, constructs file paths (e.g., [`../exercises/intro/intro1.rs`](https://github.com/rust-lang/rustlings/blob/main/../exercises/intro/intro1.rs), [`../solutions/intro/intro1.rs`](https://github.com/rust-lang/rustlings/blob/main/../solutions/intro/intro1.rs)) and emits `include_bytes!` macro calls wrapped in a static initialization.

The macro expands into code resembling this pattern:

```rust
static EMBEDDED_FILES: EmbeddedFiles = EmbeddedFiles {
    info_file: "...", // Parsed TOML content as string
    exercise_files: &[
        ExerciseFiles {
            exercise: include_bytes!("../exercises/intro/intro1.rs"),
            solution: include_bytes!("../solutions/intro/intro1.rs"),
            dir_ind: 0,
        },
        // ... additional exercises
    ],
    exercise_dirs: &[
        ExerciseDir {
            name: "intro",
            readme: include_bytes!("../exercises/intro/README.md"),
        },
        // ... additional directories
    ],
};

```

### Stage 2: The `EmbeddedFiles` Static Structure

The data structures that store these embedded bytes are defined in [[`src/embedded.rs`](https://github.com/rust-lang/rustlings/blob/main/src/embedded.rs)](https://github.com/rust-lang/rustlings/blob/main/src/embedded.rs). The **three core types** work together to organize the embedded content:

- **`EmbeddedFiles`**: The top-level container holding the [`info.toml`](https://github.com/rust-lang/rustlings/blob/main/info.toml) string, an array of `ExerciseFiles`, and an array of `ExerciseDir` entries.
- **`ExerciseFiles`**: Contains three fields—`exercise` (the source bytes), `solution` (the solution bytes), and `dir_ind` (an index pointing to the directory metadata).
- **`ExerciseDir`**: Stores the directory name and its associated [`README.md`](https://github.com/rust-lang/rustlings/blob/main/README.md) bytes.

By using `include_bytes!`, Rust stores the exact file contents as static byte slices (`&'static [u8]`) within the binary's read-only data segment, ensuring zero runtime I/O overhead until extraction is requested.

## Runtime Extraction and Initialization

When a user executes `rustlings init`, the application invokes the extraction logic to recreate the exercise tree on the local filesystem.

### The `init_exercises_dir` Method

As implemented in [[`src/embedded.rs`](https://github.com/rust-lang/rustlings/blob/main/src/embedded.rs)](https://github.com/rust-lang/rustlings/blob/main/src/embedded.rs), the `init_exercises_dir` method handles the physical write operations:

1. **Creates the root directory**: Generates the `exercises/` folder and writes the top-level [`README.md`](https://github.com/rust-lang/rustlings/blob/main/README.md).
2. **Reconstructs subdirectories**: Iterates through `exercise_dirs` to create category folders (e.g., `exercises/intro/`, `exercises/error_handling/`) and writes their respective README files.
3. **Writes exercise files**: Matches exercise metadata from [`info.toml`](https://github.com/rust-lang/rustlings/blob/main/info.toml) with the embedded byte arrays in `exercise_files`, reconstructing paths like [`exercises/intro/intro1.rs`](https://github.com/rust-lang/rustlings/blob/main/exercises/intro/intro1.rs) and writing the bytes using `fs::write`.

This method is invoked from [[`src/init.rs`](https://github.com/rust-lang/rustlings/blob/main/src/init.rs)](https://github.com/rust-lang/rustlings/blob/main/src/init.rs#L124-L136) during the initialization command:

```rust
// From src/init.rs
EMBEDDED_FILES.init_exercises_dir(&exercises)?;

```

The extraction process treats the embedded bytes as immutable templates, ensuring that every user receives the identical, official exercise set regardless of their platform or network connectivity.

## Why Compile-Time Embedding Matters

This architecture provides several distinct advantages for a CLI learning tool:

- **Self-contained distribution**: The single binary artifact contains everything needed to bootstrap the learning environment, eliminating dependency on Git submodules or network fetching.
- **Version consistency**: The exercises are permanently bound to the specific binary version; a Rustlings v6.0.0 binary always contains the v6.0.0 exercise set, preventing drift between tool and content.
- **Cross-platform integrity**: By filtering line endings during macro execution and using byte-level embedding, the tool ensures that exercise files are written with the host platform's native line endings regardless of where the binary was compiled.

## Summary

- **`rustlings_macros::include_files!`** in [`rustlings-macros/src/lib.rs`](https://github.com/rust-lang/rustlings/blob/main/rustlings-macros/src/lib.rs) reads [`info.toml`](https://github.com/rust-lang/rustlings/blob/main/info.toml) at compile time and generates `include_bytes!` calls for every exercise source, solution, and documentation file.
- **`EmbeddedFiles`**, defined in [`src/embedded.rs`](https://github.com/rust-lang/rustlings/blob/main/src/embedded.rs), stores all embedded content as static byte arrays organized by directory and exercise type.
- The **`init_exercises_dir`** method extracts these embedded bytes to the filesystem, recreating the complete `exercises/` hierarchy when users run `rustlings init`.
- **[`src/init.rs`](https://github.com/rust-lang/rustlings/blob/main/src/init.rs)** orchestrates the extraction process by calling the initialization method on the static singleton.
- This compile-time embedding strategy ensures Rustlings remains a portable, offline-capable tool with guaranteed version alignment between the CLI and its exercise curriculum.

## Frequently Asked Questions

### Does Rustlings require an internet connection to download exercises?

No. Because all exercises are embedded directly into the binary using `include_bytes!`, Rustlings operates entirely offline after installation. When you run `rustlings init`, the CLI simply writes the pre-bundled files from the `EmbeddedFiles` static struct to your local filesystem without making any network requests.

### What file determines which exercises get embedded into the binary?

The [[`info.toml`](https://github.com/rust-lang/rustlings/blob/main/info.toml)](https://github.com/rust-lang/rustlings/blob/main/info.toml) file in the repository root serves as the manifest. The `include_files!` macro parses this TOML file during the build process to determine the directory structure and relative paths for every exercise, solution, and README that must be embedded.

### How does the embedding mechanism handle Windows vs. Unix line endings?

The macro in [[`rustlings-macros/src/lib.rs`](https://github.com/rust-lang/rustlings/blob/main/rustlings-macros/src/lib.rs)](https://github.com/rust-lang/rustlings/blob/main/rustlings-macros/src/lib.rs) explicitly filters out carriage return characters (`\r`) when reading [`info.toml`](https://github.com/rust-lang/rustlings/blob/main/info.toml) by iterating through the `include_bytes!` result and removing them before UTF-8 conversion. This ensures consistent TOML parsing across all platforms during compilation, while the embedded exercise files are stored verbatim and written exactly as they exist in the source tree.

### Can I modify the embedded exercises and have Rustlings use my customized versions?

No, the embedded files are immutable and fixed at compile time. However, once you run `rustlings init`, the embedded bytes are written to your working directory as regular source files, which you are intended to edit to complete the exercises. If you delete your local `exercises/` folder and run `init` again, the original embedded versions from the binary will be restored.