Skip to content

Fields of type Option<Vec<T>> or Option<HashMap<K, V>> are not serialized if they contain an empty collection #307

@nayuta723

Description

@nayuta723

There is a serialization inconsistency between oci-spec-go and oci-spec-rs regarding empty Maps and Vectors.

  • oci-spec-go: Skips serialization for empty collections due to the omitempty tag.
  • oci-spec-rs: Still serializes empty collections because it only uses #[serde(skip_serializing_if = "Option::is_none")], which doesn't account for empty states."

To address this, there are two potential solutions:

  • Add a custom skip function: Introduce a helper function for skip_serializing_if that checks if the collection is either None or empty. This maintains the current structure but aligns the output with Go's omitempty.
fn is_option_map_empty(opt: &Option<HashMap<String, String>>) -> bool {
    opt.as_ref().map_or(true, |m| m.is_empty())
}

pub struct State {
    /// annotations are key values associated with the container.
    #[serde(default, skip_serializing_if = "is_option_map_empty")]
    annotations: Option<HashMap<String, String>>,
}
  • Remove the Option wrapper: Drop the Option and use HashMap or Vec directly with #[serde(default, skip_serializing_if = "HashMap::is_empty")]. While this makes the code cleaner and more "Rust-idiomatic," it would be a breaking change for users of this crate.
pub struct State {
    /// annotations are key values associated with the container.
    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
    annotations: HashMap<String, String>,
}

I believe using a helper function is the more reasonable approach since removing the Option would have a significant impact as a breaking change. However, if using Option for collections is considered unidiomatic in Rust, I’m also open to the latter option. Which approach would you prefer?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions