lib/wayland/src/protocol/schema.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 
  3 pub const Direction = enum {
  4     request,
  5     event,
  6 };
  7 
  8 pub const Kind = enum {
  9     int,
 10     uint,
 11     fixed,
 12     string,
 13     object,
 14     new_id,
 15     array,
 16     fd,
 17 };
 18 
 19 pub const Argument = struct {
 20     name: []const u8,
 21     kind: Kind,
 22     interface: ?[]const u8,
 23     enumeration: ?[]const u8,
 24     nullable: bool,
 25 };
 26 
 27 pub const Message = struct {
 28     name: []const u8,
 29     opcode: u16,
 30     since: u32,
 31     deprecated_since: ?u32,
 32     destructor: bool,
 33     signature: []const u8,
 34     descriptor_count: u8,
 35     minimum_payload_size: u16,
 36     arguments: []const Argument,
 37 
 38     pub fn supportedBy(self: Message, version: u32) bool {
 39         return version >= self.since;
 40     }
 41 
 42     pub fn argument(self: Message, name: []const u8) ?*const Argument {
 43         for (self.arguments) |*candidate| {
 44             if (std.mem.eql(u8, candidate.name, name)) return candidate;
 45         }
 46         return null;
 47     }
 48 
 49     pub fn newIdCount(self: Message) usize {
 50         var count: usize = 0;
 51         for (self.arguments) |candidate| {
 52             if (candidate.kind == .new_id) count += 1;
 53         }
 54         return count;
 55     }
 56 };
 57 
 58 pub const Entry = struct {
 59     name: []const u8,
 60     value: u32,
 61     since: u32,
 62     deprecated_since: ?u32,
 63 };
 64 
 65 pub const Enumeration = struct {
 66     name: []const u8,
 67     since: u32,
 68     bitfield: bool,
 69     entries: []const Entry,
 70 
 71     pub fn entry(self: Enumeration, value: u32) ?*const Entry {
 72         for (self.entries) |*candidate| {
 73             if (candidate.value == value) return candidate;
 74         }
 75         return null;
 76     }
 77 };
 78 
 79 pub const Interface = struct {
 80     name: []const u8,
 81     version: u32,
 82     requests: []const Message,
 83     events: []const Message,
 84     enumerations: []const Enumeration,
 85 
 86     pub fn request(self: Interface, opcode: u16) ?*const Message {
 87         return findMessage(self.requests, opcode);
 88     }
 89 
 90     pub fn event(self: Interface, opcode: u16) ?*const Message {
 91         return findMessage(self.events, opcode);
 92     }
 93 
 94     pub fn enumeration(self: Interface, name: []const u8) ?*const Enumeration {
 95         for (self.enumerations) |*candidate| {
 96             if (std.mem.eql(u8, candidate.name, name)) return candidate;
 97         }
 98         return null;
 99     }
100 };
101 
102 pub fn findInterface(interfaces: []const Interface, name: []const u8) ?*const Interface {
103     for (interfaces) |*candidate| {
104         if (std.mem.eql(u8, candidate.name, name)) return candidate;
105     }
106     return null;
107 }
108 
109 fn findMessage(messages: []const Message, opcode: u16) ?*const Message {
110     if (opcode >= messages.len) return null;
111     const message = &messages[opcode];
112     if (message.opcode != opcode) return null;
113     return message;
114 }
115 
116 test "schema lookup preserves opcode, version, and enum meaning" {
117     const messages = [_]Message{.{
118         .name = "create",
119         .opcode = 0,
120         .since = 2,
121         .deprecated_since = null,
122         .destructor = false,
123         .signature = "2n",
124         .descriptor_count = 0,
125         .minimum_payload_size = 4,
126         .arguments = &.{.{
127             .name = "id",
128             .kind = .new_id,
129             .interface = "created",
130             .enumeration = null,
131             .nullable = false,
132         }},
133     }};
134     const entries = [_]Entry{.{
135         .name = "ready",
136         .value = 7,
137         .since = 1,
138         .deprecated_since = null,
139     }};
140     const enumerations = [_]Enumeration{.{
141         .name = "state",
142         .since = 1,
143         .bitfield = false,
144         .entries = &entries,
145     }};
146     const interfaces = [_]Interface{.{
147         .name = "owner",
148         .version = 2,
149         .requests = &messages,
150         .events = &.{},
151         .enumerations = &enumerations,
152     }};
153 
154     const interface = findInterface(&interfaces, "owner").?;
155     try std.testing.expect(interface.request(1) == null);
156     const message = interface.request(0).?;
157     try std.testing.expect(!message.supportedBy(1));
158     try std.testing.expect(message.supportedBy(2));
159     try std.testing.expectEqual(@as(usize, 1), message.newIdCount());
160     try std.testing.expectEqual(Kind.new_id, message.argument("id").?.kind);
161     try std.testing.expectEqualStrings("ready", interface.enumeration("state").?.entry(7).?.name);
162 }