(See Holding an impl AsMut<[u8]> and multiple &mut [u8] into it at the same time for context. This is a followup.)
I wound up going with the following layout for my arena:
pub struct Arena<'buf> {
lifetime_phantom: PhantomData<&'buf mut ()>,
mem_ptr: NonNull<u8>,
mem_len: usize,
next_byte: usize,
}
My question: can this be adapted into a typed arena for a fixed type T
with no restrictions on the type? The primary problem I see is that when 'buf
ends (e.g., the arena is dumped into forget()
), the slice that it was constructed from is now again accessible. This means that if T
has padding bits, they are now observable as bytes through the &mut [u8]
.
I'm not sure that can be done with a safe API in current Rust? Is there a way MaybeUninit can save me? If so, it seems like the following would work:
impl<'buf, T> TypedArena<'buf, T> { // Same layout as Arena.
pub fn new(buf: &'buf [MaybeUninit<u8>]) -> Self { ... }
}
let mem = unsafe { MauybeUninit::<[MaybeUninit; 1024]>::uninit().assume_init() };
let arena = Arena::new(&mut mem);
// At no point is a direct reference to the arena memory created here.
I think new
does not need to be marked as unsafe
. Thoughts?
Bonus points: the above example assumes that T
is fixed. Can I make one arena allocate all sized types? The following would be Bad:
let mut arena = ...;
let _ = arena.alloc_typed<DefinitelyHasPadding>(...);
arena.reset();
let bytes = arena.alloc(4); // Oops I've witnessed padding bytes.
I suspect that zeroing every allocation (through ptr::write
) before returning it is sufficient...?