ona/src/core/meta.zig

64 lines
2.0 KiB
Zig
Raw Normal View History

///
/// 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;
}
///
/// 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.
///
pub fn Function(comptime In: type, comptime Out: type) type {
return struct {
2022-10-30 22:07:36 +00:00
callErased: fn (*anyopaque, In) Out,
context: *anyopaque,
///
/// Function type.
///
const Self = @This();
///
2022-10-30 22:07:36 +00:00
/// Invokes `self` with `input`, producing a result according to the current context data.
///
2022-10-30 22:07:36 +00:00
pub fn call(self: *Self, input: In) Out {
return self.callErased(self.context, input);
}
///
/// Creates a new [Self] by capturing the `context` value as the capture context and
/// `invoke` as the behavior executed when [call] or [callErased] is called.
///
/// The newly created [Self] is returned.
///
pub fn capture(context: anytype, comptime invoke: fn (@TypeOf(context), In) Out) Self {
const Context = @TypeOf(context);
switch (@typeInfo(Context)) {
.Pointer => |info| if (info.size == .Slice)
@compileError("`context` cannot be a slice"),
else => @compileError("`context` must be a pointer"),
}
var function = Self{
.context = @ptrCast(*anyopaque, context),
2022-10-30 22:07:36 +00:00
.callErased = struct {
fn callErased(erased: *anyopaque, input: In) Out {
return invoke(@ptrCast(*Context, @alignCast(
@alignOf(Context), erased)).*, input);
}
2022-10-30 22:07:36 +00:00
}.callErased,
};
return function;
}
};
}