Can I serialize a Box<dyn MyTrait + Send + Sync> with using Serde?

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>
        S: serde::Serializer,
        erased_serde::serialize(self, serializer)

and hold Box<dyn MyTraitSerde>s.

One of my projects does something like that: see, 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, so functionally I think you can make it work, but with "more code" being the trade off.

peace :v:

1 Like

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 {}

fn f<T: ?Sized + serde::Serialize>() {}

fn main() {
    f::<dyn MyTrait + Send + Sync>();
1 Like

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 {}

#[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:

[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?

1 Like

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 a Map<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();

// 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

1 Like

Excuse me. I test it in a, it do work well. It may be a matter of my jupyter envrionment problem.