Help with ouroboros self-referential struct with external reference

Hi,

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?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.