Skip to content

Derived "apply" implementation for enums is broken #35

Open
@Diggsey

Description

@Diggsey

When diffing an enum like:

#[derive(SerdeDiff, Serialize, Deserialize, Debug, PartialEq, Clone)]
enum Value {
    Str(String),
    Int(i32),
}

Let's say we have the diff Value::Str("A") -> Value::Str("B").

The diff implementation will produce the following sequence of commands:

[{"Enter":{"EnumVariant":"Str"}},{"Enter":{"FieldIndex":0}},{"Value":"B"},"Exit"]

However, the apply implementation does not consume the final Exit command, causing the rest of the command stream to get out of sync.

This is because of this code:

fn apply<'de, A>(
&mut self,
seq: &mut A,
ctx: &mut serde_diff::ApplyContext,
) -> Result<bool, <A as serde_diff::_serde::de::SeqAccess<'de>>::Error>
where
A: serde_diff::_serde::de::SeqAccess<'de>, {
let mut __changed__ = false;
match (self, ctx.next_path_element(seq)?) {
(this, Some(serde_diff::DiffPathElementValue::FullEnumVariant)) => {
ctx.read_value(seq, this)?;
__changed__ = true;
}
#(#apply_match_arms)*
_ => ctx.skip_value(seq)?,
}
Ok(__changed__)
}

Specifically it's because next_path_element is only called once, instead of being called until it finds an Exit command. It makes sense to only call it once because an enum can only have one variant, but since the variant still counts as a path segment, an additional Exit should be consumed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions