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 } }