A newtype can make invalid raw values hard to pass around by validating them once at construction.

Program

Play the program to choose a raw port and fall back when validation rejects it.

raw
newtype_port_validation.rs
Replay: real traced execution (multi-file project)
#[derive(Clone, Copy)]
struct Port(u16);

impl Port {
    fn new(value: u32) -> Option<Self> {
        if (1..=65535).contains(&value) {
            Some(Self(value as u16))
        } else {
            None
        }
    }
}

fn main() {
    let raw = 8080;
    let port = Port::new(raw).unwrap_or(Port(80));
    println!("port={}", port.0);
}
#[derive(Clone, Copy)]
struct Port(u16);

impl Port {
    fn new(value: u32) -> Option<Self> {
        if (1..=65535).contains(&value) {
            Some(Self(value as u16))
        } else {
            None
        }
    }
}

fn main() {
    let raw = 0;
    let port = Port::new(raw).unwrap_or(Port(80));
    println!("port={}", port.0);
}
#[derive(Clone, Copy)]
struct Port(u16);

impl Port {
    fn new(value: u32) -> Option<Self> {
        if (1..=65535).contains(&value) {
            Some(Self(value as u16))
        } else {
            None
        }
    }
}

fn main() {
    let raw = 70000;
    let port = Port::new(raw).unwrap_or(Port(80));
    println!("port={}", port.0);
}
  1. raw ← 8080

    14fn main() {15    let ra→ 8080w = 8080; //@raw=8080, 0, 7000016    let port = Port::new(ra8080w).unwrap_or(Port(80));17    println!("port={}", port.0);
  2. port ← (empty)

    15    let raw = 8080; //@raw=8080, 0, 7000016    let por→ (empty)t = Port::new(ra8080w).unwrap_or(Port(80));17    println!("port={}", port.0);18}
    outputport=8080
  1. raw ← 0

    14fn main() {15    let ra→ 0w = 0;16    let port = Port::new(ra0w).unwrap_or(Port(80));17    println!("port={}", port.0);
  2. port ← (empty)

    15    let raw = 0;16    let por→ (empty)t = Port::new(ra0w).unwrap_or(Port(80));17    println!("port={}", port.0);18}
    outputport=80
  1. raw ← 70000

    14fn main() {15    let ra→ 70000w = 70000;16    let port = Port::new(ra70000w).unwrap_or(Port(80));17    println!("port={}", port.0);
  2. port ← (empty)

    15    let raw = 70000;16    let por→ (empty)t = Port::new(ra70000w).unwrap_or(Port(80));17    println!("port={}", port.0);18}
    outputport=80
newtype `Port` wraps `u16` so APIs can ask for a validated port instead of a raw number.
constructor `Port::new` returns `Option<Port>` to make invalid input explicit.
fallback `unwrap_or` chooses a default only after validation has failed.