Skip to content

Conversation

Mingun
Copy link
Contributor

@Mingun Mingun commented Aug 12, 2023

This PR starts as a refactor of internally tagged enums tests in preparation to updating #1922, but in the process of development, I found some interesting consequences.

The first is that ContentDeserializer and ContentRefDeserializer do what they should not do, namely, determine the validity of certain data when calling deserialization methods. All Deserializer methods are just a hints what data is expected from the deserializer, and the deserializer is not obliged to follow them. It is free to call any Visitor method it sees fit. It is Visitor responsibility to detect if called visit_* method appropriate or not. So I removed all decisions from ContentDeserializer and ContentRefDeserializer about validity of content in certain methods.

This change will allow to make the next step and eliminate all calls to deserialize_any from internally tagged enums. Because this method does not called anymore, this would allow to support internally tagged enums in non-self-describing formats. I've replaced deserialize_any with deserialize_map because:

  • internally tagged enums serialized using serialize_map (for newtype variants) / serialize_struct (for unit and struct variants), that means that deserialization also should expect map
  • deserialization of structs looks the same -- calling Deserializer::deserialize_map or Deserializer::deserialize_struct and provide a visitor with visit_map and visit_seq. This is what both TaggedContentVisitor and InternallyTaggedUnitVisitor provides

The same considerations are used when replacing deserialize_any with deserialize_map for untagged variant; that code path is also called for adjacently tagged enums. Passed visitor supports only visit_map method.

This PR depends on the serde-deprecated/test#31 and I temporary add a [patch] section to use patched version to make tests passable. That is why this PR in a draft stage.

Closes #2187
Replaces #2557

@Mingun Mingun changed the title Internally tagged tests Exhaustive internally tagged tests + support of internally tagged enums in non self-describing formats Aug 12, 2023
@Mingun Mingun force-pushed the internally-tagged-tests branch from 3ea3cc4 to dafede9 Compare August 12, 2023 11:11
@Mingun Mingun force-pushed the internally-tagged-tests branch from a08c600 to a20d574 Compare August 5, 2024 17:48
@Mingun Mingun force-pushed the internally-tagged-tests branch 2 times, most recently from 8fe93e5 to 9702ce1 Compare October 22, 2024 18:42
@Mingun Mingun force-pushed the internally-tagged-tests branch from 9702ce1 to 8222225 Compare December 27, 2024 14:22
@Mingun Mingun force-pushed the internally-tagged-tests branch from 8222225 to 02835cd Compare March 20, 2025 17:32
@Mingun Mingun force-pushed the internally-tagged-tests branch from 02835cd to 86108c7 Compare July 31, 2025 14:20
@max-heller
Copy link

... eliminate all calls to deserialize_any from internally tagged enums. Because this method does not called anymore, this would allow to support internally tagged enums in non-self-describing formats. I've replaced deserialize_any with deserialize_map because:

  • internally tagged enums serialized using serialize_map (for newtype variants) / serialize_struct (for unit and struct variants), that means that deserialization also should expect map

As mentioned in jamesmunns/postcard#125 (comment), I don't think this is compatible with non-self-describing formats--at least postcard--because maps and structs are serialized differently and cannot be distinguished during deserialization:

Postcard serializes structs as a sequence of values (for each field) with no length prefix or field identifiers, whereas it serializes maps as a length prefix followed by key-value pairs. If the Serialize and Deserialize impls for the internally tagged enum both used serialize_map(), I think deserialization would work.

For instance, if variant A is serialized with serialize_struct(), deserialization will fail when it tries to use serialize_map() because there is no length prefix and there are no field identifiers in the serialized data. Worse, actually, it might "successfully" deserialize into garbage output.

Mingun and others added 15 commits September 17, 2025 00:25
…internally_tagged_variant

deserialize_untagged_variant in that place is called when deserialzie_with attribute is set.
In that case it performs special actions that is better to use explicitly in deserialize_untagged_variant
for readability
failures(1):
    newtype_unit
…lize enums

Helper methods visit_content_[seq|map] does the same as [Seq|Map]Deserializer::deserialize_any
and used everywhere except here. Reuse them for consistency
…sibility of the Visitor

Examples of errors produced during deserialization of internally tagged enums in tests
if instead of a Seq/Map a Str("unexpected string") will be provided:

In tests/test_annotations.rs
  flatten::enum_::internally_tagged::tuple:
    before: `invalid type: string "unexpected string", expected tuple variant`
    after : `invalid type: string "unexpected string", expected tuple variant Enum::Tuple`

  flatten::enum_::internally_tagged::struct_from_map:
    before: `invalid type: string "unexpected string", expected struct variant`
    after : `invalid type: string "unexpected string", expected struct variant Enum::Struct`
…zer directly

That is cheap, creating a Content[Ref]Deserializer is a no-op
Deserializer methods are only hints which deserializer is not obliged to follow.
Both TaggedContentVisitor and InternallyTaggedUnitVisitor accepts only
visit_map and visit_seq and that is what derived implementation of Deserialize
does for structs. Therefore it is fine to call deserialize_map here, as that
already did in derived deserialize implementation
…ms in non self-describing formats

Visitor passed to the deserialize_any supports only visit_map method,
so we can always request deserialize_map
@Mingun Mingun force-pushed the internally-tagged-tests branch from 86108c7 to 4800f46 Compare September 16, 2025 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Support internally tagged enums with non-self-describing formats.
2 participants