Skip to content

Commit 08c4c8d

Browse files
Add parseYaml function for custom types
1 parent 1a0cc53 commit 08c4c8d

File tree

2 files changed

+50
-9
lines changed

2 files changed

+50
-9
lines changed

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,39 @@ nested:
122122
finally: [ 8.17, 19.78, 17, 21 ]
123123
```
124124

125+
4. For parsing types not supported, add a `parseYaml` function:
126+
127+
```zig
128+
const Simple = struct {
129+
names: []const []const u8,
130+
numbers: []const i16,
131+
nested: struct {
132+
some: []const u8,
133+
wick: []const u8,
134+
},
135+
tagged: union(enum) {
136+
pub fn parseYaml(yaml: Yaml, arena: std.mem.Allocator, value: Yaml.Value) Yaml.Error!@This() {
137+
const map = try value.asMap();
138+
139+
inline for (@typeInfo(@This()).@"union".fields) |field| {
140+
if (map.get(field.name)) |entry| {
141+
return @unionInit(@This(), field.name, try yaml.parseValue(arena, field.type, entry));
142+
}
143+
}
144+
145+
return error.TypeMismatch;
146+
}
147+
},
148+
finally: [4]f16,
149+
};
150+
151+
var arena = std.heap.ArenaAllocator.init(gpa);
152+
defer arena.deinit();
153+
154+
const simple = try yaml.parse(arena.allocator(), Simple);
155+
try std.testing.expectEqual(simple.names.len, 3);
156+
```
157+
125158
### Error handling
126159

127160
The library currently reports user-friendly, more informative parsing errors only which are stored out-of-band.

src/Yaml.zig

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub fn parse(self: Yaml, arena: Allocator, comptime T: type) Error!T {
8989
}
9090
}
9191

92-
fn parseValue(self: Yaml, arena: Allocator, comptime T: type, value: Value) Error!T {
92+
pub fn parseValue(self: Yaml, arena: Allocator, comptime T: type, value: Value) Error!T {
9393
return switch (@typeInfo(T)) {
9494
.int => self.parseInt(T, value),
9595
.bool => self.parseBoolean(bool, value),
@@ -109,19 +109,19 @@ fn parseValue(self: Yaml, arena: Allocator, comptime T: type, value: Value) Erro
109109
};
110110
}
111111

112-
fn parseInt(self: Yaml, comptime T: type, value: Value) Error!T {
112+
pub fn parseInt(self: Yaml, comptime T: type, value: Value) Error!T {
113113
_ = self;
114114
const scalar = try value.asScalar();
115115
return try std.fmt.parseInt(T, scalar, 0);
116116
}
117117

118-
fn parseFloat(self: Yaml, comptime T: type, value: Value) Error!T {
118+
pub fn parseFloat(self: Yaml, comptime T: type, value: Value) Error!T {
119119
_ = self;
120120
const scalar = try value.asScalar();
121121
return try std.fmt.parseFloat(T, scalar);
122122
}
123123

124-
fn parseBoolean(self: Yaml, comptime T: type, value: Value) Error!T {
124+
pub fn parseBoolean(self: Yaml, comptime T: type, value: Value) Error!T {
125125
_ = self;
126126
const raw = try value.asScalar();
127127

@@ -145,9 +145,13 @@ fn parseBoolean(self: Yaml, comptime T: type, value: Value) Error!T {
145145
return error.TypeMismatch;
146146
}
147147

148-
fn parseUnion(self: Yaml, arena: Allocator, comptime T: type, value: Value) Error!T {
148+
pub fn parseUnion(self: Yaml, arena: Allocator, comptime T: type, value: Value) Error!T {
149149
const union_info = @typeInfo(T).@"union";
150150

151+
if (@hasDecl(T, "parseYaml")) {
152+
return T.parseYaml(self, arena, value);
153+
}
154+
151155
if (union_info.tag_type) |_| {
152156
inline for (union_info.fields) |field| {
153157
if (self.parseValue(arena, field.type, value)) |u_value| {
@@ -164,16 +168,20 @@ fn parseUnion(self: Yaml, arena: Allocator, comptime T: type, value: Value) Erro
164168
return error.UnionTagMissing;
165169
}
166170

167-
fn parseOptional(self: Yaml, arena: Allocator, comptime T: type, value: ?Value) Error!T {
171+
pub fn parseOptional(self: Yaml, arena: Allocator, comptime T: type, value: ?Value) Error!T {
168172
const unwrapped = value orelse return null;
169173
const opt_info = @typeInfo(T).optional;
170174
return @as(T, try self.parseValue(arena, opt_info.child, unwrapped));
171175
}
172176

173-
fn parseStruct(self: Yaml, arena: Allocator, comptime T: type, map: Map) Error!T {
177+
pub fn parseStruct(self: Yaml, arena: Allocator, comptime T: type, map: Map) Error!T {
174178
const struct_info = @typeInfo(T).@"struct";
175179
var parsed: T = undefined;
176180

181+
if (@hasDecl(T, "parseYaml")) {
182+
return T.parseYaml(self, arena, .{ .map = map });
183+
}
184+
177185
inline for (struct_info.fields) |field| {
178186
var value: ?Value = map.get(field.name) orelse blk: {
179187
const field_name = try mem.replaceOwned(u8, arena, field.name, "_", "-");
@@ -199,7 +207,7 @@ fn parseStruct(self: Yaml, arena: Allocator, comptime T: type, map: Map) Error!T
199207
return parsed;
200208
}
201209

202-
fn parsePointer(self: Yaml, arena: Allocator, comptime T: type, value: Value) Error!T {
210+
pub fn parsePointer(self: Yaml, arena: Allocator, comptime T: type, value: Value) Error!T {
203211
const ptr_info = @typeInfo(T).pointer;
204212

205213
switch (ptr_info.size) {
@@ -218,7 +226,7 @@ fn parsePointer(self: Yaml, arena: Allocator, comptime T: type, value: Value) Er
218226
}
219227
}
220228

221-
fn parseArray(self: Yaml, arena: Allocator, comptime T: type, list: List) Error!T {
229+
pub fn parseArray(self: Yaml, arena: Allocator, comptime T: type, list: List) Error!T {
222230
const array_info = @typeInfo(T).array;
223231
if (array_info.len != list.len) return error.ArraySizeMismatch;
224232

0 commit comments

Comments
 (0)