Deserializer generic over Deserializer

Unfortunately I can think of no better title. I'm currently exploring serde by making a toy Deserializer that is generic over Deserializer. Basically just a wrapper based instrumentation/logging for exploration. My first attempt was to "wrap" a JSON Deserializer which raised a bunch of questions. Specifically, Deserializer is implemented on a mutable borrow of serde_json's Deserializer struct and I've found myself unable to properly "wrap" that in a way that makes the compiler happy, and the way I've structured things "delegating" to the wrapped Deserializer wants to move that deserializer as Deserializer<'de> does not implement copy.

Here's what I'm working with (serde 1.0 and serde_json 1.0):
My wrapper:

pub struct Wrapper<'a, D> {
    de: &'a mut D,
}

impl<'a, 'de, D: 'de> Wrapper<'a, D>
where
    D: Deserializer<'de>,
{
    pub fn new(de: &'a mut D) -> Self {
        Wrapper { de }
    }
}

impl<'a, 'de, D> Deserializer<'de> for &mut Wrapper<'a, D>
where
    D: Deserializer<'de>,
{
    type Error = crate::Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.de
            .deserialize_any(visitor)
            .map_err(|e| crate::Error::Custom("deserialize_any".into()))
    }
...
...
}

It's compiler error:

error[E0507]: cannot move out of `*self.de` which is behind a mutable reference
   --> src/deserializer.rs:30:9
    |
30  | /         self.de
31  | |             .deserialize_any(visitor)
    | |              -----------------------^
    | |______________|______________________|
    |                |                      move occurs because `*self.de` has type `D`, which does not implement the `Copy` trait
    |                `*self.de` moved due to this method call
    |
note: this function takes ownership of the receiver `self`, which moves `*self.de`
   --> /home/sean/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.154/src/de/mod.rs:919:27
    |
919 |     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    |                           ^^^^

My attempted call site:

let mut de = serde_json::Deserializer::from_str(input);
let wrap = Wrapper::new(&mut de);

It's compiler error:

error[E0277]: the trait bound `serde_json::Deserializer<StrRead<'_>>: types::_::_serde::Deserializer<'_>` is not satisfied
   --> src/deserializer.rs:284:32
    |
284 |         let wrap = Wrapper::new(&mut de);
    |                   ------------ ^^^^^^^ the trait `types::_::_serde::Deserializer<'_>` is not implemented for `serde_json::Deserializer<StrRead<'_>>`
    |                   |
    |                   required by a bound introduced by this call
    |
    = help: the trait `types::_::_serde::Deserializer<'de>` is implemented for `&'a mut serde_json::Deserializer<R>`
note: required by a bound in `Wrapper::<'a, D>::new`
   --> src/deserializer.rs:13:8
    |
13  |     D: Deserializer<'de>,
    |        ^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::<'a, D>::new`
14  | {
15  |     pub fn new(de: &'a mut D) -> Self {
    |            --- required by a bound in this

I feel like I generally understand what these error messages are saying, but at this point I've been tinkering with it for so long I've confused myself with what's actually going on.

My specific questions:

  1. I'm curious how (or if) it's possible to satisfy the Deserializer<'de> trait bound with something like serde_json's deserializer that only implements Deserializer<'de> on a mutable borrow.
  2. When attempting to be generic over a trait such as Deserializer<'de> that does not implement Copy, how does one signal to the compiler that it's a reference?
  3. Is this pattern in general even a good idea? An alternative thought I had instead of a generic was to use an enum that would hold the concrete type(s) of Deserializer that I'm attempting to wrap, but that has the downside of having to know of them before hand.

Don't bother with so many layers of references. Just use values. This compiles.

1 Like

Thanks for the prompt reply and working example. I think there's a lesson here I've learned (and forgotten) regarding generics. Would it be correct to say that the generic D covers any T that implements Deserialize whether that's T, &T or &mut T so my attempting to specify D itself as &mut forces a set of nearly impossible constraints to satisfy?

I should have more specifically included it in my example, but if Wrapper itself is keeping some sort of state it needs to be &mut which leaves me w/ the move problem for the delegate. Something like this

Is this sort of disagreement intractable because I cannot enforce that the implementers of Deserialize<'de> are themselves references or copy?

If deserializers always implement the trait for a mutable reference, the simpler answer might be to just have an owned value in the wrapper, and specify that &mut D: Deserializer<'de> instead of D: Deserializer<'de>

Playground

use serde::{
    de::{Deserializer, Error as DeError},
    forward_to_deserialize_any, Deserialize,
};

pub struct Wrapper<D> {
    de: D,
    count: usize,
}

impl<D> Wrapper<D> {
    pub fn new(de: D) -> Self {
        Wrapper { de, count: 0 }
    }
}

impl<'de, 'a, D> Deserializer<'de> for &'a mut Wrapper<D>
where
    &'a mut D: Deserializer<'de>,
{
    type Error = <&'a mut D as Deserializer<'de>>::Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.count = self.count + 1;
        self.de
            .deserialize_any(visitor)
            .map_err(|e| DeError::custom(format!("deserialize_any: {}", e)))
    }

    forward_to_deserialize_any! {
        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
        bytes byte_buf option unit unit_struct newtype_struct seq tuple
        tuple_struct map struct enum identifier ignored_any
    }
}

#[derive(Debug, Deserialize)]
struct MyType {
    foo: String,
    qux: u64,
}

fn main() {
    let json = r#"{"foo": "bar", "qux": 42}"#;
    let mut json_des = serde_json::Deserializer::new(serde_json::de::StrRead::new(json));
    let mut d = Wrapper::new(json_des);
    let thing = MyType::deserialize(&mut d);
    dbg!(thing);
}

Of course. A type variable can stand in for any type.

No, I don't think so. I don't see anything "intractable" here. Copy can be trivially enforced by adding the Copy bound (but it would be useless as most serializers aren't Copy). Explicit references can also be used as the type parameter; the usual trick for moving out of a reference is to call mem::replace() or similar functions, but in this case, not using explicit references is simply less laborious.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.