Serializing and Deserializing between modules in complicated situation

I have two modules crate_old and crate_new:

/*
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
typetag = "*"
*/

pub mod crate_old {
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub struct MyStruct(
        #[serde()]
        pub usize
    );

    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub struct MyStructAppend(
        pub usize,
        pub usize
    );

    #[typetag::serde(tag = "MyTrait", content = "value")]
    pub trait MyTrait {}

    #[typetag::serde]
    impl MyTrait for MyStruct {}

    #[typetag::serde(tag = "RealStruct", content = "value")]
    pub trait RealStruct {}

    #[typetag::serde]
    impl RealStruct for MyStruct {}

    #[typetag::serde]
    impl RealStruct for MyStructAppend {}
}

pub mod crate_new {
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Clone, Serialize, Deserialize)]
    #[serde(untagged)]
    pub enum RealStruct {
        MyStruct(usize),
        MyStructAppend(usize, usize),
    }

    #[typetag::serde(tag = "MyTrait", content = "value")]
    pub trait MyTrait {}

    #[typetag::serde]
    impl MyTrait for RealStruct {}
}

fn main() {
    let crate1_box: Box<dyn crate_old::MyTrait> = Box::new(crate_old::MyStruct(10));
    let crate1_box_str = serde_json::to_string(&crate1_box).unwrap();
    assert_eq!(crate1_box_str, r#"{"MyTrait":"MyStruct","value":10}"#);

    let crate2_box: Box<dyn crate_new::MyTrait> = Box::new(crate_new::RealStruct::MyStruct(10));
    let crate2_box_str = serde_json::to_string(&crate2_box).unwrap();
}

In each of the modules, there is a type MyStruct. In the old crate, it is a struct, and in the new one it is a enum which has an viriant RealStruct, which has the same struct as the MyStruct in crate_old.

I get a serialized object in the crate_old:

let crate1_box: Box<dyn crate_old::MyTrait> = Box::new(crate_old::MyStruct(10));
let crate1_box_str = serde_json::to_string(&crate1_box)?;
"{\"MyTrait\":\"MyStruct\",\"value\":10}"

In crate_new, I have the following object:

let crate2_box: Box<dyn crate_new::MyTrait> = Box::new(crate_new::RealStruct::MyStruct(10));
let crate2_box_str = serde_json::to_string(&crate2_box)?;
"{\"MyTrait\":\"RealStruct\",\"value\":10}"

How can I deserialize crate1_box_str to an object the same as crate2_box in crate_new? I thought it may need custom deserialize typetag, but I can't find how. to do it.

I'm sorry, but I don't understand your problem. I feel like the solution @H2CO3 gave you here:

should work in this case, too. Maybe your real-world code has some extra difficulties not covered in your example? Even with typetag, using the #[serde(untagged)] attribute on crate_new::MyStruct allows you to deserialize crate1_box_str as Box<dyn crate_new::MyTrait>:

/*
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
typetag = "*"
*/

pub mod crate_old {
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub struct MyStruct(
        #[serde()]
        pub usize
    );

    #[typetag::serde(tag = "MyTrait", content = "value")]
    pub trait MyTrait {}

    #[typetag::serde]
    impl MyTrait for MyStruct {}
}

pub mod crate_new {
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Clone, Serialize, Deserialize)]
    #[serde(untagged)]
    pub enum MyStruct {
        RealStruct(usize),
    }

    #[typetag::serde(tag = "MyTrait", content = "value")]
    pub trait MyTrait {}

    #[typetag::serde]
    impl MyTrait for MyStruct {}
}

fn main() {
    let crate1_box: Box<dyn crate_old::MyTrait> = Box::new(crate_old::MyStruct(10));
    let crate1_box_str = serde_json::to_string(&crate1_box).unwrap();
    assert_eq!(crate1_box_str, r#"{"MyTrait":"MyStruct","value":10}"#);

    let crate2_box: Box<dyn crate_new::MyTrait> = Box::new(crate_new::MyStruct::RealStruct(10));
    let crate2_box_str = serde_json::to_string(&crate2_box).unwrap();
    assert_eq!(crate2_box_str, crate1_box_str);

    let crate2_box: Box<dyn crate_new::MyTrait> = serde_json::from_str(&crate1_box_str).unwrap();
}

Rustexplorer.

2 Likes

My bad, I got the type name RealStruct and MyStruct backwards in crate_new, it should be:

//crate_new
pub enum RealStruct {
     MyStruct(usize)
}

rather than the old one:

//crate_new
pub enum MyStruct {
     RealStruct(usize)
}

I made the correction on the problem above, and this is the Rustexplorer.

The real-word difficulties I am facing is that:
I have an old crate crate_old, it has a trait RealStruct, I implemented it to two types MyStruct and MyStructAppend. And I serialized some objects of instance of Box<dyn RealStruct>.
Later, I was building a new crate crate_new, and I tried to make the trait RealStruct into an enum

pub enum RealStruct {
    MyStruct(usize),
    MyStructAppend(usize, usize),
}

And I found if I need to deserialize the saved objects, I need to change the serialize method too. Then I got the problem.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.