Trying to implement FromRedisValue for struct with generic type

Greetings!

I am trying to make a struct with a generic value T, which are bound by only using types that already implement FromRedisValue. I thought this would be easy to do, but clearly it is something here that I fully understand. Based on other posts I found on this forum, this is my current solution.

use redis::{RedisResult, ErrorKind, from_redis_value, JsonAsyncCommands, AsyncCommands, FromRedisValue, ToRedisArgs, RedisWrite};
use serde_json::json;
use redis::{Commands, Value};
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct Test<T> where
    T: Serialize + FromRedisValue + for<'a> Deserialize<'a> {
    name: T,
    age: Option<i32>,
}

fn convert<T>(v: &Value) -> RedisResult<T>
where
    T: Serialize + FromRedisValue + for<'a> Deserialize<'a>,
{
    let json_str: String = from_redis_value(v)?;

    let result: RedisResult<T> = match serde_json::from_str::<T>(&json_str) {
        Ok(v) => v,
        Err(_err) => return Err((ErrorKind::TypeError, "Parse to JSON Failed").into()),
    };

    Ok(result)
}

impl<T: Serialize + FromRedisValue + for<'a> Deserialize<'a>> FromRedisValue for Test<T> {
    fn from_redis_value(v: &Value) -> RedisResult<Self> {
        convert(v)
    }
}

However, this does not compile, and give me this error:



error[E0283]: type annotations needed: cannot satisfy `T: Deserialize<'_>`
 --> src/main.rs:7:8
  |
7 | struct Test<T> where
  |        ^^^^^^^
  |
note: multiple `impl`s or `where` clauses satisfying `T: Deserialize<'_>` found
 --> src/main.rs:6:28
  |
6 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^
7 | struct Test<T> where
8 |     T: Serialize + FromRedisValue + for<'a> Deserialize<'a> {
  |                                     ^^^^^^^^^^^^^^^^^^^^^^^
note: required for `Test<T>` to implement `Deserialize<'de>`
 --> src/main.rs:6:28
  |
6 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
7 | struct Test<T> where
  |        ^^^^^^^
  = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0283]: type annotations needed: cannot satisfy `T: Deserialize<'de>`
 --> src/main.rs:6:28
  |
6 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^
  |
note: multiple `impl`s or `where` clauses satisfying `T: Deserialize<'de>` found
 --> src/main.rs:6:28
  |
6 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^
7 | struct Test<T> where
8 |     T: Serialize + FromRedisValue + for<'a> Deserialize<'a> {
  |                                     ^^^^^^^^^^^^^^^^^^^^^^^
  = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0283]: type annotations needed: cannot satisfy `T: Deserialize<'_>`
 --> src/main.rs:6:28
  |
6 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^
  |
note: multiple `impl`s or `where` clauses satisfying `T: Deserialize<'_>` found
 --> src/main.rs:6:28
  |
6 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^
7 | struct Test<T> where
8 |     T: Serialize + FromRedisValue + for<'a> Deserialize<'a> {
  |                                     ^^^^^^^^^^^^^^^^^^^^^^^
note: required for `__Visitor<'de, T>` to implement `Visitor<'de>`
 --> src/main.rs:6:28
  |
6 | #[derive(Debug, Serialize, Deserialize)]
  |                            ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
  = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

What exactly is happening here, and how come "multiple impls or where clauses satisfying T: Deserialize<'_> found"?
At this point I realize that I am so confused that I do not understand what I don't understand...:rofl:

What happens when you remove the for <'a> Deserialize<'a> bound from T in your struct declaration?

#[derive(Debug, Serialize, Deserialize)]
struct Test<T> where
-   T: Serialize + FromRedisValue + for<'a> Deserialize<'a> {
+   T: Serialize + FromRedisValue {
    name: T,
    age: Option<i32>,
}

The derive(Deserialize) macro adds for<'a> Deserialize<'a> to your generic parameters automatically, causing you to have this bound two times on T.

2 Likes

Thank you very much, that makes sense and works.

1 Like