Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deriving Deserializer for T when it's implemented for &mut T #2850

Closed
fjarri opened this issue Oct 26, 2024 · 2 comments
Closed

Deriving Deserializer for T when it's implemented for &mut T #2850

fjarri opened this issue Oct 26, 2024 · 2 comments

Comments

@fjarri
Copy link

fjarri commented Oct 26, 2024

When writing a Deserializer impl, it is commonly written for &mut of something, or a wrapper of it - because it has to be recursively passed down when deserializing nested structs, lists, and so on.

But if the user code wants to be generic over types that implement Deserializer (e.g. when using erased-serde, see my use case in dtolnay/erased-serde#107), it necessarily produces higher-ranked bounds on lifetimes (e.g. for<'a, 'de> &'a mut S::Des<'de>: serde::Deserializer<'de> in the quoted example), which cannot be encapsulated in a trait and will be propagated to all dependent generic code (current limitation of Rust; see rust-lang/rust#50346 and other related issues).

To amend that, it would be convenient to impl Deserializer on the object itself, which involves writing a long sheet of boilerplate like

struct MyDeserializerRef<'a, 'de> {
    de: &'a mut MyDeserializer<'de> 
} 

impl<'a, 'de> Deserializer<'de> for MyDeserializerRef<'a, 'de> {
    // ... actual deserialization logic
}

impl<'de> MyDeserializer<'de> {
    fn as_mut<'a>(&'a mut self) -> MyDeserializerRef<'a, 'de> { ... }
}

impl<'de> Deserializer<'de> for MyDeserializer<'de> {
    fn deserialize_any<V>(mut self, visitor: Visitor<'de>) -> Result<V::Value, Self::Error>
    {
        self.as_mut().deserialize_any(visitor)
    }

    fn deserialize_bool<V>(mut self, visitor: Visitor<'de>) -> Result<V::Value, Self::Error>
    {
        self.as_mut().deserialize_bool(visitor)
    }

    // ... and dozens more methods with the same content
}

Is there some easier way to do that? Is a macro necessary?

@fjarri
Copy link
Author

fjarri commented Oct 27, 2024

It seems like no macro is required, but there's still a significant amount of boilerplate. I made a standalone crate that does this kind of wrapping: https://github.com/fjarri/serde-persistent-deserializer. Is it something you would potentially want to see included in serde?

@oli-obk
Copy link
Member

oli-obk commented Oct 28, 2024

Shipping it in a separate crate seems best to me. It's not a totally common use case, and you can do major bumps if you want to change entirely how it's done.

Ideally we'd just have a blanket impl, but that's a breaking change now if it ever was possible at all

@oli-obk oli-obk closed this as completed Oct 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants