Skip to content

Commit 23bcce7

Browse files
Merge pull request #13 from PhantomUIx/feat/scene-paths
feat: add scene node path type
2 parents 7b7f55c + 78059c0 commit 23bcce7

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

lib/phantom/scene.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
pub const Properties = @import("scene/Properties.zig");
44
pub const Renderer = @import("scene/Renderer.zig");
5+
pub const Path = @import("scene/Path.zig");
56

67
pub const Node = union(enum) {
78
container: Container,
@@ -30,4 +31,5 @@ test {
3031
_ = Properties;
3132
_ = Renderer;
3233
_ = Node;
34+
_ = Path;
3335
}

lib/phantom/scene/Path.zig

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
const std = @import("std");
2+
const SceneNode = @import("../scene.zig").Node;
3+
const Self = @This();
4+
5+
pub const Error = error {
6+
InvalidType,
7+
InvalidIndex,
8+
};
9+
10+
pub const Item = union(enum) {
11+
index: usize,
12+
tag: []const u8,
13+
14+
pub fn access(self: Item, node: *const SceneNode) Error!*const SceneNode {
15+
return switch (self) {
16+
.index => |i| blk: {
17+
if (node.* == .container) {
18+
if (i >= node.container.children.len) break :blk Error.InvalidIndex;
19+
break :blk &node.container.children[i];
20+
}
21+
break :blk Error.InvalidType;
22+
},
23+
.tag => |t| if (std.mem.eql(u8, t, @tagName(node.*))) node else Error.InvalidType,
24+
};
25+
}
26+
};
27+
28+
pub const Iterator = struct {
29+
path: []const Item,
30+
index: usize = 0,
31+
32+
pub fn peek(self: *Iterator) ?Item {
33+
if (self.index >= self.path.len) return null;
34+
return self.path[self.index];
35+
}
36+
37+
pub fn next(self: *Iterator) ?Item {
38+
const item = self.peek() orelse return null;
39+
self.index += 1;
40+
return item;
41+
}
42+
};
43+
44+
pub fn access(path: []const Item, node: *const SceneNode) (Error || error{UnexpectedTag})!*const SceneNode {
45+
var iter: Iterator = .{ .path = path };
46+
47+
var curr_node = node;
48+
while (iter.next()) |tagItem| {
49+
const indexItem = if (iter.peek()) |item| blk: {
50+
iter.index += 1;
51+
break :blk item;
52+
} else null;
53+
54+
if (tagItem != .tag and indexItem != null) return error.UnexpectedTag;
55+
curr_node = try (indexItem orelse tagItem).access(curr_node);
56+
}
57+
return curr_node;
58+
}
59+
60+
test {
61+
const node: SceneNode = .{ .container = .{
62+
.layout = .{},
63+
.style = .{},
64+
.children = &.{
65+
.{ .container = .{
66+
.layout = .{},
67+
.style = .{},
68+
.children = &.{
69+
.{ .text = .{
70+
.text = "Hello, world",
71+
.font = "ABC",
72+
.font_size = .{ .value = @splat(30) },
73+
} },
74+
.{ .text = .{
75+
.text = "The quick brown fox jumps over the lazy dog",
76+
.font = "ABC",
77+
.font_size = .{ .value = @splat(30) },
78+
} },
79+
},
80+
} },
81+
},
82+
} };
83+
84+
try std.testing.expectEqualDeep(&node.container.children[0].container.children[0], try access(&.{
85+
.{ .tag = "container" },
86+
.{ .index = 0 },
87+
.{ .tag = "container" },
88+
.{ .index = 0 },
89+
.{ .tag = "text" },
90+
}, &node));
91+
92+
try std.testing.expectEqualDeep(&node.container.children[0].container.children[1], try access(&.{
93+
.{ .tag = "container" },
94+
.{ .index = 0 },
95+
.{ .tag = "container" },
96+
.{ .index = 1 },
97+
.{ .tag = "text" },
98+
}, &node));
99+
}

0 commit comments

Comments
 (0)