Type Casting
Rust never converts types implicitly. Every conversion must be written explicitly with the as keyword. This makes intent visible and prevents silent bugs from unexpected coercion.
Basic syntax
#![allow(unused)] fn main() { let x: u16 = 0x0A; let as_usize = x as usize; let as_u8 = x as u8; }
Why array indexing needs usize
Array indices must be usize — the platform-native integer for memory sizes. The compiler rejects any other type:
#![allow(unused)] fn main() { let x: u16 = 5; self.v[x] // ERROR: expected usize, found u16 self.v[x as usize] // OK }
Casting to a smaller type: truncation
When casting to a smaller type, the upper bits are discarded — only the lower bits remain:
#![allow(unused)] fn main() { let value: u16 = 0x6A42; let low = value as u8; // keeps only the lower 8 bits → 0x42 }
0x6A42 = 0110 1010 | 0100 0010
─────────
as u8 → 0x42
This is exactly what happens when extracting the NN byte from an opcode:
#![allow(unused)] fn main() { let nn = (opcode & 0x00FF) as u8; }
The mask isolates the lower byte; the cast keeps it as u8.
Casting to a larger type: zero extension
Zeros are added to the left:
#![allow(unused)] fn main() { let value: u8 = 0x42; let extended = value as u16; // 0x0042 }
This is what happens during fetch when combining two bytes into a 16-bit opcode:
#![allow(unused)] fn main() { let high = ram[pc] as u16; // 0xAB → 0x00AB let low = ram[pc + 1] as u16; // 0xCD → 0x00CD let opcode = (high << 8) | low; // 0xABCD }
Without casting to u16 before shifting, the shift would overflow the 8-bit boundary.
Summary
| Conversion | What happens |
|---|---|
| small → large | zeros added on the left |
| large → small | upper bits discarded |
| any → usize | required for array indexing |
In the emulator: Type casting appears in nearly every opcode. The register index extracted from an opcode (
u16) must be cast tousizebefore indexing intoself.v[x]. Values loaded into registers must be cast tou8. See the Bitwise Operations chapter for the masking operations that precede most casts, and The First Opcode: JP for the full fetch cycle where both casting and shifting are needed together.