clean up hook implementation

This commit is contained in:
David Allemang
2024-07-10 14:32:37 -04:00
parent fd1bd9dbf5
commit 53cbe35a97

View File

@@ -4,7 +4,8 @@ pub fn Hook(ftype: type) type {
const F: std.builtin.Type.Fn = @typeInfo(ftype).Fn; const F: std.builtin.Type.Fn = @typeInfo(ftype).Fn;
const Result: type = F.return_type.?; const Result: type = F.return_type.?;
return struct { return switch (@typeInfo(Result)) {
.Void => struct {
const Self = @This(); const Self = @This();
handlers: std.AutoArrayHashMap(*const ftype, void), handlers: std.AutoArrayHashMap(*const ftype, void),
@@ -27,28 +28,50 @@ pub fn Hook(ftype: type) type {
_ = self.handlers.orderedRemove(f); _ = self.handlers.orderedRemove(f);
} }
fn invoke_alloc_results(self: Self, alloc: std.mem.Allocator, args: anytype) ![]Result { fn invoke(self: Self, args: anytype) void {
for (self.handlers.keys()) |handler| {
@call(.auto, handler, args);
}
}
},
else => struct {
const Self = @This();
handlers: std.AutoArrayHashMap(*const ftype, void),
pub fn init(alloc: std.mem.Allocator) Self {
return Self{
.handlers = std.AutoArrayHashMap(*const ftype, void).init(alloc),
};
}
pub fn deinit(self: *Self) void {
self.handlers.deinit();
}
pub fn register(self: *Self, f: ftype) !void {
try self.handlers.putNoClobber(f, {});
}
pub fn unregister(self: *Self, f: ftype) void {
_ = self.handlers.orderedRemove(f);
}
fn invoke(self: Self, alloc: std.mem.Allocator, args: anytype) ![]Result {
const results = try alloc.alloc(Result, self.handlers.count()); const results = try alloc.alloc(Result, self.handlers.count());
for (self.handlers.keys(), results) |handler, *result| { for (self.handlers.keys(), results) |handler, *result| {
result.* = @call(.auto, handler, args); result.* = @call(.auto, handler, args);
} }
return results; return results;
} }
},
fn invoke_void(self: Self, args: anytype) void {
for (self.handlers.keys()) |handler| {
@call(.auto, handler, args);
}
}
pub const invoke = switch (@typeInfo(Result)) {
.Void => invoke_void,
else => invoke_alloc_results,
};
}; };
} }
test "void hooks" { test "void hooks" {
var set_flags = Hook(fn (*usize) void).init(std.testing.allocator);
defer set_flags.deinit();
const hooks = struct { const hooks = struct {
pub fn set_one(f: *usize) void { pub fn set_one(f: *usize) void {
f.* |= 0b01; f.* |= 0b01;
@@ -59,9 +82,6 @@ test "void hooks" {
} }
}; };
var set_flags = Hook(fn (*usize) void).init(std.testing.allocator);
defer set_flags.deinit();
var flag: usize = undefined; var flag: usize = undefined;
flag = 0; flag = 0;
@@ -94,6 +114,9 @@ test "void hooks" {
} }
test "collect hooks" { test "collect hooks" {
var collect = Hook(fn (usize) usize).init(std.testing.allocator);
defer collect.deinit();
const hooks = struct { const hooks = struct {
pub fn double(f: usize) usize { pub fn double(f: usize) usize {
return f * 2; return f * 2;
@@ -104,9 +127,6 @@ test "collect hooks" {
} }
}; };
var collect = Hook(fn (usize) usize).init(std.testing.allocator);
defer collect.deinit();
{ {
const result = try collect.invoke(std.testing.allocator, .{3}); const result = try collect.invoke(std.testing.allocator, .{3});
defer std.testing.allocator.free(result); defer std.testing.allocator.free(result);