use core::{alloc::AllocError, cmp::Ordering, marker::PhantomData, num::NonZero, ptr::NonNull};
#[derive(Debug, PartialEq)]
pub enum BlockError {
Overflow,
NotAdjacent,
InvalidIndex,
TooSmall,
}
#[derive(Debug, PartialEq)]
pub struct Block {
pub ptr: NonNull<u8>,
pub size: NonZero<usize>,
}
impl Block {
pub fn new(ptr: NonNull<u8>, size: NonZero<usize>) -> Self {
Self { ptr, size }
}
#[inline(always)]
pub fn is_adjacent(&self, other: &Self) -> bool {
self.is_lesser_adjacent(other) || self.is_greater_adjacent(other)
}
#[inline(always)]
pub fn is_lesser_adjacent(&self, other: &Self) -> bool {
unsafe { self.ptr.add(self.size.get()) == other.ptr }
}
#[inline(always)]
pub fn is_greater_adjacent(&self, other: &Self) -> bool {
unsafe { other.ptr.add(other.size.get()) == self.ptr }
}
#[inline(always)]
pub fn merge_ordered<'a>(&'a self, other: &'a Self) -> Option<(&'a Self, &'a Self)> {
if self.is_lesser_adjacent(other) {
Some((self, other))
} else if self.is_greater_adjacent(other) {
Some((other, self))
} else {
None
}
}
#[inline(always)]
pub fn cmp_adjacent(&self, other: &Self) -> Option<Ordering> {
if self.is_greater_adjacent(other) {
Some(Ordering::Greater)
} else if self.is_lesser_adjacent(other) {
Some(Ordering::Less)
} else {
None
}
}
}
#[derive(Debug)]
pub struct BlockIdxGuard<'a>(usize, PhantomData<&'a ()>);
impl<'a> BlockIdxGuard<'a> {
pub fn new(idx: usize) -> Self { Self(idx, PhantomData) }
}
pub unsafe trait ExtractIdx<T> {
unsafe fn extract(&self) -> T;
}
unsafe impl<'a> ExtractIdx<usize> for BlockIdxGuard<'a> {
unsafe fn extract(&self) -> usize { self.0 }
}
unsafe impl<'a> ExtractIdx<(usize, usize)> for (BlockIdxGuard<'a>, BlockIdxGuard<'a>) {
unsafe fn extract(&self) -> (usize, usize) {
unsafe { (self.0.extract(), self.1.extract()) }
}
}
impl From<BlockError> for AllocError {
fn from(_: BlockError) -> Self { AllocError }
}
#[test]
fn cmp_adjacent() {
let (p1, p2, p3, p4) = (
NonNull::new(1 as *mut u8).unwrap(),
NonNull::new(2 as *mut u8).unwrap(),
NonNull::new(5 as *mut u8).unwrap(),
NonNull::new(12 as *mut u8).unwrap()
);
let (b1, b2, b3, b4) = (
Block { ptr: p1, size: NonZero::new(1).unwrap() },
Block { ptr: p2, size: NonZero::new(3).unwrap() },
Block { ptr: p3, size: NonZero::new(1).unwrap() },
Block { ptr: p4, size: NonZero::new(1).unwrap() },
);
assert_eq!(b1.cmp_adjacent(&b4), None);
assert_eq!(b2.cmp_adjacent(&b4), None);
assert_eq!(b3.cmp_adjacent(&b4), None);
assert_eq!(b4.cmp_adjacent(&b1), None);
assert_eq!(b4.cmp_adjacent(&b1), None);
assert_eq!(b4.cmp_adjacent(&b1), None);
assert_eq!(b1.cmp_adjacent(&b2), Some(Ordering::Less));
assert_eq!(b1.cmp_adjacent(&b3), None);
assert_eq!(b2.cmp_adjacent(&b1), Some(Ordering::Greater));
assert_eq!(b2.cmp_adjacent(&b3), Some(Ordering::Less));
assert_eq!(b3.cmp_adjacent(&b2), Some(Ordering::Greater));
assert_eq!(b3.cmp_adjacent(&b1), None);
}