diff options
Diffstat (limited to 'src/event-set.zig')
| -rw-r--r-- | src/event-set.zig | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/event-set.zig b/src/event-set.zig new file mode 100644 index 0000000..5721a4e --- /dev/null +++ b/src/event-set.zig @@ -0,0 +1,83 @@ +const std = @import("std"); +const wayland = @import("root.zig"); + +pub fn EventSet(T: type, events: anytype) type { + return struct { + pub fn on_event(ptr: *anyopaque, ctx: *wayland.Context, opcode: u16, args: []const u8) void { + std.debug.print("event {} {}\n", .{T, opcode}); + var offset: usize = 0; + inline for (events, 0..) |event, index| { + if (@TypeOf(event) != @TypeOf(null) and index == opcode) { + const Args = std.meta.ArgsTuple(@TypeOf(event)); + var fn_args: Args = undefined; + fn_args[0] = @alignCast(@ptrCast(ptr)); + fn_args[1] = ctx; + + inline for (std.meta.fields(Args)[2..], 2..) |f, arg_index| { + switch (f.type) { + void => {}, + u32, i32 => { + const result = std.mem.readPackedIntNative(f.type, args, offset * 8); + fn_args[arg_index] = result; + offset += @sizeOf(f.type); + }, + []const u8 => { + const size: u32 = std.mem.readPackedIntNative(u32, args, offset * 8); + const padding_size: usize = @mod(@as(usize, @bitCast(-@as(isize, @intCast(size)))), 4); + offset += @sizeOf(u32); + const result = args[offset..offset + size - 1]; + offset += size + padding_size; + fn_args[arg_index] = result; + }, + *wayland.Object => { + const result = std.mem.readPackedIntNative(u32, args, offset * 8); + fn_args[arg_index] = ctx.display.registry.objects.items[result] orelse unreachable; + offset += @sizeOf(u32); + }, + else => |t| switch (@typeInfo(t)) { + .@"enum" => { + const result = std.mem.readPackedIntNative(u32, args, offset * 8); + fn_args[arg_index] = @enumFromInt(result); + offset += @sizeOf(u32); + }, + else => @compileError(std.fmt.comptimePrint("unsupported type {}", .{t})) + }, + } + } + + switch (@typeInfo(@typeInfo(@TypeOf(event)).@"fn".return_type orelse void)) { + .void => @call(.auto, event, fn_args), + .error_union => @call(.auto, event, fn_args) catch |err| { + std.log.err("error on event {} ({}): {}", .{opcode, T, err}); + }, + else => |t| @compileError(std.fmt.comptimePrint("unsupported return type {}", .{t})), + } + + return; + } + } + + std.log.warn("unimplemented event {} for {}", .{opcode, T}); + } + }; +} + +test { + const Dummy = struct { + a: u32 = 0, + b: u32 = 0, + + pub fn something(self: *@This(), a: u32, b: u32) void { + self.a = a; + self.b = b; + } + }; + + var dummy = Dummy{}; + const Events = EventSet(Dummy, .{null, Dummy.something }); + + Events.on_event(&dummy, 1, &(std.mem.toBytes(@as(u32, 1)) ++ std.mem.toBytes(@as(u32, 2)))); + + try std.testing.expectEqual(dummy.a, 1); + try std.testing.expectEqual(dummy.b, 2); +} |