stevee

My wayland statusbar
git clone git://gtms.dev/stevee
Log | Files | Refs | README | LICENSE

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 }