import "./core.zc" import "./option.zc" /// The standard error-handling type: either `Ok(v)` or `Err(message)`. struct Result { is_ok: bool; val: T; err: char*; } impl Result { /// Wraps a value in an `Ok` result. fn Ok(v: T) -> Result { return Result { is_ok: true, val: v, err: NULL }; } /// Creates an `Err` result with an error message. fn Err(e: char*) -> Result { let r: Result; r.is_ok = false; r.err = e; memset(&r.val, 0, sizeof(T)); return r; } /// Returns `true` when the result is `Ok`. fn is_ok(self) -> bool { return self.is_ok; } /// Returns `true` when the result is `Err`. fn is_err(self) -> bool { return !self.is_ok; } /// Zeroes out the internal value without freeing memory. fn forget(self) { memset(&self.val, 0, sizeof(T)); } /// Returns the `Ok` value. Panics with the error when `Err`. fn unwrap(self) -> T { if (!self.is_ok) { !"Panic: unwrap called on Err: {self.err}"; exit(1); } let v = self.val; // Moved value return v; } /// Returns a pointer to the `Ok` value. Panics when `Err`. fn unwrap_ref(self) -> T* { if (!self.is_ok) { !"Panic: unwrap_ref called on Err: {self.err}"; exit(1); } return &self.val; } /// Returns the value, or panics with `msg` and the error when `Err`. fn expect(self, msg: char*) -> T { if (!self.is_ok) { !"Panic: {msg}: {self.err}"; exit(1); } return self.val; } // Returns the contained value, or `def_val` when Err. /// Returns the contained value, or `def_val` when `Err`. fn unwrap_or(self, def_val: T) -> T { if (self.is_ok) { return self.val; } return def_val; } // Returns the contained value, or the result of `f` when Err. /// Returns the contained value, or the result of `f` when `Err`. fn unwrap_or_else(self, f: fn() -> T) -> T { if (self.is_ok) { return self.val; } return f(); } // Converts to an Option holding the error, when Err. /// Converts to an `Option` holding the error message, when `Err`. fn err(self) -> Option { if (!self.is_ok) { return Option::Some(self.err); } return Option::None(); } // Applies `f` to the error, leaving the value untouched. /// Applies `f` to the error message, leaving the value untouched. fn map_err(self, f: fn(char*) -> char*) -> Result { if (self.is_ok) { return self; } return Result::Err(f(self.err)); } // Returns true when Ok and `f` accepts the contained value. /// Returns `true` when `Ok` and `f` accepts the contained value. fn is_ok_and(self, f: fn(T) -> bool) -> bool { return self.is_ok && f(self.val); } // Returns true when Err and `f` accepts the error message. /// Returns `true` when `Err` and `f` accepts the error message. fn is_err_and(self, f: fn(char*) -> bool) -> bool { return !self.is_ok && f(self.err); } // Panics with `msg` and the value when Ok, otherwise returns the error. /// Returns the error message, or panics with `msg` when `Ok`. fn expect_err(self, msg: char*) -> char* { if (self.is_ok) { !"Panic: {msg}: expected Err, got Ok"; exit(1); } return self.err; } // Converts to an Option, mapping Ok to Some and discarding the error. /// Converts to an `Option`, mapping `Ok` to `Some` and discarding the error. fn ok(self) -> Option { if (self.is_ok) { return Option::Some(self.val); } return Option::None(); } }