2022-10-22 23:20:33 +01:00
|
|
|
const std = @import("std");
|
|
|
|
|
2022-10-10 17:46:25 +01:00
|
|
|
///
|
|
|
|
/// Returns the return type of the function type `Fn`.
|
|
|
|
///
|
|
|
|
pub fn FnReturn(comptime Fn: type) type {
|
|
|
|
const type_info = @typeInfo(Fn);
|
|
|
|
|
|
|
|
if (type_info != .Fn) @compileError("`Fn` must be a function type");
|
|
|
|
|
|
|
|
return type_info.Fn.return_type orelse void;
|
|
|
|
}
|
2022-10-20 22:30:48 +01:00
|
|
|
|
2022-10-24 01:02:07 +01:00
|
|
|
///
|
|
|
|
/// 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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-10-20 22:30:48 +01:00
|
|
|
///
|
2022-10-23 18:16:10 +01:00
|
|
|
/// 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.
|
2022-10-20 22:30:48 +01:00
|
|
|
///
|
2022-10-23 18:16:10 +01:00
|
|
|
pub fn Function(comptime captures_size: usize, comptime In: type, comptime Out: type) type {
|
2022-10-20 22:30:48 +01:00
|
|
|
return struct {
|
2022-10-23 18:16:10 +01:00
|
|
|
applyErased: fn (*anyopaque, In) Out,
|
2022-10-22 23:20:33 +01:00
|
|
|
context: [captures_size]u8,
|
2022-10-20 22:30:48 +01:00
|
|
|
|
|
|
|
///
|
|
|
|
/// Function type.
|
|
|
|
///
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
///
|
2022-10-22 23:20:33 +01:00
|
|
|
/// Applies `input` to `self`, producing a result according to the current context data.
|
2022-10-20 22:30:48 +01:00
|
|
|
///
|
2022-10-23 18:16:10 +01:00
|
|
|
pub fn apply(self: *Self, input: In) Out {
|
2022-10-22 23:20:33 +01:00
|
|
|
return self.applyErased(&self.context, input);
|
2022-10-20 22:30:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
///
|
2022-10-22 23:20:33 +01:00
|
|
|
/// 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.
|
2022-10-20 22:30:48 +01:00
|
|
|
///
|
|
|
|
/// The newly created [Self] is returned.
|
|
|
|
///
|
2022-10-23 18:16:10 +01:00
|
|
|
pub fn capture(captures: anytype, comptime call: fn (@TypeOf(captures), In) Out) Self {
|
2022-10-22 23:20:33 +01:00
|
|
|
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 {
|
2022-10-23 18:16:10 +01:00
|
|
|
fn do(erased: *anyopaque, input: In) Out {
|
2022-10-22 23:20:33 +01:00
|
|
|
return call(@ptrCast(*Captures, @alignCast(
|
|
|
|
captures_align, erased)).*, input);
|
2022-10-20 22:30:48 +01:00
|
|
|
}
|
2022-10-22 23:20:33 +01:00
|
|
|
}.do,
|
2022-10-20 22:30:48 +01:00
|
|
|
};
|
2022-10-22 23:20:33 +01:00
|
|
|
|
|
|
|
@ptrCast(*Captures, @alignCast(captures_align, &function.context)).* = captures;
|
|
|
|
|
|
|
|
return function;
|
2022-10-20 22:30:48 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|