use core::fmt::Debug;
use core::ops::{Deref, DerefMut};
use crate::{IndexAllocator, IndexError};
pub struct Box<'a, T, const MEMORY_SIZE: usize, const INDEX_SIZE: usize>
where
T: ?Sized,
{
val: &'a mut T,
allocator: &'a IndexAllocator<MEMORY_SIZE, INDEX_SIZE>,
}
impl<'a, T, const MEMORY_SIZE: usize, const INDEX_SIZE: usize> Box<'a, T, MEMORY_SIZE, INDEX_SIZE>
where
T: ?Sized,
{
pub fn try_new<U>(
val: U,
allocator: &'a IndexAllocator<MEMORY_SIZE, INDEX_SIZE>,
) -> Result<Self, IndexError>
where
U: 'a,
&'a mut T: From<&'a mut U>,
{
let inner_ref = unsafe { allocator.try_alloc_value(val)? };
Ok(unsafe { Self::from_raw_ref(inner_ref.into(), allocator) })
}
pub unsafe fn from_raw_ref(
val: &'a mut T,
allocator: &'a IndexAllocator<MEMORY_SIZE, INDEX_SIZE>,
) -> Self {
Self { val, allocator }
}
pub fn try_free(self) -> Result<(), IndexError> {
unsafe { self.allocator.try_free_value(self.val) }
}
#[must_use]
pub fn allocator(&self) -> &'a IndexAllocator<MEMORY_SIZE, INDEX_SIZE> {
self.allocator
}
}
impl<'a, T, const MEMORY_SIZE: usize, const INDEX_SIZE: usize> Drop
for Box<'a, T, MEMORY_SIZE, INDEX_SIZE>
where
T: ?Sized,
{
fn drop(&mut self) {
unsafe {
self.allocator.try_free_value(self.val).unwrap();
}
}
}
impl<'a, T, const MEMORY_SIZE: usize, const INDEX_SIZE: usize> Deref
for Box<'a, T, MEMORY_SIZE, INDEX_SIZE>
where
T: ?Sized,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.val
}
}
impl<'a, T, const MEMORY_SIZE: usize, const INDEX_SIZE: usize> DerefMut
for Box<'a, T, MEMORY_SIZE, INDEX_SIZE>
where
T: ?Sized,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.val
}
}
impl<'a, T, const MEMORY_SIZE: usize, const INDEX_SIZE: usize> Debug
for Box<'a, T, MEMORY_SIZE, INDEX_SIZE>
where
T: ?Sized + Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.val.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_box_allocation() {
let allocator: IndexAllocator<64, 8> = IndexAllocator::empty();
let test_box = Box::try_new([1u8, 2, 3, 4], &allocator).unwrap();
assert_eq!(*test_box, [1, 2, 3, 4]);
assert_eq!(unsafe { (*allocator.memory.get())[0] }, 1);
assert_eq!(unsafe { (*allocator.memory.get())[1] }, 2);
assert_eq!(unsafe { (*allocator.memory.get())[2] }, 3);
assert_eq!(unsafe { (*allocator.memory.get())[3] }, 4);
}
}