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 }