3
votes

I'm trying to derive Deserialize on a struct that has borrowed content:

#[macro_use]
extern crate serde_derive;
use std::net::SocketAddr;

#[derive(Hash, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct MyS<'a> {
    pub addr: &'a SocketAddr,
}

rust playground

I get the following compilation error:

error[E0277]: the trait bound `&'a std::net::SocketAddr: _::_serde::Deserialize<'_>` is not satisfied
 --> src/lib.rs:7:5
  |
7 |     pub addr: &'a SocketAddr,
  |     ^^^ the trait `_::_serde::Deserialize<'_>` is not implemented for `&'a std::net::SocketAddr`
  |
  = help: the following implementations were found:
            <std::net::SocketAddr as _::_serde::Deserialize<'de>>
  = note: required by `_::_serde::de::SeqAccess::next_element`

What are the different ways I can get this struct to implement Deserialize for some lifetime ?

Note: I don't actually require the deserialization to be zero-copy, it's only a nice-to-have

1
Deserializing into a reference isn't really possible, as nobody owns the data. See this Github issue: github.com/serde-rs/serde/issues/1092PitaJ

1 Answers

6
votes

You can't do this, and here's why:

Serde allows for zero-copy deserialization of certain types. In this case, the data is borrowed from the Deserializer, which in turn either borrows or owns a buffer of some kind. Since &[u8] and &str are both fundamentally streams of bytes, they can just be deserialized as references into the buffer. How exactly this works is explained in the serde docs, but it fundamentally requires that the Rust type is laid out exactly as the data exists in the buffer you are deserializing.

In your case, however, you want to deserialize a SocketAddr. The problem is that the data in the buffer is in a different form from the data you want to borrow. Serde serializes a SocketAddrs into a string via Display, see for example this implemention for SocketAddrV4. But a SocketAddr itself is stored as a 32 bit integer and a 16 bit integer. You cannot borrow one as the other; some kind of parsing needs to happen, and someone then needs to own the resulting data. Serde logically has your struct own that data. Even in binary serialization, there is no guarantee the layout of the serialized data will match the layout of the struct, so parsing needs to happen.

This is encoded in the type system via the implementations of Deserialize serde provides. This page has the full list. You can see that there is an implementation for &'a str where the lifetime of the Deserializer ('de) outlives 'a. There is no implementation for references to most other types, including &SocketAddr.

This serde issue linked by PitaJ shows a good minimal code example.