dtolnay / typetag

Serde serializable and deserializable trait objects
Apache License 2.0
1.19k stars 38 forks source link

Trait objects with marker traits #7

Closed cwhakes closed 5 years ago

cwhakes commented 5 years ago

I am trying to serialize/deserialize a global trait object, but it appears that the Serialize/Deserialize implementations aren't being implemented for marker traits.

Example:

use std::sync::{Arc, Mutex};

use lazy_static::lazy_static;
use serde::{Serialize, Deserialize};

lazy_static! {
    static ref DATA: Data = Data::new(Box::new(MyType) as Box<MyTrait + Send>);
}

#[derive(Serialize, Deserialize)]
struct Data ( Arc<Mutex<Box<dyn MyTrait + Send>>> );

#[derive(Serialize, Deserialize)]
struct MyType;

#[typetag::serde(tag = "type")]
trait MyTrait {}

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

impl Data {
    fn new(my_trait: Box<dyn MyTrait + Send>) -> Data {
        Data(Arc::new(Mutex::new(my_trait)))
    }
}

This generates the error(s):

error[E0277]: the trait bound `(dyn MyTrait + std::marker::Send + 'static): _IMPL_DESERIALIZE_FOR_Data::_serde::Serialize` is not satisfied
  --> src\main.rs:11:15
   |
11 | struct Data ( Arc<Mutex<Box<dyn MyTrait  + Send>>> );
   |               ^^^ the trait `_IMPL_DESERIALIZE_FOR_Data::_serde::Serialize` is not implemented for `(dyn MyTrait + std::marker::Send + 'static)`
   |
   = help: the following implementations were found:
             <(dyn MyTrait + 'typetag) as _IMPL_DESERIALIZE_FOR_Data::_serde::Serialize>
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Serialize` for `std::boxed::Box<(dyn MyTrait + std::marker::Send + 'static)>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Serialize` for `std::sync::Mutex<std::boxed::Box<(dyn MyTrait + std::marker::Send + 'static)>>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Serialize` for `std::sync::Arc<std::sync::Mutex<std::boxed::Box<(dyn MyTrait + std::marker::Send + 'static)>>>`
   = note: required by `_IMPL_DESERIALIZE_FOR_Data::_serde::Serializer::serialize_newtype_struct`

error[E0277]: the trait bound `dyn MyTrait + std::marker::Send: _IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` is not satisfied
  --> src\main.rs:11:15
   |
11 | struct Data ( Arc<Mutex<Box<dyn MyTrait  + Send>>> );
   |               ^^^ the trait `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` is not implemented for `dyn MyTrait + std::marker::Send`
   |
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::boxed::Box<dyn MyTrait + std::marker::Send>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::sync::Mutex<std::boxed::Box<dyn MyTrait + std::marker::Send>>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::boxed::Box<std::sync::Mutex<std::boxed::Box<dyn MyTrait + std::marker::Send>>>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::sync::Arc<std::sync::Mutex<std::boxed::Box<dyn MyTrait + std::marker::Send>>>`
   = note: required by `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize::deserialize`

error[E0277]: the trait bound `dyn MyTrait + std::marker::Send: _IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` is not satisfied
  --> src\main.rs:11:15
   |
11 | struct Data ( Arc<Mutex<Box<dyn MyTrait  + Send>>> );
   |               ^^^ the trait `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` is not implemented for `dyn MyTrait + std::marker::Send`
   |
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::boxed::Box<dyn MyTrait + std::marker::Send>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::sync::Mutex<std::boxed::Box<dyn MyTrait + std::marker::Send>>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::boxed::Box<std::sync::Mutex<std::boxed::Box<dyn MyTrait + std::marker::Send>>>`
   = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Data::_serde::Deserialize<'_>` for `std::sync::Arc<std::sync::Mutex<std::boxed::Box<dyn MyTrait + std::marker::Send>>>`
   = note: required by `_IMPL_DESERIALIZE_FOR_Data::_serde::de::SeqAccess::next_element`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
error: Could not compile `typetag-test`.
dtolnay commented 5 years ago

I think you would need Send as a supertrait in order to do the deserialization.

#[typetag::serde(tag = "type")]
trait MyTrait: Send {}

Otherwise, if you allow implementations of MyTrait that do not implement Send, the trait system does not have a way to weed out those implementations when deserializing into Box\<MyTrait + Send>.

cwhakes commented 5 years ago

I had tried to add Send as a supertrait before, but that didn't work. Including the Send as a supertrait and modifying Data to not need it worked.

#[derive(Serialize, Deserialize)]
struct Data ( Arc<Mutex<Box<dyn MyTrait>>> );
dtolnay commented 5 years ago

Both Box<dyn MyTrait> and Box<dyn MyTrait + Send> should work equivalently as of typetag 0.1.2 if you have Send as a supertrait -- but the second is redundant anyway when we already know all implementations of MyTrait are Send from the supertrait bound. Glad you got it working!