aboutsummaryrefslogtreecommitdiff
path: root/src/event-set.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/event-set.zig')
-rw-r--r--src/event-set.zig83
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);
+}