Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Types and Traits

Use types to enforce invariants (rust-type-invariants)

Leverage the type system to make illegal states unrepresentable.

Define newtypes to encode domain constraints.

// Good — a `Nice` value is guaranteed to be valid
pub struct Nice(NiceValue);
type NiceValue = RangedI8<-20, 19>;

// Bad — `i8` admits invalid values for nice levels
pub type Nice = i8;

Prefer enums over bare integers and boolean flags.

// Good — access mode is constrained by the enum
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AccessMode {
    O_RDONLY = 0,
    O_WRONLY = 1,
    O_RDWR = 2,
}

// Bad — `u8` admits invalid values
pub type AccessMode = u8;

Encode invariants in generic parameters where needed.

impl IoMem<Sensitive> {
    // Good — only unsafe code can write to sensitive MMIO
    pub unsafe fn write_u32(&self, offset: usize, new_val: u32) { /* .. */ }
}

impl IoMem<Insensitive> {
    // Good — safe code can write to insensitive MMIO
    pub fn write_u32(&self, offset: usize, new_val: u32) { /* .. */ }
}

pub enum Sensitive {}
pub enum Insensitive {}

Asterinas uses this pattern widely, for example with newtypes such as CpuId and AlignedUsize<const N: u16>.

See also: PR #2265 and #2514.

Prefer enum over trait objects for closed sets (enum-over-dyn)

When the set of variants is known and closed, an enum is often preferable to Box<dyn Trait> for both performance and pattern-matching expressiveness.

// Good — closed set modeled as an enum
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TermStatus {
    Exited(u8),
    Killed(SigNum),
}

Encapsulate fields behind getters (getter-encapsulation)

Do not make fields public when a simple getter method would do. A getter preserves naming flexibility and leaves room for future invariants.

// Good — field is private, accessed via getter
pub struct Vma {
    perms: VmPerms,
}

impl Vma {
    pub fn perms(&self) -> VmPerms {
        self.perms
    }
}

// Bad — public field exposes representation
pub struct Vma {
    pub perms: VmPerms,
}