1
0
Fork 0
mirror of https://github.com/zigzap/zap.git synced 2025-10-20 15:14:08 +00:00

BoundFunction YEAH

This commit is contained in:
renerocksai 2025-03-23 23:28:09 +01:00
parent 3353b6a525
commit 6dd3c93a0f

View file

@ -96,22 +96,58 @@ test OldBind {
try std.testing.expectEqualStrings("Goodbye, Alice!\n", try bound_farewell.call(.{"Goodbye"}));
}
/// Creates a function type with instance pointer prepended to args
fn PrependFnArg(Func: type, Instance: type) type {
const InstancePtr = *Instance;
// Get the function type
const fn_info = @typeInfo(Func);
if (fn_info != .@"fn") {
@compileError("Second argument must be a function");
}
// Create new parameter list with instance pointer prepended
comptime var new_params: [fn_info.@"fn".params.len + 1]std.builtin.Type.Fn.Param = undefined;
new_params[0] = .{
.is_generic = false,
.is_noalias = false,
.type = InstancePtr,
};
// Copy original parameters
for (fn_info.@"fn".params, 0..) |param, i| {
new_params[i + 1] = param;
}
// Return the new function type
return @Type(.{
.@"fn" = .{
.calling_convention = fn_info.@"fn".calling_convention,
.is_generic = fn_info.@"fn".is_generic,
.is_var_args = fn_info.@"fn".is_var_args,
.return_type = fn_info.@"fn".return_type,
.params = &new_params,
},
});
}
/// Bind functions like `fn(a: X, b: Y)` to an instance of a struct. When called, the instance's `pub fn(self: *This(), a: X, b: Y)` is called.
///
/// make callbacks stateful when they're not meant to be?
// pub fn Bound(Instance: type, Func: type, func: anytype) type {
pub fn Bound(Instance: type, Func: type, DFunc: type) type {
pub fn Bind(Instance: type, Func: type) type {
// TODO: construct DFunc on-the-fly
// Verify Func is a function type
const func_info = @typeInfo(Func);
// if (func_info != .@"fn") {
// @compileError("Bound expexts a function type as second parameter");
// }
if (func_info != .@"fn") {
@compileError("Bound expexts a function type as second parameter");
}
const InstanceMethod = PrependFnArg(Func, Instance);
return struct {
instance: *Instance,
foo: *const DFunc,
foo: *const InstanceMethod,
const BoundFunction = @This();
@ -120,13 +156,13 @@ pub fn Bound(Instance: type, Func: type, DFunc: type) type {
}
// convenience init
pub fn init(instance_: *Instance, foo_: *const DFunc) BoundFunction {
pub fn init(instance_: *Instance, foo_: *const InstanceMethod) BoundFunction {
return .{ .instance = instance_, .foo = foo_ };
}
};
}
test Bound {
test Bind {
const Person = struct {
name: []const u8,
_buf: [1024]u8 = undefined,
@ -140,7 +176,7 @@ test Bound {
var alice: Person = .{ .name = "Alice" };
const bound_greet = Bound(Person, CallBack, @TypeOf(Person.speak)).init(&alice, &Person.speak);
const bound_greet = Bind(Person, CallBack).init(&alice, &Person.speak);
const greeting = try bound_greet.call(.{"Hello"});