How to deal with lifetimes with custom ser/de?

Hi all,

I'm trying to write a sample for ser/de using the Serde example (Implementing a Serializer · Serde).

The problem is that structure has a lifetime:

#[derive(Debug)]
pub struct Serializer<'a> {
    length: usize,
    buffer: &'a mut Vec<u8>,   // ref on Vector made on purpose
}

And when implementing for example SerializeStruct:

impl<'a> ser::SerializeStruct for &'a mut Serializer<'a> {
    type Ok = usize;
    type Error = Error;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
    where
        T: ?Sized + Serialize,
    {
        self.length += value.serialize(&mut **self)?;
        Ok(())
    }

    fn end(self) -> Result<usize> {
        Ok(0)
    }
}

the compiler complains about the 'a lifetime:

error[E0503]: cannot use `self.length` because it was mutably borrowed
   --> src/serde_test.rs:498:9
    |
490 | impl<'a> ser::SerializeStruct for &'a mut Serializer<'a> {
    |      -- lifetime `'a` defined here
...
498 |         self.length += value.serialize(&mut **self)?;
    |         ^^^^^^^^^^^^^^^----------------------------^
    |         |              |               |
    |         |              |               `**self` is borrowed here
    |         |              argument requires that `**self` is borrowed for `'a`
    |         use of borrowed `**self`

error: lifetime may not live long enough
   --> src/serde_test.rs:498:24
    |
490 | impl<'a> ser::SerializeStruct for &'a mut Serializer<'a> {
    |      -- lifetime `'a` defined here
...
494 |     fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
    |                           - let's call the lifetime of this reference `'1`
...
498 |         self.length += value.serialize(&mut **self)?;
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`

I understand that double borrow causes one error, but I can't get out of it.

Any idea how to circumvent this error ?

Thanks a lot for your help.

impl<'a> ser::SerializeStruct for &'a mut Serializer<'a> {

Don't conflate these two lifetimes. &'a mut YourType<'a> is almost always wrong — it means the value is borrowed for the rest of its existence, because &'a mut T must outlive T, and YourType<'a> must outlive 'a. Another common form of this mistake is:

impl<'a> YourType<'a> {
    pub fn do_something(&'a mut self) {...}
}

This makes self have type &'a mut Self = &'a mut YourType<'a>.

In both cases, the solution is to let them be separate, so that the Serializer can be borrowed for shorter lifetimes:

impl<'a, 'b> ser::SerializeStruct for &'a mut Serializer<'b> {

If they're not mentioned in the body of the impl, then they can be unnamed:

impl ser::SerializeStruct for &'_ mut Serializer<'_> {

In this position, '_ means to create a new lifetime variable distinct from all others.

7 Likes

@kpreid Thanks for taking the time to answer.

That makes sense. But replacing by your proposal doesn't still compile :thinking:

@kornel Thanks for your answer. You mean "don't use references for Serializer-like structs ?"

Sorry I’ve misread as Deserializer struct. Serialization of a reference is fine.

The general reason we say “don't put references in structs” is that references are a lot more narrowly applicable than beginners commonly think, and it is very common to try to use references in a place that actually requires ownership (or is much simpler with ownership).

With a few exceptions, a data type should only contain references when, in the use cases for that data type, the place the reference points to always already exists before the value containing the reference is created.

2 Likes