From ee9b8fc921f48dc893808e1c9dbfbef321aa362c Mon Sep 17 00:00:00 2001 From: Nguyễn Gia Phong Date: Sun, 28 Feb 2021 17:18:03 +0700 Subject: [lang/zig] Learn some Zig --- lang/zig/error-union.zig | 115 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 lang/zig/error-union.zig (limited to 'lang/zig/error-union.zig') 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 + } +} -- cgit 1.4.1