use crate::region::Region;
use std::alloc::Layout;
use std::ops;
pub struct Header {
drop_fn: Option<fn(*mut u8)>,
}
pub struct Handle<T> {
ptr: *mut T,
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Self { ptr: self.ptr }
}
}
impl<T> Copy for Handle<T> {}
impl<T> Handle<T> {
pub fn raw(self) -> RawHandle {
RawHandle {
ptr: self.ptr as *mut u8,
}
}
}
pub struct RawHandle {
ptr: *mut u8,
}
impl Clone for RawHandle {
fn clone(&self) -> Self {
Self { ptr: self.ptr }
}
}
impl Copy for RawHandle {}
impl<T> From<Handle<T>> for RawHandle {
fn from(handle: Handle<T>) -> Self {
handle.raw()
}
}
impl RawHandle {
pub unsafe fn trust_type<T>(self) -> Handle<T> {
Handle {
ptr: self.ptr as *mut T,
}
}
}
#[derive(Default)]
pub struct RawDynVec<R: Region<Header>> {
region: R,
}
impl<R: Region<Header>> Drop for RawDynVec<R> {
fn drop(&mut self) {
self.clear();
}
}
impl<R: Region<Header>, T> ops::Index<Handle<T>> for RawDynVec<R> {
type Output = T;
fn index(&self, index: Handle<T>) -> &Self::Output {
self.get(index)
}
}
impl<R: Region<Header>, T> ops::IndexMut<Handle<T>> for RawDynVec<R> {
fn index_mut(&mut self, index: Handle<T>) -> &mut Self::Output {
self.get_mut(index)
}
}
impl<R: Region<Header>> RawDynVec<R> {
pub fn with_region(region: R) -> Self {
Self { region }
}
pub fn count(&self) -> usize {
self.region.count()
}
pub fn try_insert<T>(&mut self, item: T) -> Result<Handle<T>, T> {
let layout = Layout::new::<T>();
let drop_fn: Option<fn(*mut u8)> = if std::mem::needs_drop::<T>() {
Some(|ptr: *mut u8| unsafe { std::ptr::drop_in_place(ptr as *mut T) })
} else {
None
};
match unsafe { self.insert_raw(layout, drop_fn) } {
Ok(handle) => {
unsafe {
handle.ptr.cast::<T>().write(item);
Ok(handle.trust_type::<T>())
}
},
Err(()) => Err(item),
}
}
pub fn clear(&mut self) {
for (ptr, header) in self.region.deallocate_all() {
if let Some(drop_fn) = header.drop_fn {
drop_fn(ptr)
}
}
}
pub fn insert<T>(&mut self, item: T) -> Handle<T> {
match self.try_insert(item) {
Ok(handle) => handle,
Err(_) => {
panic!("Failed to allocate the item");
}
}
}
pub unsafe fn insert_raw(
&mut self,
layout: Layout,
drop_fn: Option<fn(*mut u8)>,
) -> Result<RawHandle, ()> {
let header = Header {
drop_fn,
};
match self.region.allocate(layout, header) {
Ok(ptr) => {
Ok(RawHandle { ptr, })
}
Err(_) => Err(()),
}
}
pub fn remove<T>(&mut self, handle: Handle<T>) -> Result<T, ()> {
if let Some(_) = self.region.deallocate(handle.ptr as *mut u8) {
let item = unsafe { handle.ptr.read() };
Ok(item)
} else {
Err(())
}
}
pub fn remove_raw(&mut self, handle: RawHandle) -> Result<(), ()> {
if let Some(header) = self.region.deallocate(handle.ptr) {
if let Some(drop_fn) = header.drop_fn {
drop_fn(handle.ptr);
}
Ok(())
} else {
Err(())
}
}
pub fn get_ptr<T>(&self, handle: Handle<T>) -> *const T {
if self.region.has_allocated(handle.ptr as *mut u8) {
handle.ptr
} else {
std::ptr::null()
}
}
pub fn get_mut_ptr<T>(&self, handle: Handle<T>) -> *mut T {
if self.region.has_allocated(handle.ptr as *mut u8) {
handle.ptr
} else {
std::ptr::null_mut()
}
}
pub fn get_ptr_raw(&mut self, handle: RawHandle) -> *const u8 {
if self.region.has_allocated(handle.ptr) {
handle.ptr
} else {
std::ptr::null()
}
}
pub fn get_mut_ptr_raw(&mut self, handle: RawHandle) -> *mut u8 {
if self.region.has_allocated(handle.ptr) {
handle.ptr
} else {
std::ptr::null_mut()
}
}
pub fn try_get<T>(&self, handle: Handle<T>) -> Option<&T> {
unsafe { std::mem::transmute(self.get_ptr(handle)) }
}
pub fn try_get_mut<T>(&mut self, handle: Handle<T>) -> Option<&mut T> {
unsafe { std::mem::transmute(self.get_mut_ptr(handle)) }
}
pub fn get<T>(&self, handle: Handle<T>) -> &T {
self.try_get(handle).expect("Invalid handle")
}
pub fn get_mut<T>(&mut self, handle: Handle<T>) -> &mut T {
self.try_get_mut(handle).expect("Invalid handle")
}
}
#[cfg(test)]
#[test]
fn properly_dropped() {
use std::cell::Cell;
use std::rc::Rc;
use crate::region::block::Block;
let drop_count = Rc::new(Cell::new(0u16));
struct DropCheck(Rc<Cell<u16>>);
impl Drop for DropCheck {
fn drop(&mut self) {
self.0.set(self.0.get() + 1);
}
}
{
let mut vec = RawDynVec::with_region(Block::new(2048));
for _ in 0..100 {
vec.insert(DropCheck(Rc::clone(&drop_count)));
}
}
assert_eq!(drop_count.get(), 100);
}
#[cfg(test)]
#[test]
fn normal_use() {
use crate::region::block::Block;
let mut vec = RawDynVec::with_region(Block::new(2048));
let h_i32 = vec.insert(5i32);
let h_vec = vec.insert(vec![1u8, 2, 3]);
assert_eq!(vec[h_i32], 5i32);
assert_eq!(vec[h_vec][1], 2u8);
vec[h_vec].push(8);
assert_eq!(vec.get(h_vec).last(), Some(&8));
let other_vec = vec.remove(h_vec).unwrap();
assert_eq!(&other_vec[..], &[1, 2, 3, 8][..]);
assert_eq!(vec.try_get(h_vec), None);
}