1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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: *const wayland.Context, opcode: u16, args: []const u8) void {
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.get(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(), _: *const wayland.Context, a: u32, b: u32) void {
self.a = a;
self.b = b;
}
};
var dummy = Dummy{};
const Events = EventSet(Dummy, .{null, Dummy.something });
var ctx: wayland.Context = undefined;
Events.on_event(&dummy, &ctx, 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);
}
|