include!(env!("BINDINGS"));
use crate::exports::test::arena_allocated_resources::to_test::{Guest, GuestThing};
export!(Component);
struct Component;
impl Guest for Component {
type Thing = MyThing;
}
mod arena {
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{cell::UnsafeCell, mem::MaybeUninit};
pub struct Arena<T, const SIZE: usize> {
buffer: [UnsafeCell<MaybeUninit<T>>; SIZE],
offset: AtomicUsize,
}
unsafe impl<T: Sync, const SIZE: usize> Sync for Arena<T, SIZE> {}
unsafe impl<T: Send, const SIZE: usize> Send for Arena<T, SIZE> {}
impl<T: Default, const SIZE: usize> Arena<T, SIZE> {
pub const fn new() -> Self {
Self {
buffer: [const { UnsafeCell::new(MaybeUninit::uninit()) }; SIZE],
offset: AtomicUsize::new(0),
}
}
pub fn alloc_one(&self) -> Option<&mut T> {
if self.offset.load(Ordering::Relaxed) >= SIZE {
None
} else {
let pos = self.offset.fetch_add(1, Ordering::Acquire);
if pos >= SIZE {
self.offset.fetch_sub(1, Ordering::Release);
None
} else {
let ptr = self.buffer[pos].get();
let uninit = unsafe { &mut *ptr };
Some(uninit.write(Default::default()))
}
}
}
}
}
use arena::Arena;
#[derive(Clone)]
struct MyThing {
contents: u32,
}
static ARENA: Arena<Option<MyThing>, 4> = Arena::new();
impl GuestThing for MyThing {
fn new(v: u32) -> MyThing {
MyThing { contents: v }
}
fn get(&self) -> u32 {
self.contents
}
unsafe fn resource_into_raw_(val: Self::Rep) -> *mut Self::Rep {
val.and_then(|v| {
ARENA.alloc_one().map(|x| {
*x = Some(v);
x as *mut _
})
})
.unwrap_or(core::ptr::null_mut())
}
unsafe fn resource_from_raw_(handle: *mut Self::Rep) -> Self::Rep {
unsafe { &mut *handle }.take()
}
}