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

Deserialzing untagged versions should default to latest version (not earliest) #8

Open
joaoantoniocardoso opened this issue Jul 22, 2022 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@joaoantoniocardoso
Copy link

joaoantoniocardoso commented Jul 22, 2022

Hi! This library is so useful, but I'm failing to use it with serde_json. I've tried the following way:

use serde_json::json;
use obake;

#[obake::versioned]
#[obake(version("0.1.0"))]
#[obake(version("0.2.0"))]
#[obake(version("0.3.0"))]
#[obake(derive(Debug, PartialEq, serde::Serialize, serde::Deserialize))]
#[obake(serde(untagged))]
#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
struct Character {
    name: String,
    age: u32,
    #[obake(cfg(">=0.2.0"))]
    height: f32,
    #[obake(cfg(">=0.3.0"))]
    weight: f32,
}

impl From<Character!["0.1.0"]> for Character!["0.2.0"] {
    fn from(old: Character!["0.1.0"]) -> Self {
        Self {
            name: old.name,
            age: old.age,
            ..Default::default()
        }
    }
}

impl From<Character!["0.2.0"]> for Character!["0.3.0"] {
    fn from(old: Character!["0.2.0"]) -> Self {
        Self {
            name: old.name,
            age: old.age,
            height: old.height,
            ..Default::default()
        }
    }
}

fn main() {}

#[cfg(test)]
mod tests {
    use serde_json::json;
    use crate::*;

    #[test]
    fn from_2_to_3() {
        let freeza_ser = serde_json::to_string_pretty(&json!({
            "name": "Freeza",
            "age": 32,
            "height": 1.53,
        })).unwrap();
        dbg!(&freeza_ser);

        let freeza: VersionedCharacter = serde_json::from_str(&freeza_ser).unwrap();
        dbg!(&freeza);
        let freeza: Character = freeza.into();
        dbg!(&freeza);

        let freeza_expected = Character {
            name: "Freeza".into(),
            age: 32,
            height: 1.53,
            weight: 0.,
        };
        assert_eq!(&freeza_expected, &freeza);
    }
}

The output is:

failures:

---- tests::from_2_to_3 stdout ----
[src/main.rs:56] &freeza_ser = "{\n  \"age\": 32,\n  \"height\": 1.53,\n  \"name\": \"Freeza\"\n}"
[src/main.rs:59] &freeza = Character_v0_1_0(
    Character_v0_1_0 {
        name: "Freeza",
        age: 32,
    },
)
[src/main.rs:61] &freeza = Character_v0_3_0 {
    name: "Freeza",
    age: 32,
    height: 0.0,
    weight: 0.0,
}
thread 'tests::from_2_to_3' panicked at 'assertion failed: `(left == right)`
  left: `Character_v0_3_0 { name: "Freeza", age: 32, height: 1.53, weight: 0.0 }`,
 right: `Character_v0_3_0 { name: "Freeza", age: 32, height: 0.0, weight: 0.0 }`', src/main.rs:69:9

So, the current behavior is that serde_json::from_str::<VersionedCharacter>(&freeza_ser) is deserializing into the first version, and I want it to deserialize like the following:

fn character_parser(serialized_data: &String) -> Character {
    if let Ok(data) = serde_json::from_str::<Character!["0.3.0"]>(&serialized_data) {
        return data;
    }

    if let Ok(data) = serde_json::from_str::<Character!["0.2.0"]>(&serialized_data) {
        let data: Character!["0.3.0"] = data.into();
        return data;
    }

    if let Ok(data) = serde_json::from_str::<Character!["0.1.0"]>(&serialized_data) {
        let data: Character!["0.2.0"] = data.into();
        let data: Character!["0.3.0"] = data.into();
        return data;
    }

    return Character::default();
}

Am I missing something crucial here? Is there any way for this lib to implement that parsing automatically?

Thank you!

@doctorn
Copy link
Owner

doctorn commented Aug 25, 2022

This is very interesting thank you! I believe the issue has to do with the ambiguity caused by untagged. The behaviour you're observing is that the deserializer is trying earlier versions first, when in actual fact we'd like it to try later versions first. I'll have a look at this as soon as possible!

@doctorn doctorn self-assigned this Aug 25, 2022
@doctorn doctorn added the bug Something isn't working label Aug 25, 2022
@doctorn doctorn changed the title How to use it with serde_json? Deserialzing untagged versions should default to latest version (not earliest) Aug 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants