Serde: type annotations needed: cannot resolve `_: serde::Deserialize<'_>`

Hi, I am trying to write a customized serde deserializer for a Vec that contains something that could be converted into a base64 string. Unfortunately I get a "type annotations needed" compilation error that I can't manage to fix.

Strangely enough, if I attempt to do about the same thing with a map instead of a Vec, things compile correctly. (You can see the compiling map example at the playground link)

Playground link

This is the relevant code for the custom deserializer:

pub mod ser_vec_b64 {
    use super::*;

    pub fn deserialize<'de, T, V, D>(deserializer: D) -> Result<V, D::Error>
    where
        D: Deserializer<'de>,
        T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>,
        V: Default + Extend<T>,
    {
        struct SeqVisitor<T, V> {
            item: PhantomData<T>,
            seq: PhantomData<V>,
        }

        impl<'de, T, V> Visitor<'de> for SeqVisitor<T, V>
        where
            T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>,
            V: Default + Extend<T>,
        {
            type Value = V;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("A vector")
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: SeqAccess<'de>,
            {
                let mut res_vec: V = V::default();
                while let Some(str_item) = seq.next_element::<String>()? {
                    let vec = base64::decode_config(&str_item, URL_SAFE_NO_PAD)
                        .map_err(|err| Error::custom(err.to_string()))?;
                    let item = T::try_from(&vec).map_err(|_| Error::custom("Length mismatch"))?;
                    res_vec.extend(Some(item));
                }
                Ok(res_vec)
            }
        }

        let visitor = SeqVisitor {
            item: PhantomData,
            seq: PhantomData,
        };
        deserializer.deserialize_seq(visitor)
    }
}

And this is an example struct:

#[derive(Deserialize)]
struct MyVecStruct {
    #[serde(deserialize_with = "ser_vec_b64::deserialize")]
    my_vec: Vec<[u8; 16]>,
}

I get this compilation error:

$ cargo run
   Compiling check_serde_vec v0.1.0 (/home/real/projects/rust_check/check_serde_vec)
error[E0283]: type annotations needed: cannot resolve `_: serde::Deserialize<'_>`
   --> src/main.rs:124:32
    |
74  |     pub fn deserialize<'de, T, V, D>(deserializer: D) -> Result<V, D::Error>
    |            -----------
...
77  |         T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>,
    |            ---------------- required by this bound in `ser_vec_b64::deserialize`
...
124 |     #[serde(deserialize_with = "ser_vec_b64::deserialize")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^

I tried to expand the macros using cargo expand, but I didn't manage to spot any important difference between the two cases of Vec and HashMap. I suspected that the issue has something to do with this expression: for<'t> TryFrom<&'t [u8]>, but even when I tried to modify or remove it in various way I couldn't convince the compiler to compile the MyVecStruct.

Any help is appreciated!

Shouldn't it be &'de [u8], instead of &'t [u8]?

If you take a look at the doc for Vec, you'll find these:

impl<'a, T> Extend<&'a T> for Vec<T> where
    T: 'a + Copy,

impl<T> Extend<T> for Vec<T>

So it isn't able to conclude that T should be [u8; 16]. It might as well have been &[u8; 16]?

Thanks, I wouldn't have guessed that in a very long time!

After reading your insight, my best workaround was to add an IntoIterator<Item=T> bound to V.
I don't really need it, but it does solve the ambiguity:

pub fn deserialize<'de, T, V, D>(deserializer: D) -> Result<V, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>,
    V: Default + Extend<T> + IntoIterator<Item = T>,

Do you have another idea of how to solve this ambiguity cleanly?

@Phlopsi: Thank you for taking the time to send your idea. I think that having &'t [u8] works because of the preceding for<'t>.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.