Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exhaustive internally tagged tests + support of internally tagged enums in non self-describing formats #2569

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from

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-rs/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 and others added 30 commits August 7, 2023 19:19
Unit variant of externally tagged enum cannot be deserialized from the string
token by itself. It is ContentDeserializer + serde_test::Deserializer that makes
this possible, because serde_test::Deserializer produces Content::Str() from
Token::BorrowedStr() and ContentDeserializer produces unit variant from Content::Str().

The following tokens all produces Content::String(variant):
- Token::String(variant)
- Token::Str(variant)
- Token::UnitVariant { variant, .. }

Token::BorrowedStr(variant) produces Content::Str(variant) that was the real purpose to
use it in test in serde-rs#933. This actually makes this test testing `Content` rather than type itself.

Correct way to represent enum one of:
- [xxxVariant { .. }]
- [Enum { .. }, xxxVariant { variant, .. }]
- [Enum { .. }, String(variant), <variant content>]
- [Enum { .. }, Str(variant), <variant content>]
- [Enum { .. }, BorrowedStr(variant), <variant content>]
(review this commit with "ignore whitespace changes" option on)
Moved:
- test_internally_tagged_bytes                                  => string_and_bytes mod
- test_internally_tagged_struct_variant_containing_unit_variant => struct_variant_containing_unit_variant
- test_internally_tagged_borrow                                 => borrow
- test_enum_in_internally_tagged_enum                           => newtype_variant_containing_externally_tagged_enum
- test_internally_tagged_newtype_variant_containing_unit_struct => newtype_variant_containing_unit_struct

(review this commit with "ignore whitespace changes" option on)
We already have two tests where inner types serialized
as a Struct container and as a Map container. No need yet
another test for a Map container
Moved all except flattened tests:
- test_internally_tagged_enum_with_skipped_conflict    => with_skipped_conflict
- test_internally_tagged_enum_containing_flatten       => containing_flatten
- test_internally_tagged_enum_new_type_with_unit       => newtype_variant_containing_unit
- test_internally_tagged_unit_enum_with_unknown_fields => unit_variant_with_unknown_fields
- test_expecting_message_internally_tagged_enum        => expecting_message
- newtype_variant_containing_unit                   -> newtype_unit
- newtype_variant_containing_unit_struct            -> newtype_unit_struct
- newtype_variant_containing_externally_tagged_enum -> newtype_enum
- struct_variant_containing_unit_variant            -> struct_enum
(review this commit with "ignore whitespace changes" option on)
…internally tagged enum

failures (3) - until serde-rs/test#31 is merged:
    struct_enum::newtype
    struct_enum::struct_
    struct_enum::tuple
In theory, ContentRefDeserializer should have matching implementation,
but handling empty maps and sequences as units breaks some cases with
untagged enums:
- test_untagged_newtype_variant_containing_unit_struct_not_map
@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
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 that passed th the deserialize_any supports only visit_map method,
so we can always requests deserialize_map
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.
1 participant