Modules
As the emulator grows, keeping everything in main.rs becomes unmanageable. Modules let you split code into files while controlling what is visible from the outside.
Declaring a module
In main.rs:
#![allow(unused)] fn main() { mod cpu; mod memory; mod display; }
mod cpu; tells the compiler: "find the module named cpu in the filesystem." The compiler looks in two places:
| Declaration | Compiler looks for |
|---|---|
mod cpu; | src/cpu.rs or src/cpu/mod.rs |
mod memory; | src/memory.rs or src/memory/mod.rs |
Both forms are equivalent. The folder form (cpu/mod.rs) is preferred when the module has submodules — like when we add a tests.rs file inside the cpu/ directory.
Submodules and test files
When src/cpu/mod.rs contains:
#![allow(unused)] fn main() { #[cfg(test)] mod tests; }
The compiler looks for src/cpu/tests.rs. The full path of this module is cpu::tests. This is how we keep test code out of the main module without losing access to the internals being tested.
Bringing items into scope
#![allow(unused)] fn main() { // full path — always works let cpu = cpu::Cpu::new(); // use — brings an item into the local scope use cpu::Cpu; let cpu = Cpu::new(); }
super in test files
Inside src/cpu/tests.rs:
#![allow(unused)] fn main() { use super::*; // import everything from cpu/mod.rs }
super refers to the parent module. This gives the test file access to Cpu, execute(), and anything else in cpu/mod.rs — without needing to know the full path crate::cpu::Cpu.
Visibility rules
Items are private by default:
#![allow(unused)] fn main() { pub struct Cpu { ... } // visible everywhere pub fn step(&mut self) { } // visible everywhere fn execute(&mut self) { } // private — only inside cpu/mod.rs }
A child module can always see its parent's private items. The reverse is not true.
The module tree for this project
crate (main.rs)
├── cpu (src/cpu/mod.rs)
│ └── tests (src/cpu/tests.rs)
├── memory (src/memory/mod.rs)
│ └── tests (src/memory/tests.rs)
└── display (src/display/mod.rs)
Related Rust concepts: Module visibility uses
pubwhich is introduced in Slices and Ranges. The#[cfg(test)]attribute that gates the test module is covered in Attributes and cfg.