common_core.zig (10209B)
1 const Object = opaque {}; 2 3 const Message = extern struct { 4 name: [*:0]const u8, 5 signature: [*:0]const u8, 6 types: ?[*]const ?*const Interface, 7 }; 8 9 const Interface = extern struct { 10 name: [*:0]const u8, 11 version: c_int, 12 method_count: c_int, 13 methods: ?[*]const Message, 14 event_count: c_int, 15 events: ?[*]const Message, 16 }; 17 18 const list = struct { 19 pub const Link = extern struct { 20 prev: ?*Link, 21 next: ?*Link, 22 23 pub fn init(link: *Link) void { 24 link.* = .{ .prev = link, .next = link }; 25 } 26 27 pub fn insert(link: *Link, other: *Link) void { 28 other.prev = link; 29 other.next = link.next; 30 link.next = other; 31 other.next.?.prev = other; 32 } 33 34 pub fn remove(link: *Link) void { 35 link.prev.?.next = link.next; 36 link.next.?.prev = link.prev; 37 link.* = .{ .prev = null, .next = null }; 38 } 39 40 pub fn replaceWith(link: *Link, other: *Link) void { 41 other.next = link.next; 42 other.next.?.prev = other; 43 other.prev = link.prev; 44 other.prev.?.next = other; 45 46 link.* = .{ .prev = null, .next = null }; 47 } 48 49 pub fn swapWith(link: *Link, other: *Link) void { 50 const old_other_prev = other.prev.?; 51 other.remove(); 52 53 link.replaceWith(other); 54 55 if (old_other_prev == link) { 56 other.insert(link); 57 } else { 58 old_other_prev.insert(link); 59 } 60 } 61 62 /// private helper that doesn't handle empty lists and assumes that 63 /// other is the link of a Head. 64 fn insertList(link: *Link, other: *Link) void { 65 other.next.?.prev = link; 66 other.prev.?.next = link.next; 67 link.next.?.prev = other.prev; 68 link.next = other.next; 69 70 other.init(); 71 } 72 }; 73 74 pub const Direction = enum { 75 forward, 76 reverse, 77 }; 78 79 /// This has the same ABI as wl.list.Link/wl_list. If link_field is null, then 80 /// T.getLink()/T.fromLink() will be used. This allows for compatiability 81 /// with wl.Client and wl.Resource 82 pub fn Head(comptime T: type, comptime link_field: ?@Type(.enum_literal)) type { 83 return extern struct { 84 const Self = @This(); 85 86 link: Link, 87 88 pub fn init(head: *Self) void { 89 head.link.init(); 90 } 91 92 pub fn prepend(head: *Self, elem: *T) void { 93 head.link.insert(linkFromElem(elem)); 94 } 95 96 pub fn append(head: *Self, elem: *T) void { 97 head.link.prev.?.insert(linkFromElem(elem)); 98 } 99 100 pub fn prependList(head: *Self, other: *Self) void { 101 if (other.empty()) return; 102 head.link.insertList(&other.link); 103 } 104 105 pub fn appendList(head: *Self, other: *Self) void { 106 if (other.empty()) return; 107 head.link.prev.?.insertList(&other.link); 108 } 109 110 pub fn first(head: *Self) ?*T { 111 if (head.empty()) { 112 return null; 113 } else { 114 return elemFromLink(head.link.next.?); 115 } 116 } 117 118 pub fn last(head: *Self) ?*T { 119 if (head.empty()) { 120 return null; 121 } else { 122 return elemFromLink(head.link.prev.?); 123 } 124 } 125 126 pub fn length(head: *const Self) usize { 127 var count: usize = 0; 128 var current = head.link.next.?; 129 while (current != &head.link) : (current = current.next.?) { 130 count += 1; 131 } 132 return count; 133 } 134 135 pub fn empty(head: *const Self) bool { 136 return head.link.next == &head.link; 137 } 138 139 /// Removal of elements during iteration is illegal 140 pub fn Iterator(comptime direction: Direction) type { 141 return struct { 142 head: *Link, 143 current: *Link, 144 145 pub fn next(it: *@This()) ?*T { 146 it.current = switch (direction) { 147 .forward => it.current.next.?, 148 .reverse => it.current.prev.?, 149 }; 150 if (it.current == it.head) return null; 151 return elemFromLink(it.current); 152 } 153 }; 154 } 155 156 /// Removal of elements during iteration is illegal 157 pub fn iterator(head: *Self, comptime direction: Direction) Iterator(direction) { 158 return .{ .head = &head.link, .current = &head.link }; 159 } 160 161 /// Removal of the current element during iteration is permitted. 162 /// Removal of other elements is illegal. 163 pub fn SafeIterator(comptime direction: Direction) type { 164 return struct { 165 head: *Link, 166 current: *Link, 167 future: *Link, 168 169 pub fn next(it: *@This()) ?*T { 170 it.current = it.future; 171 it.future = switch (direction) { 172 .forward => it.future.next.?, 173 .reverse => it.future.prev.?, 174 }; 175 if (it.current == it.head) return null; 176 return elemFromLink(it.current); 177 } 178 }; 179 } 180 181 /// Removal of the current element during iteration is permitted. 182 /// Removal of other elements is illegal. 183 pub fn safeIterator(head: *Self, comptime direction: Direction) SafeIterator(direction) { 184 return .{ 185 .head = &head.link, 186 .current = &head.link, 187 .future = switch (direction) { 188 .forward => head.link.next.?, 189 .reverse => head.link.prev.?, 190 }, 191 }; 192 } 193 194 fn linkFromElem(elem: *T) *Link { 195 if (link_field) |f| { 196 return &@field(elem, @tagName(f)); 197 } else { 198 return elem.getLink(); 199 } 200 } 201 202 fn elemFromLink(link: *Link) *T { 203 if (link_field) |f| { 204 return @fieldParentPtr(@tagName(f), link); 205 } else { 206 return T.fromLink(link); 207 } 208 } 209 }; 210 } 211 }; 212 213 const Array = extern struct { 214 size: usize, 215 alloc: usize, 216 data: ?*anyopaque, 217 218 /// Does not clone memory 219 pub fn fromArrayList(comptime T: type, array_list: std.ArrayList(T)) Array { 220 return Array{ 221 .size = array_list.items.len * @sizeOf(T), 222 .alloc = array_list.capacity * @sizeOf(T), 223 .data = array_list.items.ptr, 224 }; 225 } 226 227 pub fn slice(array: Array, comptime T: type) []align(4) T { 228 const data = array.data orelse return &[0]T{}; 229 // The wire protocol/libwayland only guarantee 32-bit word alignment. 230 const ptr: [*]align(4) T = @ptrCast(@alignCast(data)); 231 return ptr[0..@divExact(array.size, @sizeOf(T))]; 232 } 233 }; 234 235 /// A 24.8 signed fixed-point number. 236 const Fixed = enum(i32) { 237 _, 238 239 pub fn toInt(f: Fixed) i24 { 240 return @truncate(@intFromEnum(f) >> 8); 241 } 242 243 pub fn fromInt(i: i24) Fixed { 244 return @enumFromInt(@as(i32, i) << 8); 245 } 246 247 pub fn toDouble(f: Fixed) f64 { 248 return @as(f64, @floatFromInt(@intFromEnum(f))) / 256; 249 } 250 251 pub fn fromDouble(d: f64) Fixed { 252 return @enumFromInt(@as(i32, @intFromFloat(d * 256))); 253 } 254 }; 255 256 const Argument = extern union { 257 i: i32, 258 u: u32, 259 f: Fixed, 260 s: ?[*:0]const u8, 261 o: ?*Object, 262 n: u32, 263 a: ?*Array, 264 h: i32, 265 }; 266 267 fn Dispatcher(comptime Obj: type, comptime Data: type) type { 268 const client_side = @hasDecl(Obj, "Event"); 269 const Payload = if (client_side) Obj.Event else Obj.Request; 270 return struct { 271 fn dispatcher( 272 implementation: ?*const anyopaque, 273 object: if (client_side) *client.wl.Proxy else *server.wl.Resource, 274 opcode: u32, 275 _: *const Message, 276 args: [*]Argument, 277 ) callconv(.C) c_int { 278 inline for (@typeInfo(Payload).@"union".fields, 0..) |payload_field, payload_num| { 279 if (payload_num == opcode) { 280 var payload_data: payload_field.type = undefined; 281 if (payload_field.type != void) { 282 inline for (@typeInfo(payload_field.type).@"struct".fields, 0..) |f, i| { 283 switch (@typeInfo(f.type)) { 284 // signed/unsigned ints, fds, new_ids, bitfield enums 285 .int, .@"struct" => @field(payload_data, f.name) = @as(f.type, @bitCast(args[i].u)), 286 // objects, strings, arrays 287 .pointer, .optional => @field(payload_data, f.name) = @as(f.type, @ptrFromInt(@intFromPtr(args[i].o))), 288 // non-bitfield enums 289 .@"enum" => @field(payload_data, f.name) = @as(f.type, @enumFromInt(args[i].i)), 290 else => unreachable, 291 } 292 } 293 } 294 295 const HandlerFn = fn (*Obj, Payload, Data) void; 296 @as(*const HandlerFn, @ptrCast(@alignCast(implementation)))( 297 @as(*Obj, @ptrCast(object)), 298 @unionInit(Payload, payload_field.name, payload_data), 299 @as(Data, @ptrFromInt(@intFromPtr(object.getUserData()))), 300 ); 301 302 return 0; 303 } 304 } 305 unreachable; 306 } 307 }; 308 }