use std::{
alloc::{Allocator, Layout},
ops::{Deref, DerefMut},
ptr::{self, NonNull},
slice::{from_raw_parts, from_raw_parts_mut},
};
use zerocopy::FromZeros;
use crate::abi::SandboxSafe;
#[repr(C)]
pub struct BVec<T, A: Allocator> {
alloc: A,
ptr: *mut T,
len: u64,
}
impl<T: FromZeros, A: Allocator> BVec<T, A> {
pub fn try_new_in(alloc: A, len: usize) -> Option<Self> {
if len == 0 {
return Some(Self {
alloc: alloc,
ptr: ptr::null_mut(),
len: 0,
});
}
let layout = Layout::array::<T>(len).ok()?;
let ptr = alloc.allocate_zeroed(layout).ok()?;
Some(Self {
alloc: alloc,
ptr: ptr.as_ptr().cast(),
len: len as u64,
})
}
}
impl<T, A: Allocator> Deref for BVec<T, A> {
type Target = [T];
fn deref(&self) -> &[T] {
match NonNull::new(self.ptr) {
Some(p) => unsafe { from_raw_parts(p.as_ptr().cast_const(), self.len as usize) },
None => &[],
}
}
}
impl<T, A: Allocator> DerefMut for BVec<T, A> {
fn deref_mut(&mut self) -> &mut [T] {
match NonNull::new(self.ptr) {
Some(p) => unsafe { from_raw_parts_mut(p.as_ptr(), self.len as usize) },
None => &mut [],
}
}
}
impl<T, A: Allocator> Drop for BVec<T, A> {
fn drop(&mut self) {
let (Ok(layout), Some(p)) = (
Layout::array::<T>(self.len as usize),
NonNull::new(self.ptr.cast::<u8>()),
) else {
return;
};
unsafe { self.alloc.deallocate(p, layout) };
}
}
unsafe impl<T: SandboxSafe, A: Allocator + SandboxSafe> SandboxSafe for BVec<T, A> {}