From 21a9753d46ceeb37bd1c8cb08ec8d3cf652eade6 Mon Sep 17 00:00:00 2001 From: torque Date: Thu, 23 Nov 2023 17:47:21 -0800 Subject: [PATCH] parser: change omitted value behavior to work with all default values Special casing optional values was a little odd before. Now, the user can supply a default value for any field that may be omitted from the serialized data. This behaves the same way as the stdlib JSON parser as well. --- src/parser.zig | 10 +++++----- src/parser/value.zig | 14 ++++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/parser.zig b/src/parser.zig index 3fc7524..c697fef 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -61,11 +61,11 @@ pub const Options = struct { ignore_extra_fields: bool = true, // Only used by the parseTo family of functions. - // If true, if a struct field is an optional type and the corresponding mapping key - // does not exist, the object field will be set to `null`. By default, if the - // parsed document is missing a mapping key for a given field, an error will be - // raised instead. - treat_omitted_as_null: bool = false, + // If true, if a struct field has a default value associated with it and the + // corresponding mapping key does not exist, the object field will be set to the + // default value. By default, this behavior is enabled, allowing succinct + // representation of objects that have default fields. + allow_omitting_default_values: bool = true, // Only used by the parseTo family of functions. // If true, strings may be coerced into other scalar types, like booleans or diff --git a/src/parser/value.zig b/src/parser/value.zig index 0d27ffc..1503a8e 100644 --- a/src/parser/value.zig +++ b/src/parser/value.zig @@ -208,8 +208,11 @@ pub const Value = union(enum) { inline for (stt.fields) |field| { if (map.get(field.name)) |value| { @field(result, field.name) = try value.convertTo(field.type, allocator, options); - } else if (options.treat_omitted_as_null and @typeInfo(field.type) == .Optional) { - @field(result, field.name) = null; + } else if (options.allow_omitting_default_values) { + if (comptime field.default_value) |def| + @field(result, field.name) = @as(*align(1) const field.type, @ptrCast(def)).* + else + return error.BadValue; } else { return error.BadValue; } @@ -224,8 +227,11 @@ pub const Value = union(enum) { inline for (stt.fields) |field| { if (clone.fetchSwapRemove(field.name)) |kv| { @field(result, field.name) = try kv.value.convertTo(field.type, allocator, options); - } else if (options.treat_omitted_as_null and @typeInfo(field.type) == .Optional) { - @field(result, field.name) = null; + } else if (options.allow_omitting_default_values) { + if (comptime field.default_value) |def| + @field(result, field.name) = @as(*align(1) const field.type, @ptrCast(def)).* + else + return error.BadValue; } else return error.BadValue; } // there were extra fields in the data