Last active
December 15, 2024 23:18
-
-
Save nickelca/a203f2d08ceec8ef24384cfb474dfc8d to your computer and use it in GitHub Desktop.
Text components with std.json parsing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Text_Object = @This(); | |
list: []const Text, | |
pub const Text = union(enum) { | |
component: Component, | |
plain: []const u8, | |
pub fn jsonParse( | |
ally: std.mem.Allocator, | |
tokens: anytype, | |
options: std.json.ParseOptions, | |
) std.json.ParseError(@TypeOf(tokens.*))!Text { | |
return switch (try tokens.peekNextTokenType()) { | |
.string => .{ | |
.plain = try std.json.innerParse([]const u8, ally, tokens, options), | |
}, | |
.object_begin => .{ | |
.component = try std.json.innerParse(Component, ally, tokens, options), | |
}, | |
else => error.UnexpectedToken, | |
}; | |
} | |
}; | |
pub const Component = struct { | |
text: []const u8, | |
color: ?[]const u8 = null, | |
italic: bool = false, | |
bold: bool = false, | |
obfuscated: bool = false, | |
pub fn equals(self: Component, to: Component) bool { | |
return std.mem.eql(u8, self.text, to.text) and | |
self.italic == to.italic and | |
self.bold == to.bold and | |
self.obfuscated == to.obfuscated and | |
((self.color == null and to.color == null) or | |
(self.color != null and to.color != null and | |
std.mem.eql(u8, self.color.?, to.color.?))); | |
} | |
}; | |
pub fn jsonParse( | |
ally: std.mem.Allocator, | |
tokens: anytype, | |
options: std.json.ParseOptions, | |
) std.json.ParseError(@TypeOf(tokens.*))!Text_Object { | |
const list: []Text = switch (try tokens.peekNextTokenType()) { | |
.array_begin => try std.json.innerParse([]Text, ally, tokens, options), | |
.string, .object_begin => try ally.dupe(Text, &.{ | |
try std.json.innerParse(Text, ally, tokens, options), | |
}), | |
else => return error.UnexpectedToken, | |
}; | |
return .{ .list = list }; | |
} | |
fn Test_Text_Object_JSON( | |
arena: std.mem.Allocator, | |
expected: Text_Object, | |
json: []const u8, | |
) !void { | |
const obj = try std.json.parseFromSlice(Text_Object, arena, json, .{ | |
.allocate = .alloc_if_needed, | |
}); | |
defer obj.deinit(); | |
try std.testing.expectEqual(expected.list.len, obj.value.list.len); | |
for (expected.list, obj.value.list) |e, a| { | |
switch (e) { | |
.plain => |t1| switch (a) { | |
.plain => |t2| try std.testing.expectEqualStrings(t1, t2), | |
.component => return error.TestExpectedEqual, | |
}, | |
.component => |c1| switch (a) { | |
.plain => return error.TestExpectedEqual, | |
.component => |c2| try std.testing.expect(c1.equals(c2)), | |
}, | |
} | |
} | |
} | |
test "Text Object JSON" { | |
var arena_state: std.heap.ArenaAllocator = .init(std.testing.allocator); | |
defer arena_state.deinit(); | |
const arena = arena_state.allocator(); | |
try Test_Text_Object_JSON( | |
arena, | |
.{ .list = &.{ | |
.{ .plain = "Hello" }, | |
} }, | |
\\"Hello" | |
, | |
); | |
_ = arena_state.reset(.retain_capacity); | |
try Test_Text_Object_JSON( | |
arena, | |
.{ .list = &.{ | |
.{ .component = .{ .text = "Apple" } }, | |
} }, | |
\\{"text": "Apple"} | |
, | |
); | |
_ = arena_state.reset(.retain_capacity); | |
try Test_Text_Object_JSON( | |
arena, | |
.{ .list = &.{ | |
.{ .component = .{ .text = "Mansaf", .bold = true } }, | |
} }, | |
\\{"text": "Mansaf", "bold": true} | |
, | |
); | |
_ = arena_state.reset(.retain_capacity); | |
try Test_Text_Object_JSON( | |
arena, | |
.{ .list = &.{ | |
.{ .component = .{ .text = "Woooo" } }, | |
} }, | |
\\[{"text": "Woooo"}] | |
, | |
); | |
_ = arena_state.reset(.retain_capacity); | |
try Test_Text_Object_JSON( | |
arena, | |
.{ .list = &.{ | |
.{ .component = .{ .text = "Gaming" } }, | |
.{ .plain = "std.json is goated" }, | |
.{ .component = .{ .text = "W", .color = "red", .obfuscated = true } }, | |
} }, | |
\\[ | |
\\ {"text": "Gaming"}, | |
\\ "std.json is goated", | |
\\ {"text":"W", "color":"red", "obfuscated": true} | |
\\] | |
, | |
); | |
_ = arena_state.reset(.retain_capacity); | |
} | |
const std = @import("std"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment