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.
This commit is contained in:
torque 2023-11-23 17:47:21 -08:00
parent e8ddee5ab2
commit 21a9753d46
Signed by: torque
SSH Key Fingerprint: SHA256:nCrXefBNo6EbjNSQhv0nXmEg/VuNq3sMF5b8zETw3Tk
2 changed files with 15 additions and 9 deletions

View File

@ -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

View File

@ -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