Application Context Implementation #4
|
@ -2,6 +2,11 @@ const meta = @import("./meta.zig");
|
||||||
const stack = @import("./stack.zig");
|
const stack = @import("./stack.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Closure for allocating, reallocating, and deallocating dynamic memory resources through itself.
|
||||||
|
///
|
||||||
|
pub const Allocator = meta.BiFunction(56, ?[]u8, usize, AllocationError![]u8);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// File-system agnostic abstraction for manipulating a file.
|
/// File-system agnostic abstraction for manipulating a file.
|
||||||
///
|
///
|
||||||
|
@ -186,16 +191,24 @@ pub const Writer = meta.Function(@sizeOf(usize), []const u8, usize);
|
||||||
/// Returns `true` if `this` is the same length and contains the same data as `that`, otherwise
|
/// Returns `true` if `this` is the same length and contains the same data as `that`, otherwise
|
||||||
/// `false`.
|
/// `false`.
|
||||||
///
|
///
|
||||||
pub fn equalsBytes(this: []const u8, that: []const u8) bool {
|
pub fn equals(comptime Element: type, this: []const Element, that: []const Element) bool {
|
||||||
return std.mem.eql(u8, this, that);
|
if (this.len != that.len) return false;
|
||||||
|
|
||||||
|
{
|
||||||
|
var i = std.mem.zeroes(usize);
|
||||||
|
|
||||||
|
while (i < this.len) : (i += 1) if (this[i] != that[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Equivalence of bytes" {
|
test "Equivalence of bytes" {
|
||||||
const bytes_sequence = &.{69, 42, 0};
|
const bytes_sequence = &.{69, 42, 0};
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
try testing.expect(equalsBytes(bytes_sequence, bytes_sequence));
|
try testing.expect(equals(u8, bytes_sequence, bytes_sequence));
|
||||||
try testing.expect(!equalsBytes(bytes_sequence, &.{69, 42}));
|
try testing.expect(!equals(u8, bytes_sequence, &.{69, 42}));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
|
@ -11,6 +11,63 @@ pub fn FnReturn(comptime Fn: type) type {
|
||||||
return type_info.Fn.return_type orelse void;
|
return type_info.Fn.return_type orelse void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns a double-input single-output closure type where `A` represents the first input type, `B`
|
||||||
|
/// represents the second, and `Out` represents the output type, and `captures_size` represents the
|
||||||
|
/// size of the closure context.
|
||||||
|
///
|
||||||
|
pub fn BiFunction(comptime captures_size: usize, comptime A: type,
|
||||||
|
comptime B: type, comptime Out: type) type {
|
||||||
|
|
||||||
|
return struct {
|
||||||
|
applyErased: fn (*anyopaque, A, B) Out,
|
||||||
|
context: [captures_size]u8,
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Function type.
|
||||||
|
///
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Applies `a` and `b` to `self`, producing a result according to the current context data.
|
||||||
|
///
|
||||||
|
pub fn apply(self: *Self, a: A, b: B) Out {
|
||||||
|
return self.applyErased(&self.context, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Creates a new [Self] by capturing the `captures` value as the context and `call` as the
|
||||||
|
/// as the behavior executed when [apply] or [applyErased] is called.
|
||||||
|
///
|
||||||
|
/// The newly created [Self] is returned.
|
||||||
|
///
|
||||||
|
pub fn capture(captures: anytype, comptime call: fn (@TypeOf(captures), A, B) Out) Self {
|
||||||
|
const Captures = @TypeOf(captures);
|
||||||
|
|
||||||
|
if (@sizeOf(Captures) > captures_size)
|
||||||
|
@compileError("`captures` must be smaller than or equal to " ++
|
||||||
|
std.fmt.comptimePrint("{d}", .{captures_size}) ++ " bytes");
|
||||||
|
|
||||||
|
const captures_align = @alignOf(Captures);
|
||||||
|
|
||||||
|
var function = Self{
|
||||||
|
.context = undefined,
|
||||||
|
|
||||||
|
.applyErased = struct {
|
||||||
|
fn do(erased: *anyopaque, a: A, b: B) Out {
|
||||||
|
return call(@ptrCast(*Captures, @alignCast(
|
||||||
|
captures_align, erased)).*, a, b);
|
||||||
|
}
|
||||||
|
}.do,
|
||||||
|
};
|
||||||
|
|
||||||
|
@ptrCast(*Captures, @alignCast(captures_align, &function.context)).* = captures;
|
||||||
|
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns a single-input single-output closure type where `In` represents the input type, `Out`
|
/// Returns a single-input single-output closure type where `In` represents the input type, `Out`
|
||||||
/// represents the output type, and `captures_size` represents the size of the closure context.
|
/// represents the output type, and `captures_size` represents the size of the closure context.
|
||||||
|
|
Loading…
Reference in New Issue