Add Zig Error Handling Example
This commit is contained in:
parent
f5517fd441
commit
e394029a24
2
zig-error-handling/.gitignore
vendored
Normal file
2
zig-error-handling/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
zig-out/
|
||||||
|
.zig-cache/
|
26
zig-error-handling/build.zig
Normal file
26
zig-error-handling/build.zig
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "zig-error-handling",
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = b.host,
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
const run_exe = b.addRunArtifact(exe);
|
||||||
|
const run_step = b.step("run", "Run the application");
|
||||||
|
|
||||||
|
run_step.dependOn(&run_exe.step);
|
||||||
|
|
||||||
|
const unit_tests = b.addTest(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = b.host,
|
||||||
|
});
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||||
|
|
||||||
|
test_step.dependOn(&run_unit_tests.step);
|
||||||
|
}
|
77
zig-error-handling/src/main.zig
Normal file
77
zig-error-handling/src/main.zig
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const AddNumbersError = error{
|
||||||
|
InequalLengths,
|
||||||
|
GuardOverflow,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This functions performs saturated addition of two u8 (unsigned 8-bit integer) slices,
|
||||||
|
// but if any addition result is more than guard then it returns GuardOverflow error instead.
|
||||||
|
pub fn numbers_magic(allocator: std.mem.Allocator, a: []const u8, b: []const u8, guard: u8) ![]u8 {
|
||||||
|
if (a.len != b.len) {
|
||||||
|
return error.InequalLengths;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = try allocator.alloc(u8, a.len);
|
||||||
|
// errdefer is called only when error is returned, so when there is no error normal result will
|
||||||
|
// be returned to the caller (it should not be deallocated in every case, because it would result
|
||||||
|
// in segmentation fault)
|
||||||
|
errdefer allocator.free(result);
|
||||||
|
|
||||||
|
for (0.., result) |idx, _| {
|
||||||
|
// Saturated addition to avoid integer overflow panic.
|
||||||
|
result[idx] = a[idx] +| b[idx];
|
||||||
|
|
||||||
|
if (result[idx] > guard) {
|
||||||
|
return error.GuardOverflow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
std.debug.print(
|
||||||
|
"This example does not offer runnable code other than tests. Use zig build test to run them :)\n",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This numbers_magic call will not generate any error, so try is used.
|
||||||
|
// The result needs to be freed, because there was no error.
|
||||||
|
test "numers magic no error, no memory leak" {
|
||||||
|
const result = try numbers_magic(
|
||||||
|
std.testing.allocator,
|
||||||
|
&.{ 1, 2, 3, 4, 5, 6 },
|
||||||
|
&.{ 2, 1, 3, 7, 4, 2 },
|
||||||
|
50,
|
||||||
|
);
|
||||||
|
defer std.testing.allocator.free(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Numbers magic call is expected to return error (40 + 17 > 50), no deallocation is needed here.
|
||||||
|
// and it does not result in any memory leak, because of errdefer inside numbers_magic,
|
||||||
|
// which cleans up in that case.
|
||||||
|
test "numbers magic error, no memory leak" {
|
||||||
|
const result = numbers_magic(
|
||||||
|
std.testing.allocator,
|
||||||
|
&.{ 10, 20, 30, 40, 45, 43 },
|
||||||
|
&.{ 12, 11, 13, 17, 14, 12 },
|
||||||
|
50,
|
||||||
|
);
|
||||||
|
|
||||||
|
try std.testing.expect(result == error.GuardOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just to show that there will be memory leak if function succeeded (no error returned).
|
||||||
|
// Errdefer inside numbers_magic won't clean up in this case, so without using
|
||||||
|
// std.testing.allocator.free(...) this will leak memory.
|
||||||
|
// This test will fail, there should be information about this in output e.g. "1 leaked"
|
||||||
|
test "numbers magic no error, memory leak" {
|
||||||
|
_ = try numbers_magic(
|
||||||
|
std.testing.allocator,
|
||||||
|
&.{ 1, 2, 3, 4, 5, 6 },
|
||||||
|
&.{ 2, 1, 3, 7, 4, 2 },
|
||||||
|
50,
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user