3

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.

5
  • 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. Commented Apr 12, 2022 at 7:05
  • @cdhowie this is literally this minimal example, and the compiler output... Commented Apr 12, 2022 at 7: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? Commented Apr 12, 2022 at 7: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. Commented Apr 12, 2022 at 7: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. Commented Apr 12, 2022 at 7:18

1 Answer 1

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!

Sign up to request clarification or add additional context in comments.

3 Comments

I've made progress thanks to your answer, but it's not quite complete, I've updated my question
@CertainlyNotAdrian Edited to explain. Though, being a different error, I think you should've post a new question about it.
@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 :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.