0

I'm trying to implement a memory pool based on TypedArena. Here's a simplified version of my original code:

#![feature(rustc_private)]
extern crate arena;
use arena::TypedArena;

pub struct MemoryPool {
    arena: TypedArena<Vec<u8>>,
    bytes_allocated: usize,
}

impl MemoryPool {
    pub fn consume(&mut self, buf: Vec<u8>) -> &[u8] {
        self.bytes_allocated += buf.capacity();
        self.arena.alloc(buf)
    }
}

pub struct ByteArray<'a> {
    data: &'a [u8],
}

impl<'a> ByteArray<'a> {
    pub fn set_data(&mut self, data: &'a [u8]) {
        self.data = data;
    }
}

pub struct S<'a> {
    pool: &'a mut MemoryPool,
}

impl<'a> S<'a> {
    pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
        let v = vec!();
        let data = self.pool.consume(v);
        buffer.set_data(data);
    }
}

However, the compiler complains about the line: let data = self.pool.consume(v);:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> <anon>:34:26
   |
34 |     let data = self.pool.consume(v);
   |                          ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 32:54...
  --> <anon>:32:55
   |
32 |     pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
   |  _______________________________________________________^ starting here...
33 | |     let v = vec!();
34 | |     let data = self.pool.consume(v);
35 | |     buffer.set_data(data);
36 | |   }
   | |___^ ...ending here
note: ...so that reference does not outlive borrowed content
  --> <anon>:34:16
   |
34 |     let data = self.pool.consume(v);
   |                ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 32:54...
  --> <anon>:32:55
   |
32 |     pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
   |  _______________________________________________________^ starting here...
33 | |     let v = vec!();
34 | |     let data = self.pool.consume(v);
35 | |     buffer.set_data(data);
36 | |   }
   | |___^ ...ending here
note: ...so that types are compatible (expected &mut ByteArray<'_>, found &mut ByteArray<'a>)
  --> <anon>:35:12
   |
35 |     buffer.set_data(data);
   |            ^^^^^^^^

My question is:

  1. Why data does not have lifetime 'a? I'm thinking that since pool has lifetime a and consume returns the same lifetime as self, it should have lifetime 'a.

  2. What's the best way to make this code work as intended? Basically I want to allocate new bytes and adjust their lifetime to be the same as the memory pool. I know I can use TypedArena directly since alloc does not take a mut reference. However I really want to track other information such as bytes_allocated.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
Chao Sun
  • 655
  • 1
  • 6
  • 16

1 Answers1

0

Let's tackle this step by step:

cannot infer an appropriate lifetime for autoref

"autoref" describes the process of building the right reference for the self argument of a method. The compiler is unable to find a reference with the right lifetime to call consume(). Why is it unable?

note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 32:54...
  --> <anon>:32:55
   |
32 |     pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
   |  _______________________________________________________^ starting here...
33 | |     let v = vec!();
34 | |     let data = self.pool.consume(v);
35 | |     buffer.set_data(data);
36 | |   }
   | |___^ ...ending here
note: ...so that reference does not outlive borrowed content
  --> <anon>:34:16
   |
34 |     let data = self.pool.consume(v);
   |                ^^^^^^^^^

The "anonymous lifetime #1" refers to the lifetime of &mut self. This note is just saying: we can't pass a reference with a lifetime greater than the lifetime of self into consume(): then consume() would think that its self argument lives longer than it actually does.

note: but, the lifetime must be valid for the lifetime 'a

This is the rule you already expected to be applied. But where is the problem now? Well: the lifetime of &mut self (anonymous lifetime #1) could life shorter than 'a! That's all! And we can fix it quite easily:

impl<'a> S<'a> {
    pub fn write<'b: 'a>(&'b mut self, buffer: &mut ByteArray<'a>) {
        //      ^^^^^^^^  ^^
        ...
    }
}

Here we just name the previously anonymous lifetime #1 to be able to bound it, saying that it has to outlive 'a (live longer than 'a).

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • Thanks. I think the confusion I had was that `self.pool` has lifetime of `self` instead of `pool`, with `pool` being mutable. This is not intuitive as there's a lifetime annotation `'a` attached to `pool. To fix the code, do you have other suggestion rather than adding a `'b` for `self`? This doesn't work for my original code as struct `S` is expected to live shorter than `'a`. – Chao Sun Apr 05 '17 at 07:32
  • @ChaoSun that's not possible. The `MemoryPool` can't return a reference that lives longer than itself and similarly, `S` can't return something that references something that lives longer than itself, and `S::pool` lives exactly as long as `S`. I'm not quite sure what you're trying to achieve. – Lukas Kalbertodt Apr 05 '17 at 07:57