I have tried Typetag
and erased_serde
, but it seems they can serialize Box<dyn MyTrait>
, and can not work on Box<dyn MyTrait + Send + Syn>
. Is there other way I can do that?
Heya, you may be able to do something like this:
pub trait MyTraitSerde: MyTrait + Send + Sync + erased_serde::Serialize {}
impl<'a> serde::Serialize for dyn MyTraitSerde + 'a {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
erased_serde::serialize(self, serializer)
}
}
and hold Box<dyn MyTraitSerde>
s.
One of my projects does something like that: see data_type.rs, though I don't understand it well enough to explain what's going on.
It is possible to go from a Box<dyn MyTraitSerde>
to a &dyn MyTrait
(see box_dt_display.rs), so functionally I think you can make it work, but with "more code" being the trade off.
peace
If the types implementing your trait are Send + Sync
you can just make them supertraits of MyTrait
, and then you don't have to worry about the bounds being different.
Are you sure? This worked for me.
trait MyTrait: erased_serde::Serialize {}
erased_serde::serialize_trait_object!(MyTrait);
fn f<T: ?Sized + serde::Serialize>() {}
fn main() {
f::<dyn MyTrait + Send + Sync>();
}
I seems it does not have a compile error, but do have a run time error. The playgound can not use erased_serde. So make a test in my jupyter:
// :dep erased-serde
// :dep serde = { features = ["derive"] }
// :dep bincode = { version = ">= 1.3.3"}
use std::io::{BufWriter, BufReader};
use serde::{Serialize, Deserialize, de::DeserializeOwned};
use bincode;
use erased_serde;
pub trait MyTrait: erased_serde::Serialize {}
erased_serde::serialize_trait_object!(MyTrait);
#[derive(Serialize, Deserialize)]
pub struct MyStruct;
pub fn sof<T: Serialize>(data: &T, name: &str, path: &str) {
let full_path = path.to_owned() + name;
let w = std::fs::File::create(full_path).unwrap();
let mut f = BufWriter::new(w);
bincode::serialize_into(&mut f, &data).unwrap();
}
impl MyTrait for MyStruct {}
fn main() {
let my_struct_box: Box<dyn MyTrait + Send + Sync> = Box::new(MyStruct);
sof(&my_struct_box, "filename", "D:/Rust/");
}
It does compile, but when I call:
main()
[E0599] Error: the method `sof` exists for struct `Box<dyn bt::dcon::A + Send + Sync>`, but its trait bounds were not satisfied
One more asking:
I found that erased_serde
has only method serialize
, but not deserialize
. So when I serialized Box<dyn MyTrait>
, how can I deserialize it back to Box<dyn MyTrait>
?
Your reduced code also compiles and runs for me. What's the full error?
Oh, deserialization needs to know the original type during the deserialization call, so there's:
- "normal deserialization" (probably not what you want), and
- stateful deserialization, where we have something within the serialized information that tells us how to deserialize that serialized information.
In the following example, I have two things:
-
TypeReg<String>
, which can be thought of as aMap<String, FnToDeserializeTheValue>
. - A serialized
Map<String, Box<dyn MyTraitSerde>>
// Here's the map that tells the deserializer how to deserialize the value
let mut type_reg = TypeReg::<String>::new();
type_reg.register::<u32>(String::from("one"));
// Here's the serialized string, wrapped in a Deserializer of the chosen format
let deserializer = serde_yaml::Deserializer::from_str("one: 1");
// This:
let data_u32 = type_reg.deserialize_single(deserializer).unwrap();
// calls:
// serde_tagged::de::external::deserialize(deserializer, self)
// and self is the Map<String, FnToDeserializeTheValue>
// so serde_tagged can read from the map key to get the function
// The deserialized thing is in a Box, but I know it's a `u32`, so I can downcast it
let data_u32 = BoxDataTypeDowncast::<u32>::downcast_ref(&data_u32).copied();
The code for that is in this test + some of the code above. There's also an example on the readme for deserializing many Box<dyn _>
s
Excuse me. I test it in a main.rs
, it do work well. It may be a matter of my jupyter
envrionment problem.