1

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.

  • 1
    Please provide a minimal example that we can copy and paste to reproduce the problem, or _at the very least_ include the full compiler output. – cdhowie Apr 12 '22 at 07:05
  • @cdhowie this is literally this minimal example, and the compiler output... – CertainlyNotAdrian Apr 12 '22 at 07:08
  • 1
    You use the same name for the trait `DeserializableDocument` and the generic parameter `DeserializableDocument`. Did you mean to write `struct KafkaMessage<'a, D> where D: DeserializableDocuemnt<'a>` or something like that? – Sebastian Redl Apr 12 '22 at 07:13
  • "However upon trying to define the empty trait object DeserializableDocument" - `DeserializableDocument` is a trait, not a trait object. You definitely have quite a few technical terms confused. Your might want to re-read the relevant parts of the documentation about traits and generics. – Sebastian Redl Apr 12 '22 at 07:15
  • @SebastianRedl I think you are correct, I changed the syntax but still get the error. The objective remains the same, I want `Data` to implement `Deserialize` and `Document`. – CertainlyNotAdrian Apr 12 '22 at 07:18

1 Answers1

3

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!

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • I've made progress thanks to your answer, but it's not quite complete, I've updated my question – CertainlyNotAdrian Apr 12 '22 at 07:53
  • 1
    @CertainlyNotAdrian Edited to explain. Though, being a different error, I think you should've post a new question about it. – Chayim Friedman Apr 12 '22 at 08:09
  • @CertainlyNotAdrian, do not update (expand) questions if it is not for a better explanation. For new content is better to open a newly related one :) – Netwave Apr 12 '22 at 08:28