0

I want to use the memory allocator M to allocate an Allocated which is gonna live together with M inside a struct. However, I don't want to pollute UseM with its lifetime. Is there a way to store Allocated inside UseM?

use std::marker::PhantomData;

pub struct Allocated<'r, T> {
    _phantom: PhantomData<&'r T>
}

pub trait MemPool<'s, 'r, T> {
    fn allocate_default(
        &'s self,
        size: usize,
    ) -> Allocated<'r, T>;
}

struct M<T> {
    _phantom: PhantomData<T>
}

impl<'s, T> MemPool<'s, 's, T> for M<T>
{
    fn allocate_default(
        &'s self,
        size: usize,
    ) -> Allocated<'s, T>{
        todo!()
    }
}

struct UseM<T> {
    //I wanted to allocated with m
    m: M<T>,
    //and store here, withotu `UseM` having to have a lifetime
    allocated: Allocated<'r, T>
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8bf2af2f7202a49c196cda98189f6971

error[E0261]: use of undeclared lifetime name `'r`
  --> src/lib.rs:32:26
   |
28 | struct UseM<T> {
   |             - help: consider introducing lifetime `'r` here: `'r,`
...
32 |     allocated: Allocated<'r, T>
   |                          ^^ undeclared lifetime
Rafaelo
  • 33
  • 1
  • 15
  • Relevant: [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/q/32300132/2189130) – kmdreko Dec 16 '21 at 21:52

1 Answers1

2

This is a “self-referential struct”, a pattern that can't be implemented in safe Rust directly, for two reasons:

  1. There is no way to write lifetime annotations that express it, and
  2. Structs are allowed to be moved, which would invalidate pointers into them, and there's no way to declare “this won't move because it is in a separate heap allocation” (except for the Pin mechanism which is not usable with only safe code).

The crate ouroboros uses macros and internal unsafe code to provide a safe mechanism to create this type of structure. However, you will have some additional verbosity in accessing the struct, and some things are not possible. Declaring your struct using ouroboros would look like this:

#[ouroboros::self_referencing]
struct UseM<T> {
    m: M<T>,
    #[borrows(m)]
    allocated: Allocated<'this, T>,
}
Kevin Reid
  • 37,492
  • 13
  • 80
  • 108