Skip to content

Support flattening Option<T> into the UnionSchema of T #517

@Kriskras99

Description

@Kriskras99

Original issues #449 and #458 by @PookieBuns

Currently the SchemaAware(De)Serializer implementations only support one representation of Option<T>: ["null", T::get_schema()] (order of null and T does not matter). This means that the following schema:

[
    "null",
    "int",
    "string"
]

can only map to the following enum:

enum Example {
    Null,
    Int(i32),
    String(String),
}

It is requested that the following Option would also match this schema:

enum Example {
    Int(i32),
    String(String),
}
Option<Example>

This would require the following changes to the serializer:

  1. In serialize_some and serialize_none: Only require that the current schema is a Schema::Union with a Schema::Null variant
  2. In serialize_some there are two cases to keep in mind:
  • If there are only two variants, serialize using the current implementation.
  • If there are more variants, serialize T using the current union schema but provide a flag to the serializer that the null variant cannot be used. It would be preferable to modify the union schema/create a new union schema so that the null variant does not exist, but as we need a reference to the schema that would mean using a Cow<Schema> everywhere.
  1. In get_resolved_union_variant the logic needs to be modified to correct the index:
  • If the index is before the null variant, it can be used as is
  • If the index is at or after the null variant, the index needs to be incremented by one
  1. UnionSerializer would also need to be changed to ignore the null variant when the flag is set

This would require the following changes to the deserializer:

  1. In deserialize_option:
  • Only require that the current schema is a Schema::Union with a Schema::Null variant
  • If a null is read, then the current logic can be used
  • Otherwise, store the index that was read and visit_some with the current deserializer
  1. In with_union reading the index must be skipped if the index is already set.
  2. In deserialize_enum the UnionEnumDeserializer must be provided with the stored index
  3. In UnionEnumDeserializer::variant_seed the stored index must be used if available

This would require the AvroSchemaComponent implementation for Option<T> to only panic if T::get_schema is a union with a Schema::Null variant, otherwise modify that schema to include Schema::Null.

There is probably more changes needed, but this is what I can think of right now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions