mirror of
https://github.com/zoriya/zig-wayland.git
synced 2025-12-06 07:06:12 +00:00
Use an enum for the field name in list.Head
This avoids issues with zig's comptime function memoization semantics when pointer types such as slices are used. References: https://github.com/ziglang/zig/issues/7948
This commit is contained in:
@@ -21,7 +21,7 @@ const C = struct {
|
||||
|
||||
pub fn main() void {
|
||||
{
|
||||
var a: wl.list.Head(B, "link") = undefined;
|
||||
var a: wl.list.Head(B, .link) = undefined;
|
||||
a.init();
|
||||
|
||||
var one = B{ .data = 1 };
|
||||
|
||||
@@ -413,10 +413,37 @@ pub const list = struct {
|
||||
reverse,
|
||||
};
|
||||
|
||||
/// Compared to std.meta.FieldEnum this version returns an empty enum for opaque types
|
||||
/// and only supports structs and opaque types.
|
||||
pub fn FieldEnum(comptime T: type) type {
|
||||
const field_infos = switch (@typeInfo(T)) {
|
||||
.Struct => |info| info.fields,
|
||||
.Opaque => [_]void{},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
var enum_fields: [field_infos.len]std.builtin.Type.EnumField = undefined;
|
||||
for (field_infos) |field, i| {
|
||||
enum_fields[i] = .{
|
||||
.name = field.name,
|
||||
.value = i,
|
||||
};
|
||||
}
|
||||
return @Type(.{
|
||||
.Enum = .{
|
||||
.layout = .Auto,
|
||||
.tag_type = std.math.IntFittingRange(0, field_infos.len - 1),
|
||||
.fields = &enum_fields,
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/// This has the same ABI as wl.list.Link/wl_list. If link_field is null, then
|
||||
/// T.getLink()/T.fromLink() will be used. This allows for compatiability
|
||||
/// with wl.Client and wl.Resource
|
||||
pub fn Head(comptime T: type, comptime link_field: ?[]const u8) type {
|
||||
pub fn Head(comptime T: type, comptime link_field: ?FieldEnum(T)) type {
|
||||
return extern struct {
|
||||
const Self = @This();
|
||||
|
||||
@@ -427,12 +454,12 @@ pub const list = struct {
|
||||
}
|
||||
|
||||
pub fn prepend(head: *Self, elem: *T) void {
|
||||
const link = if (link_field) |f| &@field(elem, f) else elem.getLink();
|
||||
const link = if (link_field) |f| &@field(elem, @tagName(f)) else elem.getLink();
|
||||
head.link.insert(link);
|
||||
}
|
||||
|
||||
pub fn append(head: *Self, elem: *T) void {
|
||||
const link = if (link_field) |f| &@field(elem, f) else elem.getLink();
|
||||
const link = if (link_field) |f| &@field(elem, @tagName(f)) else elem.getLink();
|
||||
head.link.prev.?.insert(link);
|
||||
}
|
||||
|
||||
@@ -469,7 +496,7 @@ pub const list = struct {
|
||||
.reverse => it.current.prev.?,
|
||||
};
|
||||
if (it.current == it.head) return null;
|
||||
return if (link_field) |f| @fieldParentPtr(T, f, it.current) else T.fromLink(it.current);
|
||||
return if (link_field) |f| @fieldParentPtr(T, @tagName(f), it.current) else T.fromLink(it.current);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -494,7 +521,7 @@ pub const list = struct {
|
||||
.reverse => it.future.prev.?,
|
||||
};
|
||||
if (it.current == it.head) return null;
|
||||
return if (link_field) |f| @fieldParentPtr(T, f, it.current) else T.fromLink(it.current);
|
||||
return if (link_field) |f| @fieldParentPtr(T, @tagName(f), it.current) else T.fromLink(it.current);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -554,7 +581,7 @@ pub fn Signal(comptime T: type) type {
|
||||
return extern struct {
|
||||
const Self = @This();
|
||||
|
||||
listener_list: list.Head(Listener(T), "link"),
|
||||
listener_list: list.Head(Listener(T), .link),
|
||||
|
||||
pub fn init(signal: *Self) void {
|
||||
signal.listener_list.init();
|
||||
|
||||
Reference in New Issue
Block a user