How to save a Box<dyn Trait> varialble to a local file?

I have the following traits and types:

trait MyTrait1 {}
trait MyTrait2 {}
trait MyTrait3 {}
trait MyTrait4 {}

struct MyStruct1<T>(T);
struct MyStruct2<T>(T);
struct MyStruct3<T>(T);
struct MyStruct4<T>(T);

impl<T> MyTrait1 for MyStruct1<T> {}

impl<T: MyTrait1> MyTrait2 for MyStruct2<T> {}

impl<T: MyTrait2> MyTrait3 for MyStruct3<T> {}

impl<T: MyTrait3> MyTrait4 for MyStruct4<T> {}

I try to save the Box variable my_box:

let my_struct1 = MyStruct1(1);
let my_struct2 = MyStruct2(my_struct1);
let my_strcut3 = MyStruct3(my_struct2);
let my_struct4 = MyStruct4(my_struct4);

let my_box: Box<dyn MyTrait4> = Box::new(my_struct4);

I tried to get to this in these ways:

  1. serde + typetag:
#[typetag::serde(tag = "MyTrait1")]
trait MyTrait1 {}

#[derive(Serialize, Deserialize)]
struct MyStruct1<T>(T);

#[typetag::serde]
impl<T> MyTrait1 for MyStruct1<T> {}

But it has the compile error:

error: deserialization of generic impls is not supported yet; use #[typetag::serialize] to generate serialization only

And I need the types to have generic type parameters, so it seems typetag can not work it out.

  1. I save the my_box as a String to a local .txt file, and when I need to load it, I open the file and clone the text then paste it to where it is needed. It works fine in simple example. But when I have a Vec of Box<dyn MyTrait> , the file is too large, approximattly 60000 lines. If have paste the 60000 lines codes to the project, then the compile process take a long time. And besides, the project just can not compile, throw the error like main overflow stack.

  2. Save the my_box as a String to file, and eval the string when it is needed. But in Rust, there is no way to eval a string like in Java.

I have struggled for this for a month, and it seems it is very hard to do this in Rust. I thought the reason maybe that Rust have no runtime and no reflection (I'm new to programming, so the terms maybe wrong). So is there any other way that can help?

You're correct that Rust doesn't have any reflection. A dyn trait erases all information about the type, except only the fact that it implements that trait. This makes serialization of such object impossible, because its data, size, layout, etc. are all a hidden implementation detail, and Rust doesn't leave a way to access it.

The typetag crate does extra work behind the scenes to add methods to the trait to expose concrete types, but as the error message suggests, it doesn't support generic types, i.e. MyStruct<T>. It only allows MyStruct without <T>.

Don't use generics if you use typetag. Or use an enum instead of trait. Or modify the trait yourself to implement serialization yourself, for example add fn to_serde_value(&self) -> serde_json::Value and fn from_serde_value(value: Value) -> Box<dyn Trait> to your traits, and use that for serialization, the hard way.

3 Likes

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.