@@ -20,22 +20,23 @@ A Design by Contract Library for Zig
20
20
---
21
21
22
22
Zig-DbC is a small library that provides a collection of functions to use
23
- [ design by contract] ( https://en.wikipedia.org/wiki/Design_by_contract ) (DbC) principles in software written in Zig
24
- programming language.
25
- It provides a simple and idiomatic API for defining * preconditions* , * postconditions* , and * invariants* that can be
23
+ [ design by contract] ( https://en.wikipedia.org/wiki/Design_by_contract ) (DbC) principles in Zig programs.
24
+ It provides a simple and idiomatic API for defining preconditions, postconditions, and invariants that can be
26
25
checked at runtime.
27
26
28
27
A common use case for DbC (and by extension Zig-DbC) is adding checks that guarantee the code behaves as intended.
29
- This can be especially useful, for example, during the implementation of complex data structures and algorithms
30
- (like balanced trees and graphs) where correctness depends on specific conditions being met.
28
+ This can be especially useful during the implementation of complex data structures and algorithms (like balanced trees
29
+ and graphs) where correctness depends on specific conditions being met.
31
30
32
31
### Features
33
32
34
- * A simple API to define ` preconditions ` , ` postconditions ` , and ` invariants `
35
- * Contracts are active in ` Debug ` , ` ReleaseSafe ` , and ` ReleaseSmall ` modes to catch bugs early
36
- * In ` ReleaseFast ` mode, all contract checks are removed at compile time
37
- * The ` contract ` function passes errors from your code to the caller
38
- * An optional mode to handle partial state changes in functions that can return errors
33
+ - A simple API to define preconditions, postconditions, and invariants
34
+ - ` require ` and ` ensure ` functions check preconditions and postconditions
35
+ - ` requiref ` and ` ensuref ` functions check preconditions and postconditions with formatted error messages
36
+ - ` requireCtx ` and ` ensureCtx ` functions check preconditions and postconditions with a context string
37
+ - ` contract ` and ` contractWithErrorTolerance ` functions check invariants
38
+ - Checks are active in ` Debug ` , ` ReleaseSafe ` , and ` ReleaseSmall ` build modes to catch bugs
39
+ - In ` ReleaseFast ` mode, all checks are removed at compile time to remove overhead
39
40
40
41
> [ !IMPORTANT]
41
42
> Zig-DbC is in early development, so bugs and breaking API changes are expected.
@@ -55,7 +56,7 @@ Run the following command in the root directory of your project to download Zig-
55
56
zig fetch --save=dbc " https://github.com/habedi/zig-dbc/archive/<branch_or_tag>.tar.gz"
56
57
```
57
58
58
- Replace ` <branch_or_tag> ` with the desired branch or tag, like ` main ` (for the development version) or ` v0.1 .0 `
59
+ Replace ` <branch_or_tag> ` with the desired branch or tag, like ` main ` (for the development version) or ` v0.2 .0 `
59
60
(for the latest release).
60
61
This command will download zig-dbc and add it to Zig's global cache and update your project's ` build.zig.zon ` file.
61
62
@@ -69,7 +70,6 @@ const std = @import("std");
69
70
pub fn build(b: *std.Build) void {
70
71
const target = b.standardTargetOptions(.{});
71
72
const optimize = b.standardOptimizeOption(.{});
72
-
73
73
const exe = b.addExecutable(.{
74
74
.name = "your-zig-program",
75
75
.root_source_file = b.path("src/main.zig"),
@@ -83,7 +83,7 @@ pub fn build(b: *std.Build) void {
83
83
// 2. Get Zig-DbC's top-level module
84
84
const zig_dbc_module = zig_dbc_dep.module("dbc");
85
85
86
- // 3. Add the module to your executable so you can @import("zig- dbc")
86
+ // 3. Add the module to your executable so you can @import("dbc")
87
87
exe.root_module.addImport("dbc", zig_dbc_module);
88
88
89
89
b.installArtifact(exe);
@@ -95,32 +95,33 @@ pub fn build(b: *std.Build) void {
95
95
Finally, you can ` @import("dbc") ` and start using it in your Zig code.
96
96
97
97
``` zig
98
+ const std = @import("std");
98
99
const dbc = @import("dbc");
99
100
100
101
pub fn MyStruct() type {
101
102
return struct {
102
103
const Self = @This();
103
- field: i32,
104
- is_ready: bool,
104
+ field: i32, is_ready: bool,
105
105
106
+ // The invariant guarantees that the object's state is always valid.
107
+ // It's checked automatically by the `contract` function.
106
108
fn invariant(self: Self) void {
107
- dbc.require(self.field > 0, "Field must always be positive");
109
+ dbc.require(.{ self.field > 0, "Field must always be positive" } );
108
110
}
109
111
110
112
pub fn doSomething(self: *Self) !void {
111
113
const old = .{ .field = self.field };
112
- return dbc.contract(self, @TypeOf( old), old, struct {
113
- fn run(ctx: @TypeOf(old), s: *Self) !void {
114
+ return dbc.contract(self, old,
115
+ struct { fn run(ctx: @TypeOf(old), s: *Self) !void {
114
116
// Precondition
115
- dbc.require(s.is_ready, "Struct not ready");
117
+ dbc.require(.{ s.is_ready, "Struct not ready" } );
116
118
117
119
// ... method logic ...
118
120
s.field += 1;
119
121
120
122
// Postcondition
121
- dbc.ensure(s.field > ctx.field, "Field must increase");
122
- }
123
- }.run);
123
+ dbc.ensure(.{ s.field > ctx.field, "Field must increase" });
124
+ }}.run);
124
125
}
125
126
};
126
127
}
@@ -136,6 +137,13 @@ Alternatively, you can use the `make docs` command to generate the documentation
136
137
This will generate HTML documentation in the ` docs/api ` directory, which you can serve locally with ` make serve-docs `
137
138
and view in a web browser.
138
139
140
+ #### Validators
141
+
142
+ Zig-DbC supports reusable validators in ` require ` and ` ensure ` functions by passing as argument either:
143
+
144
+ - a function with signature ` fn(T) bool ` , or
145
+ - a struct value with a ` run ` function with this signature: ` pub fn run(self, T) bool ` .
146
+
139
147
### Examples
140
148
141
149
Check out the [ examples] ( examples/ ) directory for example usages of Zig-DbC.
0 commit comments