martineausw/ziggurat
Type assertion and constraints zig library.
Library for defining type constraints and assertions.
Inspired off of this brainstorming thread.
The goal of ziggurat is to enable developers to comprehensibly define arbitrarily complex type constraints and assertions.
zig fetch --save git+https://github.com/martineausw/ziggurat.git#0.0.0
cd /path/to/clone/
git clone https://github.com/martineausw/ziggurat.git#0.0.0
cd /path/to/zig/project
zig fetch --save /path/to/clone/ziggurat/
ziggurat makes generous use of closures. This is done by returning function pointers as a member access of struct definitions.
I justify using closures as it lends itself to a declarative approach which appears more sensible than an imperative approach, in that it's easier to wrap (ha) my head around and favors type safety, also I appreciate the aesthetics.
fn foo() fn () void { // Returns signature of enclosed function
return struct {
fn bar() void {}
}.bar; // Accesses `bar` function pointer.
}
const bar: *const fn () void = foo();
// These are all equivalent: bar() == foo()() == void
test "closure equality" {
try std.testing.expectEqual(*const fn () void, @TypeOf(bar));
try std.testing.expectEqual(bar, foo());
try std.testing.expectEqual(void, @TypeOf(bar()));
try std.testing.expectEqual(bar(), foo()());
}
That out of the way, hopefully this isn't terribly intimidating:
fn foo(actual_value: anytype) sign(some_prototype)(actual_value)(void) { ... }
Prototype requires an eval function pointer.
const Prototype = struct {
name: [:0]const u8,
eval: *const fn (actual: anytype) anyerror!bool,
onFail: ?*const fn (prototype: Prototype, actual: anytype) void = null,
onError: ?*const fn (err: anyerror, prototype: Prototype, actual: anytype) void = null,
};
Here is an example implementation of a prototype.
const int: Prototype = .{
.eval = struct {
fn eval(actual: anytype) !bool {
return switch (@typeInfo(@TypeOf(actual))) {
.int => true,
else => false,
};
}
}.eval,
};
Here's an implementation that only accepts odd integer values:
const odd_int: Prototype = .{
.eval = struct {
fn eval(actual: anytype) bool {
return switch (@typeInfo(@TypeOf(actual))) {
.comptime_int => @mod(actual, 2) == 1,
.int => actual % 2 == 1,
else => false,
};
}
}.eval,
};
Intended to be used in comptime:
Intermediate and utility prototypes:
Boolean operations for prototype evaluation results
sign calls eval on a given prototype and will call onError or onFail for error or false return values, respectively. Complex prototypes are intended to be composed using operators and auxiliary prototypes.
pub fn sign(prototype: Prototype) fn (actual: anytype) fn (comptime return_type: type) type {
return struct {
pub fn validate(actual: anytype) fn (comptime return_type: type) type {
if (comptime prototype.eval(actual)) |result| {
if (!result) if (prototype.onFail) |onFail|
comptime onFail(prototype, actual);
} else |err| {
if (prototype.onError) |onError|
comptime onError(err, prototype, actual);
}
return struct {
pub fn returns(comptime return_type: type) type {
return return_type;
}
}.returns;
}
}.validate;
};