lib/ui/src/abi/scalar.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 /// `bind` checks the ten header table spans and rejects the buffer with the first check that fails.
4 /// A span whose `count` is 0 is not checked, whatever its `offset`. An `offset` below the 152 byte
5 /// header is rejected with `error.SpanOutOfBounds`. An `offset` that is not a multiple of the
6 /// element alignment is rejected with `error.SpanMisaligned`. A span whose byte length overflows
7 /// or whose end passes the buffer is rejected with `error.SpanOutOfBounds`.
8 pub const Span = extern struct {
9 /// `Span.offset` is a byte offset from the start of the buffer.
10 offset: u32 = 0,
11 /// `Span.count` is a number of elements, not bytes.
12 count: u32 = 0,
13 };
14
15 pub const Rect = extern struct {
16 x: f32 = 0,
17 y: f32 = 0,
18 width: f32 = 0,
19 height: f32 = 0,
20 };
21
22 pub const IRect = extern struct {
23 x: i32 = 0,
24 y: i32 = 0,
25 width: u32 = 0,
26 height: u32 = 0,
27 };
28
29 pub const Color = extern struct {
30 r: u8 = 0,
31 g: u8 = 0,
32 b: u8 = 0,
33 a: u8 = 0,
34 };
35
36 pub const AssetHandle = extern struct {
37 index: u32 = 0,
38 generation: u32 = 0,
39 };
40
41 /// `Atom.offset` and `Atom.len` locate the atom's bytes in the string table. An atom that runs
42 /// past that table is rejected with `error.AtomTextOutOfBounds`.
43 pub const Atom = extern struct {
44 offset: u32 = 0,
45 len: u32 = 0,
46 };
47
48 /// `atom_absent` is 0. Entry 0 of the atom table is reserved and never dereferenced. `View.text`
49 /// returns an empty slice for it. The survey still bounds-checks its record like every other atom.
50 pub const atom_absent: u32 = 0;
51
52 comptime {
53 std.debug.assert(@sizeOf(Span) == 8);
54 std.debug.assert(@alignOf(Span) == 4);
55 std.debug.assert(@offsetOf(Span, "offset") == 0);
56 std.debug.assert(@offsetOf(Span, "count") == 4);
57 std.debug.assert(@sizeOf(Rect) == 16);
58 std.debug.assert(@alignOf(Rect) == 4);
59 std.debug.assert(@offsetOf(Rect, "width") == 8);
60 std.debug.assert(@sizeOf(IRect) == 16);
61 std.debug.assert(@alignOf(IRect) == 4);
62 std.debug.assert(@offsetOf(IRect, "width") == 8);
63 std.debug.assert(@sizeOf(Color) == 4);
64 std.debug.assert(@alignOf(Color) == 1);
65 std.debug.assert(@offsetOf(Color, "a") == 3);
66 std.debug.assert(@sizeOf(AssetHandle) == 8);
67 std.debug.assert(@alignOf(AssetHandle) == 4);
68 std.debug.assert(@offsetOf(AssetHandle, "generation") == 4);
69 std.debug.assert(@sizeOf(Atom) == 8);
70 std.debug.assert(@alignOf(Atom) == 4);
71 std.debug.assert(@offsetOf(Atom, "len") == 4);
72 }
73
74 test "every scalar record carries defaults a consumer can rely on" {
75 try std.testing.expectEqual(Span{ .offset = 0, .count = 0 }, Span{});
76 try std.testing.expectEqual(Rect{ .x = 0, .y = 0, .width = 0, .height = 0 }, Rect{});
77 try std.testing.expectEqual(IRect{ .x = 0, .y = 0, .width = 0, .height = 0 }, IRect{});
78 try std.testing.expectEqual(Color{ .r = 0, .g = 0, .b = 0, .a = 0 }, Color{});
79 try std.testing.expectEqual(AssetHandle{ .index = 0, .generation = 0 }, AssetHandle{});
80 try std.testing.expectEqual(Atom{ .offset = 0, .len = 0 }, Atom{});
81 }
82
83 test "a span measures its own extent in bytes at its element size" {
84 const span = Span{ .offset = 64, .count = 3 };
85 try std.testing.expectEqual(@as(u64, 64), span.offset);
86 try std.testing.expectEqual(@as(u64, 88), span.offset + span.count * @sizeOf(Atom));
87 }