CertainlyNotAdrian
CertainlyNotAdrian

Reputation: 377

Rust struct field that implements multiple traits

I'm trying to implement a struct that holds a field which implements two traits:

use meilisearch_sdk::document::Document;
use serde::{Serialize,Deserialize};


trait DeserializableDocument<'a>: Deserialize<'a> + Document{}


#[derive(Serialize, Deserialize, Debug)]
pub struct KafkaMessage<'a, DeserializableDocument>{
    Data: &'a DeserializableDocument,
}

Where the following struct would satisfy Data:

#[derive(Serialize, Deserialize, Debug)]
pub struct User {
    ID: String,
    Firstname: String,
    Lastname: String,
}

impl Document for User {
    type UIDType = String;
    fn get_uid(&self) -> &Self::UIDType { &self.ID }
}

However upon trying to define the empty trait object DeserializableDocument I get the following error:

type annotations needed

cannot infer type for type parameter `Self`

note: cannot satisfy `Self: <my-project>::documents::_::_serde::Deserialize<'a>`
[dependencies]
serde = { version="1.0",   features = ["derive"] }
meilisearch-sdk = "0.15"

What is the correct way to approach this?

Edit 1:

When restructured according to @ChayimFriedman answer and @SebastianRedl comment:

#[derive(Serialize, Deserialize, Debug)]
pub struct KafkaMessage<D> where D: Document {
    Data: D,
}

I get the following compiler error:

type annotations needed for `std::option::Option<D>`

consider giving `__field1` the explicit type `std::option::Option<D>`, where the type parameter `D` is specified

Ofcourse, specifying D: Option<D> doesn't resolve it either.

Upvotes: 3

Views: 1717

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 71440

Document already includes the Self: DeserializeOwned bound, and DeserializeOwned is basically for<'a> Deserialize<'a> (and also has this bound). So you basically requested the compiler to satisfy:

trait DeserializableDocument<'a>: Deserialize<'a> + for<'b> Deserialize<'b> {}

Or, generalized:

trait Trait<'a> {}
trait Foo<'a>: Trait<'a> + for<'b> Trait<'b> {}

This produces the same error:

error[E0283]: type annotations needed
 --> src/lib.rs:2:16
  |
2 | trait Foo<'a>: Trait<'a> + for<'b> Trait<'b> {}
  |                ^^^^^^^^^ cannot infer type for type parameter `Self`
  |
  = note: cannot satisfy `Self: Trait<'a>`

I don't know why this error happens (it sound trivial to prove that if Trait<'a> is implemented for any lifetime 'a then Trait<'a> is implemented for some lifetime 'a) Edit: this is a compiler bug: #844351, but since DeserializeOwned implies any lifetime for Deserialize<'a>, you can just omit that bound:

trait DeserializableDocument: Document {}

Edit: As for your new error, it is exactly the same reason. The #[derive(Deserialize)] is expanding to something like:

impl<'de, D> Deserialize<'de> for KafkaMessage<D>
where
    D: Document,
    D: Deserialize<'de>,
{
    // ...
}

Which like we already learn, is essentially the same as:

impl<'de, D> Deserialize<'de> for KafkaMessage<D>
where
    D: for<'a> Deserialize<'a>,
    D: Deserialize<'de>,
{
    // ...
}

And again we see the conflict.

The best advice I can give is to just not put the where bounds on the struct, but rather on the impls. Putting bounds on the struct is a bad idea anyway.


1. Thanks @steffahn for helping to find it out at users.rust-lang.org!

Upvotes: 3

Related Questions