postcard-dyn: support non-string map keys - #303
Open
teddytennant wants to merge 1 commit into
Open
Conversation
serde_json::Value requires object keys to be strings, so postcard-dyn rejected any schema whose map key was not a String. serde_json itself does not have that restriction on the types it will accept as a map key: it stores primitive keys as their string representation instead, so a HashMap<u32, u32> round trips through serde_json but not through postcard-dyn. Do the same thing here for bool, the integer types, and unit variants of an enum, in both directions. Key types serde_json also cannot store as a string still return ShouldSupportButDont.
✅ Deploy Preview for cute-starship-2d9c9b canceled.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
postcard-dynrejects any schema whose map key is not aString, in both directions:serde_json::Valuedoes require object keys to be strings, butserde_jsonitself does not refuse the same types postcard-dyn does — it stores primitive
keys as their string representation. So a
HashMap<u32, u32>round tripsthrough
serde_jsonbut not throughpostcard-dyn.Reproducer from #275:
The change
de_map_key/ser_map_keyhandle keys of the typesserde_jsoncan store asa string —
bool, all the integer types,String, and unit variants of anenum — by going through that string form, and only that string form. The key
still goes down the ordinary
de_named_type/ser_named_typepath for itsschema type, so the wire encoding is unchanged and there is only one place that
knows how each type is encoded.
This is the right layer for it because the mismatch is purely between the
postcard data model and
serde_json::Value, which is exactly what these twofunctions bridge; postcard itself already handles these keys fine.
Types
serde_jsonalso cannot turn into a string key still returnShouldSupportButDontrather than being silently mangled, and that is assertedin the test.
With this, the reproducer above returns
{"map":{"1":1}}, equal to whatserde_json::to_valueproduces for the same struct.Deliberately not changed
charand float keys.serde_jsondoes store those as strings too, butde_named_typehasOwnedDataModelType::Char => todo!(), so acceptingcharkeys would give a serializer the deserializer can't undo, and round tripping a
float through a decimal string is not something I wanted to do silently. Both
are noted in a TODO next to the new code.
The same change is applied to
postcard-dyn-ng, matching how other fixes havebeen mirrored into the
-ngcrates. The two hunks are identical apart from the-ngschema type shapes.Verification
New test
de::test::mapsround trips a map through postcard →Value→postcard for string,
bool,u32,i64and unit-variant-enum keys, assertsthe intermediate
Valuematches whatserde_json::to_valueproduces for thesame map, and asserts a
(u8, u8)key is still rejected by bothfrom_slice_dynand
to_stdvec_dyn.Before the fix (test present, source change reverted):
Note the string-keyed case passes there — that half is the control, and it is
unaffected by this change.
After:
Reverting only the
ser.rshalf and leavingde.rsfixed also fails the test,at the re-serialize step — the round trip catches an asymmetric ser/de rather
than just one direction.
Full
./ci.shfeature set passes:cargo test --allis green across theworkspace (0 failures),
cargo clippy --all --all-targets -- --deny=warningsis clean, and
cargo fmt --all -- --checkis clean.Note on #194
#194 replaces
postcard-dyn'sde.rswholesale with areserialize/module anddrops the
ShouldSupportButDontpath along the way. It has been idle since2025-06, and this is a scoped fix for the specific bug in #275 rather than a
claim on that work — but if #194 lands first, this becomes redundant and should
just be dropped.
Closes #275.