You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: emit #[serde(default)] without skip_serializing_if for required fields with intrinsic Rust defaults
When a schema marks a field `required` but its Rust type has an
intrinsic default (`Vec`, `HashMap`, `Option<T>`), the previous code
went through PR oxidecomputer#918's path and emitted both `#[serde(default)]` and
`skip_serializing_if`. That made deserialize lenient (`{}` parses) but
also silently dropped the field from serialize output when empty —
which violates the schema's wire contract: a `required` field must
always be present.
Introduces a new `StructPropertyState::RequiredWithDefault` that
splits the two halves: emit `#[serde(default)]` alone, so deserialize
stays lenient while serialize always renders the field. The promotion
from `Optional` happens in `convert_struct_property` only when the
field is in the schema's required array.
Tests:
- New fixture `typify/tests/schemas/required-with-implicit-defaults.json`
covering required Vec / Map (with and without explicit empty default)
and mixed required/optional structs. Verifies via expectorate that
required fields emit `#[serde(default)]` only and optional ones keep
`skip_serializing_if`.
- Five runtime tests in `typify-test/src/main.rs` proving:
- `from_str("{}")` succeeds (lenient deserialize)
- serializing the default emits required fields with empty values
- optional empty fields are still skipped
- serialize → deserialize round-trip preserves content
Fixture diffs in `github.out`, `vega.out`, and four workspace fixtures
are intentional ripple effects: every required Vec/Map/Option field in
the corpus loses its `skip_serializing_if` clause.
Wire-format change documented in CHANGELOG: payloads that previously
omitted empty required fields will now render them as `[]`, `{}`, or
`null`.
Copy file name to clipboardExpand all lines: CHANGELOG.adoc
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,6 +16,7 @@
16
16
=== Bug fixes
17
17
* fix untagged enum variant ordering: Integer now comes before Number to prevent unreachable deserialization (#991)
18
18
* generate `Default` impl for structs where all required fields have explicit defaults (#918)
19
+
* honour the JSON Schema `required` contract on serialization for fields whose Rust type has an intrinsic default (`Vec`, `HashMap`, `Option<T>`). Previously an empty/`None` required field was silently omitted because `skip_serializing_if` was applied; now `#[serde(default)]` is emitted alone, so deserialize stays lenient (`{}` parses) but serialize always renders the field. **Wire-format change**: payloads that previously omitted empty required fields will now render them as `[]`, `{}`, or `null`
19
20
* generate `TryFrom` instead of `From` for bounded integer newtypes, enforcing min/max constraints (#986)
20
21
* render integer `minimum`/`maximum` as integers (not floats) in doc comments (#843)
21
22
* handle special characters in enum variant names (`=`, `>`, `≥`, etc.) without panicking (#948)
0 commit comments