1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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
}
}
|