Вывод Serde's Serialize или Deserialize заставляет универсальный тип быть сериализуемым, хотя это не обязательно - PullRequest
0 голосов
/ 26 апреля 2018

Мой тип A, который может содержать все, что реализует trait Trait, является сериализуемым, хотя тип, реализующий черту Trait, может и не быть. В моем случае это не может быть - это закрытый асимметричный ключ:

extern crate serde;
#[macro_use]
extern crate serde_derive;

use serde::de::DeserializeOwned;
use serde::Serialize;

trait Trait {
    type SerialisableType: Clone + Serialize + DeserializeOwned;

    fn inner(&self) -> &Self::SerialisableType;
}

#[derive(Serialize, Deserialize)]
enum A<T: Trait> {
    Variant0(B<T>), // *** NOTE: Compiles if this is commented ***
    Variant1(T::SerialisableType),
}

#[derive(Serialize, Deserialize)]
struct B<T: Trait> {
    inner: T::SerialisableType,
}

// ==============================================

struct NonSerialisable {
    serialisable: Serialisable,
}

impl Trait for NonSerialisable {
    type SerialisableType = Serialisable;

    fn inner(&self) -> &Self::SerialisableType {
        &self.serialisable
    }
}

#[derive(Clone, Serialize, Deserialize)]
struct Serialisable(Vec<u8>);

#[derive(Serialize, Deserialize)]
enum E {
    Variant0(A<NonSerialisable>),
    Variant1(B<NonSerialisable>),
}

fn main() {}

площадка

Это ошибка с:

error[E0277]: the trait bound `NonSerialisable: serde::Serialize` is not satisfied
  --> src/main.rs:43:10
   |
43 | #[derive(Serialize, Deserialize)]
   |          ^^^^^^^^^ the trait `serde::Serialize` is not implemented for `NonSerialisable`
   |
   = note: required because of the requirements on the impl of `serde::Serialize` for `A<NonSerialisable>`
   = note: required by `serde::Serializer::serialize_newtype_variant`

error[E0277]: the trait bound `NonSerialisable: serde::Deserialize<'_>` is not satisfied
  --> src/main.rs:43:21
   |
43 | #[derive(Serialize, Deserialize)]
   |                     ^^^^^^^^^^^ the trait `serde::Deserialize<'_>` is not implemented for `NonSerialisable`
   |
   = note: required because of the requirements on the impl of `serde::Deserialize<'_>` for `A<NonSerialisable>`
   = note: required by `serde::de::VariantAccess::newtype_variant`

Если я закомментирую A::Variant0, как указано в встроенном комментарии в коде, то он скомпилируется нормально. Это заставляет меня думать, что компилятор не может сделать вывод о том, что B<T> является сериализуемым, но затем он действительно может вывести это, поскольку он может выяснить, что E является сериализуемым, что потребует также B для сериализации.

Где проблема?

1 Ответ

0 голосов
/ 26 апреля 2018

Во время раскрытия макроса компилятор еще не определил, какой B упоминается внутри Variant0 или как этот B может использовать параметры своего типа. Таким образом, расширение макроса выводит границы признаков, которые будут работать для наиболее распространенных случаев того, что может быть B, например, если бы B было Box или Vec. В этих случаях для сериализации B<T> потребуется T: Serialize, а для десериализации B<T> потребуется T: Deserialize<'de>.

Вы можете предоставить рукописные границы родового типа для замены предполагаемых границ.

#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
enum A<T: Trait> {
    Variant0(B<T>),
    Variant1(T::SerialisableType),
}
...