From: Brendan Hansen Date: Sun, 26 Feb 2023 03:23:08 +0000 (-0600) Subject: starting experimentation with Result type X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=e47c7d3d82f92e61b231379c50b84e2bb261f0d6;p=onyx.git starting experimentation with Result type --- diff --git a/core/container/result.onyx b/core/container/result.onyx new file mode 100644 index 00000000..2a14f62e --- /dev/null +++ b/core/container/result.onyx @@ -0,0 +1,90 @@ +package core + +use core {Optional, conv} + +@conv.Custom_Format.{ #solidify format {T=Ok_Type, E=Err_Type} } +Result :: struct (Ok_Type: type_expr, Err_Type: type_expr) { + status: Result_Status; + __data: Result_Data(Ok_Type, Err_Type); +} + +Result_Status :: enum { + Ok :: 1; + Err :: 2; +} + +#local +Result_Data :: struct (T: type_expr, E: type_expr) { + value: T; + error: E; +} + + +#inject Result { + // Ok :: macro (x: $T) do return .{ .Ok, .{ value = x } }; + // Err :: macro (x: $T) do return .{ .Err, .{ error = x } }; + + is_ok :: (r: #Self) => r.status == .Ok; + + is_err :: (r: #Self) => !r.status == .Err; + + ok :: (r: #Self) -> Optional(r.Ok_Type) { + if r.status == .Ok do return Optional.make(r.__data.value); + return .{}; + } + + err :: (r: #Self) -> Optional(r.Err_Type) { + if r.status == .Err do return Optional.make(r.__data.error); + return .{}; + } + + unwrap :: (r: #Self) -> r.Ok_Type { + if r.status == .Err { + msg := tprintf("Unwrapping Result with error '{}'.", r.__data.error); + assert(false, msg); + return .{}; + } + + return r.__data.value; + } + + unwrap_or_default :: (r: #Self) -> r.Ok_Type { + if r.status == .Err do return .{}; + + return r.__data.value; + } + + transform :: (r: #Self, f: (r.Ok_Type) -> $R) => { + if r.status == .Err do return r; + return .{ .Ok, .{ value = f(r.__data.value) } }; + } + + and_then :: (r: #Self, f: (r.Ok_Type) -> Result($R, r.Err_Type)) -> Result(R, r.Err_Type) { + if r.status == .Err do return r; + return .{ .Ok, .{ value = f(r.__data.value) } }; + } + + or_else :: (r: Result, generate: () -> typeof r) => { + if r.status == .Ok do return r; + return .{}; + } + + forward_err :: macro (r: Result($T, $E)) -> T { + res := r; + if res.status == .Ok do return res.__data.value; + + return #from_enclosing .{ .Err, .{ error = res.__data.error } }; + } + + format :: (o: ^conv.Format_Output, format: ^conv.Format, res: ^Result($T, $E)) { + if res.status == .Ok { + conv.format(o, "{}({\"})", res.status, res.__data.value); + } else { + conv.format(o, "{}({\"})", res.status, res.__data.error); + } + } +} + +#overload +__implicit_bool_cast :: macro (r: Result($O, $E)) => r.status == .Ok; +