Handle partial union matches
This commit is contained in:
parent
cd311cfa3c
commit
91edd17801
1 changed files with 14 additions and 9 deletions
|
@ -278,37 +278,42 @@ pub fn DeserializerContext(comptime Result: type, comptime From: type, comptime
|
|||
util.deepFree(allocator, val);
|
||||
}
|
||||
|
||||
const DeserializeError = error{ ParseFailure, MissingField, DuplicateUnionMember, SparseSlice, OutOfMemory };
|
||||
|
||||
fn deserialize(
|
||||
self: *@This(),
|
||||
allocator: std.mem.Allocator,
|
||||
comptime T: type,
|
||||
intermediary: anytype,
|
||||
comptime field_ref: FieldRef,
|
||||
) !?T {
|
||||
) DeserializeError!?T {
|
||||
if (comptime Context.options.isScalar(T)) {
|
||||
const val = @field(intermediary.static, util.comptimeJoin(".", field_ref));
|
||||
return try self.context.deserializeScalar(allocator, T, val orelse return null);
|
||||
return self.context.deserializeScalar(allocator, T, val orelse return null) catch return error.ParseFailure;
|
||||
}
|
||||
|
||||
switch (@typeInfo(T)) {
|
||||
// At most one of any union field can be active at a time, and it is embedded
|
||||
// in its parent container
|
||||
// At most one of any union field can be active at a time
|
||||
.Union => |info| {
|
||||
var result: ?T = null;
|
||||
errdefer if (result) |v| self.deserializeFree(allocator, v);
|
||||
// TODO: errdefer cleanup
|
||||
const union_ref: FieldRef = if (Context.options.embed_unions) field_ref[0 .. field_ref.len - 1] else field_ref;
|
||||
var partial_match_found: bool = false;
|
||||
inline for (info.fields) |field| {
|
||||
const F = field.field_type;
|
||||
const new_field_ref = union_ref ++ &[_][]const u8{field.name};
|
||||
const maybe_value = try self.deserialize(allocator, F, intermediary, new_field_ref);
|
||||
const maybe_value = self.deserialize(allocator, F, intermediary, field_ref) catch |err| switch (err) {
|
||||
error.MissingField => blk: {
|
||||
partial_match_found = true;
|
||||
break :blk @as(?F, null);
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
if (maybe_value) |value| {
|
||||
// TODO: errdefer cleanup
|
||||
errdefer self.deserializeFree(allocator, value);
|
||||
if (result != null) return error.DuplicateUnionMember;
|
||||
result = @unionInit(T, field.name, value);
|
||||
}
|
||||
}
|
||||
if (partial_match_found and result == null) return error.MissingField;
|
||||
return result;
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in a new issue