extern crate alloc;
use alloc::alloc::{alloc as malloc, dealloc, Layout};
use core::mem;
use core::ops::{Deref, DerefMut, Drop};
use core::ptr::NonNull;
use crate::raw::PackedPtr;
trait PackedPtrType {
type Ptr;
}
impl<const CAPACITY: u32, T> PackedPtrType for PackedBox<CAPACITY, T> {
type Ptr = PackedPtr<CAPACITY, T>;
}
#[derive(Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[repr(transparent)]
pub struct PackedBox<const CAPACITY: u32, T> {
packed: PackedPtr<CAPACITY, T>,
}
#[derive(Clone, Debug)]
pub enum AllocationError {
InvalidLayout,
NullPtr,
}
unsafe impl<const CAPACITY: u32, T: Send> Send for PackedBox<CAPACITY, T> {}
unsafe impl<const CAPACITY: u32, T: Sync> Sync for PackedBox<CAPACITY, T> {}
impl<const CAPACITY: u32, T> Clone for PackedBox<CAPACITY, T>
where
T: Clone,
{
#[inline]
fn clone(&self) -> Self {
Self::new_with_bitfield(self.as_ref().clone(), self.bitfield()).unwrap()
}
#[inline]
fn clone_from(&mut self, source: &Self) {
let this: &mut T = self;
let source: &T = source;
this.clone_from(source);
}
}
impl<const CAPACITY: u32, T> Deref for PackedBox<CAPACITY, T> {
type Target = PackedPtr<CAPACITY, T>;
fn deref(&self) -> &Self::Target {
&self.packed
}
}
impl<const CAPACITY: u32, T> DerefMut for PackedBox<CAPACITY, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.packed
}
}
impl<const CAPACITY: u32, T> Drop for PackedBox<CAPACITY, T> {
fn drop(&mut self) {
if mem::size_of::<T>() == 0 {
return;
}
let layout = Self::layout().unwrap();
let offset = self.packed.masked_pointer().cast();
unsafe {
dealloc(offset, layout);
}
}
}
impl<const CAPACITY: u32, T> PackedBox<CAPACITY, T> {
#[inline]
fn layout() -> Result<Layout, AllocationError> {
let alignment = 2usize
.checked_pow(
CAPACITY
.checked_sub(1)
.ok_or(AllocationError::InvalidLayout)?,
)
.ok_or(AllocationError::InvalidLayout)?;
Layout::new::<T>()
.align_to(alignment)
.map_err(|_| AllocationError::InvalidLayout)
}
#[inline]
pub fn new(value: T) -> Result<Self, AllocationError> {
Self::new_with_bitfield(value, 0)
}
pub fn new_with_bitfield(value: T, bitfield: usize) -> Result<Self, AllocationError> {
if CAPACITY == 0 || CAPACITY >= (mem::size_of::<usize>() * 8) as u32 {
return Err(AllocationError::InvalidLayout);
}
if mem::size_of::<T>() == 0 {
let mask = <Self as PackedPtrType>::Ptr::mask();
let packed = unsafe {
PackedPtr::new_unchecked_raw((!mask | (bitfield & mask)) as *mut _)
};
return Ok(PackedBox { packed });
}
let layout = Self::layout()?;
let offset: *mut T = unsafe {
malloc(layout).cast()
};
let pointer = NonNull::new(offset).ok_or(AllocationError::NullPtr)?;
debug_assert_eq!(offset as usize & <Self as PackedPtrType>::Ptr::mask(), 0);
unsafe {
pointer.as_ptr().write(value);
}
let mut packed = unsafe {
PackedPtr::new_unchecked(pointer)
};
if bitfield != 0 {
packed.set_bitfield(bitfield);
}
Ok(PackedBox { packed })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_capacity_fails() {
let result: Result<PackedBox<0, _>, _> = PackedBox::new(1234);
assert!(matches!(result, Err(AllocationError::InvalidLayout)));
}
#[test]
fn large_bitfields_invalid() {
const MAX_WIDTH: u32 = (mem::size_of::<usize>() * 8) as u32;
let result: Result<PackedBox<{ MAX_WIDTH }, _>, _> = PackedBox::new("test");
assert!(matches!(result, Err(AllocationError::InvalidLayout)));
}
#[test]
fn new_with_bitfield() {
let ptr: PackedBox<4, _> = PackedBox::new_with_bitfield(1234, 0b1010).unwrap();
assert_eq!(ptr.bitfield(), 0b1010);
assert_eq!(*ptr.as_ref(), 1234);
let ptr: PackedBox<4, _> = PackedBox::new_with_bitfield((), 0b0101).unwrap();
assert_eq!(ptr.bitfield(), 0b0101);
assert_eq!(*ptr.as_ref(), ());
}
#[test]
fn clone_pointer() {
let ptr: PackedBox<4, _> =
PackedBox::new_with_bitfield(String::from("test"), 0b1010).unwrap();
assert_eq!(ptr.bitfield(), 0b1010);
assert_eq!(*ptr.as_ref(), "test");
let cloned = ptr.clone();
assert_eq!(ptr.bitfield(), cloned.bitfield());
assert_eq!(ptr.as_ref(), cloned.as_ref());
assert!(!core::ptr::eq(ptr.as_ref(), cloned.as_ref()));
let ptr: PackedBox<4, _> = PackedBox::new_with_bitfield((), 0b0101).unwrap();
assert_eq!(ptr.bitfield(), 0b0101);
assert_eq!(*ptr.as_ref(), ());
let cloned = ptr.clone();
assert_eq!(ptr.bitfield(), cloned.bitfield());
assert_eq!(ptr.as_ref(), cloned.as_ref());
assert!(core::ptr::eq(ptr.as_ref(), cloned.as_ref()));
}
#[test]
fn zero_size_types() {
let mut ptr: PackedBox<63, _> = PackedBox::new(()).unwrap();
assert_eq!(
ptr.as_ref() as *const _ as usize,
!PackedPtr::<63, ()>::mask()
);
*ptr.as_mut() = ();
}
#[test]
fn clone_from_same_buf() {
let mut ptr1: PackedBox<1, i32> = PackedBox::new(4).unwrap();
let ptr2: PackedBox<1, i32> = PackedBox::new(2).unwrap();
let ptr1_ref1: &i32 = ptr1.as_ref();
let ptr1_off1: usize = ptr1_ref1 as *const _ as usize;
ptr1.clone_from(&ptr2);
drop(ptr2);
let ptr1_ref2: &i32 = ptr1.as_ref();
let ptr1_off2: usize = ptr1_ref2 as *const _ as usize;
assert_eq!(ptr1_off1, ptr1_off2);
}
}