// std.maybe — typed-uninitialized storage wrapper. // // `Maybe(T)` is the jam analog of Rust's `std::mem::MaybeUninit`: a // same-sized-as-T wrapper whose contained bytes may not yet be a valid T // (uninitialised, partially init, freshly freed). The type system marks // it as not-yet-readable — to extract a real T, call `assumeInit()`, // asserting that the bytes ARE a valid T and taking responsibility for // the safety contract. Reading the storage as a T while it isn't one is // undefined behaviour. // // Distinct from `std/option`: // - `Option(T)`: a sum type — None or Some(T). Has a discriminant. // Models "may or may not have a value" at runtime. // - `Maybe(T)`: a same-sized storage wrapper — bytes either ARE a // valid T or aren't yet. No discriminant. Models the // "initialisation gap" between alloc and use. // // Use cases: // - Two-stage construction: declare a slot, fill it, call assumeInit. // - TODO: a `Vec(Maybe(T))` fast-path (allocate-uninit + per-slot // write + `Maybe(T).assumeInitVec(v) -> Vec(T)`) would mirror Rust's // `Box::new_uninit_slice(n)` → fill → `.assume_init()`. Needs a // `Vec.allocUninit(n)` constructor first. pub fn Maybe(T: type) type { return struct { // T-sized storage slot. Layout-identical to T at runtime — the // wrapper is a pure type-system marker. The `value` field is // internal; callers should never read it directly (they should // call `assumeInit()`). value: T, // Wrap an already-initialised T in a Maybe slot. pub fn init(v: T) Self { return Self { value: v }; } // Read the contained T. Caller asserts the backing storage has // been written with a valid T — UB if not. jam has no init- // tracking; this is your contract. pub fn assumeInit(self: Self) T { return self.value; } }; }