Help with ouroboros self-referential struct with external reference
⚓ Rust 📅 2025-11-13 👤 surdeus 👁️ 3Hi,
I have the following code:
use ouroboros::self_referencing;
#[self_referencing]
struct Foo {
backing_storage: Vec<u8>,
#[borrows(mut backing_storage)]
#[covariant]
arena: Arena<'this>,
#[borrows(arena)]
#[not_covariant]
model: Box<dyn DoStuff<'this> + 'this>,
}
struct Arena<'a> {
memory: &'a mut [u8],
}
impl<'a> Arena<'a> {
fn new(backing: &'a mut [u8], size: usize) -> Self {
Arena {
memory: &mut backing[0..size],
}
}
}
struct ArenaUser<'a, const N: usize> {
arena: &'a Arena<'a>,
some_data: [u8; N],
}
impl<'a, const N: usize> ArenaUser<'a, N> {
fn new(arena: &'a Arena<'a>) -> Self {
ArenaUser {
arena,
some_data: [0; N],
}
}
}
trait DoStuff<'a> {
fn do_stuff(&self, arena: &'a Arena<'a>) -> &[u8];
}
impl<'a, const N: usize> DoStuff<'a> for ArenaUser<'a, N> {
fn do_stuff(&self, arena: &'a Arena<'a>) -> &'a [u8] {
&arena.memory[0..]
}
}
fn main() {
let model = FooBuilder {
backing_storage: vec![0; 10],
arena_builder: |backing| Arena::new(backing, 10),
model_builder: |arena| Box::new(ArenaUser::<1>::new(arena)),
}
.build();
}
This currently builds. (It seems that ouroboros is not available on the playground so I can't share a link, sorry :().
This struct has an arena which takes a reference to a Vec stored in the same struct. It also has an object that takes a reference to the arena within itself. I'm storing that object as a trait object in order to erase the generics as I need the top struct to not be generic.
Now I need ArenaUser to hold a reference to an external object. I haven't been able to figure out the lifetimes to make this work. This is what I have now:
use ouroboros::self_referencing;
#[self_referencing]
struct Foo<'a> {
backing_storage: Vec<u8>,
#[borrows(mut backing_storage)]
#[covariant]
arena: Arena<'this>,
#[borrows(arena)]
#[not_covariant]
model: Box<dyn DoStuff<'this> + 'a>,
}
struct Arena<'a> {
memory: &'a mut [u8],
}
impl<'a> Arena<'a> {
fn new(backing: &'a mut [u8], size: usize) -> Self {
Arena {
memory: &mut backing[0..size],
}
}
}
struct ArenaUser<'a, 'b, const N: usize> {
arena: &'a Arena<'a>,
some_data: [u8; N],
reference: &'b u8,
}
impl<'a, 'b, const N: usize> ArenaUser<'a, 'b, N> {
fn new(arena: &'a Arena<'a>, reference: &'b u8) -> Self {
ArenaUser {
arena,
some_data: [0; N],
reference,
}
}
}
trait DoStuff<'a> {
fn do_stuff(&self, arena: &'a Arena<'a>) -> &[u8];
}
impl<'a, 'b, const N: usize> DoStuff<'a> for ArenaUser<'a, 'b, N> {
fn do_stuff(&self, arena: &'a Arena<'a>) -> &'a [u8] {
&arena.memory[0..]
}
}
fn main() {
let ref_value: u8 = 42;
let model = FooBuilder {
backing_storage: vec![0; 10],
arena_builder: |backing| Arena::new(backing, 10),
model_builder: |arena| Box::new(ArenaUser::<1>::new(arena, &ref_value)),
}
.build();
}
The code above just adds the reference field to ArenaUser and its new() method.
I've taken a look at the examples and it seems that what I want is possible, but the Box<dyn Trait<'a> + 'a> syntax is already getting too advanced Rust for me.
Can anyone point me in the right direction?
1 post - 1 participant
🏷️ Rust_feed