about summary refs log tree commit diff
path: root/lang/zig/error-union.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lang/zig/error-union.zig')
-rw-r--r--lang/zig/error-union.zig115
1 files changed, 115 insertions, 0 deletions
diff --git a/lang/zig/error-union.zig b/lang/zig/error-union.zig
new file mode 100644
index 0000000..8ec75b2
--- /dev/null
+++ b/lang/zig/error-union.zig
@@ -0,0 +1,115 @@
+const std = @import("std");
+const maxInt = std.math.maxInt;
+const expect = std.testing.expect;
+
+fn charToDigit(c: u8) u8 {
+    return switch (c) {
+        '0'...'9' => c - '0',
+        'A'...'Z' => c - 'A' + 10,
+        'a'...'z' => c - 'a' + 10,
+        else => maxInt(u8),
+    };
+}
+
+const ParseError = error{ InvalidChar, Overflow };
+
+pub fn parseU64(buf: []const u8, radix: u8) ParseError!u64 {
+    var x: u64 = 0;
+
+    return for (buf) |c| {
+        const digit = charToDigit(c);
+        if (digit >= radix)
+            break error.InvalidChar;
+        // x *= radix
+        if (@mulWithOverflow(u64, x, radix, &x))
+            break error.Overflow;
+        // x += digit
+        if (@addWithOverflow(u64, x, digit, &x))
+            break error.Overflow;
+    } else x;
+}
+
+test "parse u64" {
+    const result = try parseU64("1234", 10);
+    expect(result == 1234);
+}
+
+fn doAThing(str: []u8) !void {
+    const number = parseU64(str, 10) catch |err| return err;
+    // The same as
+    const number = try parseU64(str, 10);
+}
+
+test "error switch" {
+    if (parseU64("42069", 10)) |number| {
+        expect(number == 42069);
+    } else |err| switch (err) {
+        error.Overflow => {
+            // handle overflow...
+        },
+        // we promise that InvalidChar won't happen
+        // (or crash in debug mode if it does)
+        error.InvalidChar => unreachable,
+    }
+}
+
+test "error union" {
+    var foo: anyerror!i32 = undefined;
+
+    // Use compile-time reflection to access the type of an error union:
+    comptime expect(@typeInfo(@TypeOf(foo)).ErrorUnion.payload == i32);
+    comptime expect(@typeInfo(@TypeOf(foo)).ErrorUnion.error_set == anyerror);
+
+    // Coerce values
+    foo = 1234;
+    foo = error.SomeError;
+}
+
+const A = error{
+    NotDir,
+
+    /// A doc comment
+    PathNotFound,
+};
+const B = error{
+    OutOfMemory,
+
+    /// B doc comment
+    PathNotFound,
+};
+
+const C = A || B;
+
+fn bar() C!void {
+    return error.NotDir;
+}
+
+test "merge error sets" {
+    if (bar()) {
+        @panic("unexpected");
+    } else |err| switch (err) {
+        error.OutOfMemory => @panic("unexpected"),
+        error.PathNotFound => @panic("unexpected"),
+        error.NotDir => {},
+    }
+}
+
+const Error = error { Overflow };
+
+// With an inferred error set
+pub fn add_inferred(comptime T: type, a: T, b: T) !T {
+    var answer: T = undefined;
+    return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
+}
+
+// With an explicit error set
+pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
+    var answer: T = undefined;
+    return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
+}
+
+test "inferred error set" {
+    if (add_inferred(u8, 255, 1)) |_| unreachable else |err| switch (err) {
+        error.Overflow => {}, // ok
+    }
+}