Question about TypedArena


#1

I’m a bit confused about using TypedArena. Currently I have the following code:

pub struct S<'a> {
  arena: &'a mut TypedArena<Vec<u8>>
}

impl<'a> S<'a> {
  pub fn new(arena: &'a mut TypedArena<Vec<u8>>) -> Self {
    Self { arena: arena }
  }

  pub fn own(&mut self, data: Vec<u8>) -> &'a Vec<u8> {
    self.arena.alloc(data)
  }
}

The idea is to consume unique data and return reference of it that has the same lifetime
as the arena ('a). However this doesn’t compile, with the following error message:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/bin/read_parquet.rs:16:16
   |
16 |     self.arena.alloc(data)
   |                ^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 15:54...
  --> src/bin/read_parquet.rs:15:55
   |
15 |     pub fn own(&mut self, data: Vec<u8>) -> &'a Vec<u8> {
   |  _______________________________________________________^ starting here...
16 | |     self.arena.alloc(data)
17 | |   }
   | |___^ ...ending here
note: ...so that reference does not outlive borrowed content
  --> src/bin/read_parquet.rs:16:5
   |
16 |     self.arena.alloc(data)
   |     ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 15:54...
  --> src/bin/read_parquet.rs:15:55
   |
15 |     pub fn own(&mut self, data: Vec<u8>) -> &'a Vec<u8> {
   |  _______________________________________________________^ starting here...
16 | |     self.arena.alloc(data)
17 | |   }
   | |___^ ...ending here
note: ...so that reference does not outlive borrowed content
  --> src/bin/read_parquet.rs:16:5
   |
16 |     self.arena.alloc(data)
   |     ^^^^^^^^^^^^^^^^^^^^^^

Can someone explain what’s wrong in the code, and how can I achieve the purpose? Thanks.


#2

Are you intentionally storing a &mut reference to the arena? It makes lifetime requirements stricter, and causes the error you’re seeing. AFAICT, alloc doesn’t require a mutable borrow of the arena. So, if you change your code to be:

pub struct S<'a> {
  arena: &'a TypedArena<Vec<u8>>
}

It should work.


#3

Thanks @vitalyd! Yes, after removing &mut it compiles (I unintentionally added &mut assuming alloc needs a &mut self).

It’s very interesting that the modifier &mut caused this to be rejected by the compiler though. Not sure what difference it made in terms of the lifetime analysis…


#4

It would then require &mut self in own to be identical to 'a, i.e. the following also compiles but is not what you want/need here:

pub struct S<'a> {
  arena: &'a mut TypedArena<Vec<u8>>
}

pub fn own(&'a mut self, data: Vec<u8>) -> &'a Vec<u8> {
    self.arena.alloc(data)
}

This basically comes down to variance - mutable references are invariant. Immutable references, however, are variant. So, returning a &'a Vec<u8> from a shorter borrow of &TypedArena is fine because a longer lifetime is a subtype of a shorter lifetime for immutable references. But, once you switch to mutable, that variance/subtyping relationship goes away.

Hope that helps.


#5

Got it. Thanks for the explanation!