Purpose of the `src` Directory in Brush: Rust Workspace Structure Explained

The src directories in Brush contain the root modules and implementation code for each crate in the workspace, following standard Cargo conventions to organize entry points, sub-modules, and compilation units.

The Brush repository (ArthurBrussee/brush) implements 3D Gaussian splatting as a Rust mono-repo workspace. Understanding the purpose of the src directory in Brush reveals how the project organizes its multi-crate architecture into independent, compilable units that handle everything from dataset loading to training and rendering.

Standard Rust Module Organization

Each src folder serves as the root of a crate's module hierarchy, containing the entry point files that the Rust compiler uses to begin compilation.

Root Module Entry Points

Every crate in Brush contains either lib.rs (for library crates) or main.rs (for binary crates) directly inside its src directory. These files act as the crate root, declaring public APIs and module hierarchies. For example, crates/brush-dataset/src/lib.rs re-exports the public interface:

pub mod config;
pub mod scene;
pub mod scene_loader;

mod formats;
pub use formats::{DatasetLoadResult, load_dataset};

This structure allows other crates to access functionality through clean import paths while keeping implementation details organized in sub-modules.

Sub-Module Discovery

The compiler follows mod statements from the root file to discover additional source files. In crates/brush-dataset/src/, the module tree extends into specialized files like scene.rs and scene_loader.rs, plus subdirectories such as formats/ containing mod.rs, nerfstudio.rs, and colmap.rs. This organization isolates format-specific parsing logic while maintaining a unified public API.

Workspace Structure and Compilation

Brush employs a workspace configuration that treats each src directory as an independent compilation unit while maintaining cross-crate dependencies.

Mono-Repo Layout

The top-level Cargo.toml defines a workspace whose members array points to crate directories under crates/. Each member directory contains its own Cargo.toml and src/ folder, creating clear boundaries between concerns like data loading, training logic, and rendering backends.

Separate Compilation Units

Because each crate maintains its own src directory, Cargo can build them independently, cache artifacts, and emit separate library files (.rlllib or .so). This separation means changes to crates/brush-train/src/train.rs do not force recompilation of crates/brush-dataset/src/lib.rs, significantly accelerating development cycles in this multi-crate project.

Key Crates and Their src Contents

The Brush workspace organizes functionality across several specialized crates, each with distinct responsibilities reflected in their src structure.

brush-dataset

Located at crates/brush-dataset/src/, this crate handles 3D scene data ingestion. The lib.rs file defines the Dataset struct and re-exports loading functions, while src/formats/mod.rs delegates to format-specific implementations like nerfstudio.rs and colmap.rs.

brush-train

The training logic resides in crates/brush-train/src/, containing train.rs (implementing the train function) and config.rs (defining the Config struct). These files implement the optimization loop for Gaussian splatting parameters.

Additional Crates

Practical Implementation Examples

The src directories contain the actual implementations consumed by Brush applications. Here are examples demonstrating how code in these directories is used.

Loading a Dataset

This example uses the brush-dataset crate to load training data. The load_dataset function is defined in crates/brush-dataset/src/formats/mod.rs:

use brush_dataset::load_dataset;
use brush_dataset::Dataset;

fn main() -> anyhow::Result<()> {
    // Load a NeRFStudio dataset from a folder
    let dataset: Dataset = load_dataset("my/nerfstudio_scene")?;
    println!("Loaded {} training views", dataset.train.views.len());

    // Estimate an up-direction from the camera poses
    let up = dataset.estimate_up();
    println!("Estimated up vector: {up:?}");
    Ok(())
}

Training a Model

The training entry point resides in crates/brush-train/src/train.rs, while configuration parsing uses crates/brush-train/src/config.rs:

use brush_train::{train, Config};

fn main() -> anyhow::Result<()> {
    // Parse a TOML config file
    let cfg: Config = toml::from_str(&std::fs::read_to_string("train.toml")?)?;

    // Run the training loop
    train(cfg)?;
    Ok(())
}

Summary

  • The src directory in each Brush crate follows Cargo's standard layout, containing lib.rs or main.rs as the compilation entry point.
  • Sub-modules are organized under src/ using files and folders that mirror Rust's module hierarchy, as seen in crates/brush-dataset/src/formats/.
  • Workspace configuration enables independent compilation of each src tree, caching artifacts for faster builds.
  • Implementation files like train.rs, scene.rs, and render_bwd.rs contain the actual logic exposed through public APIs defined in their respective lib.rs files.

Frequently Asked Questions

Why does each crate in Brush have its own src directory?

Each crate maintains an independent src directory because Brush is organized as a Cargo workspace. This separation allows each crate to compile as a distinct unit with its own dependencies and artifact output. According to the Brush source code, the workspace root Cargo.toml references these crates under crates/, and each follows the standard Rust convention where src/ contains the implementation code.

What is the difference between lib.rs and main.rs in Brush's src folders?

Library crates like brush-dataset and brush-train use src/lib.rs to expose public APIs that other crates can import, while binary crates use src/main.rs to define executable entry points. In Brush, most crates are libraries (lib.rs) that export functionality such as load_dataset or train, allowing the application logic to compose these capabilities while keeping the source organized in src/ directories.

How does the src directory structure affect compilation speed in Brush?

The src directories enable faster incremental compilation because Cargo treats each crate as a separate compilation unit. When you modify crates/brush-train/src/config.rs, only that crate and its dependents rebuild, while crates/brush-dataset/src/ and other crates remain cached. This architectural boundary prevents unnecessary recompilation across the mono-repo workspace.

Where are tests located in relation to the src directory in Brush?

Unit tests typically reside within the src tree using #[cfg(test)] modules inside source files like crates/brush-dataset/src/lib.rs, or in separate test files imported via mod statements. Integration tests live in a top-level tests/ folder adjacent to src/, while the source code under src/ may contain doc tests and example functions compiled only when running cargo test or cargo run --example.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →