customizable-buddy 0.0.4

A new buddy allocator that allows custom buddy finding algorithm
Documentation
use customizable_buddy::{
    BuddyAllocator, BuddyCollection, BuddyLine, LinkedListBuddy, OligarchyCollection,
};
use std::{collections::BTreeSet, fmt, mem::MaybeUninit, ptr::NonNull};

fn main() {
    let mut allocator = BuddyAllocator::<16, BuddySet, LinkedListBuddy>::new();
    allocator.init(12, non_null(0x1000));
    println!();
    assert!(allocator.allocate_type::<usize>().is_err());
    println!();
    unsafe { allocator.transfer(non_null(0x1000), 0x7fff_f000) };

    println!();
    println!("A {allocator:?}");
    let (ptr0, size0) = allocator.allocate_type::<[u8; 2048]>().unwrap();
    println!("B {allocator:?}");
    let (ptr1, size1) = allocator.allocate_type::<[u8; 4096]>().unwrap();
    println!("C {allocator:?}");
    let (ptr2, size2) = allocator.allocate_type::<[u8; 4096 * 3 - 100]>().unwrap();
    println!("D {allocator:?}");

    assert_eq!(4096, size0);
    assert_eq!(4096, size1);
    assert_eq!(4096 * 3, size2);

    println!();
    println!("{allocator:?}");
    allocator.deallocate(ptr0, size0);
    println!("{allocator:?}");
    allocator.deallocate(ptr1, size1);
    println!("{allocator:?}");
    allocator.deallocate(ptr2, size2);
    println!("{allocator:?}");
}

#[inline]
fn non_null(addr: usize) -> NonNull<u8> {
    NonNull::new(addr as *mut _).unwrap()
}

struct BuddySet {
    set: MaybeUninit<BTreeSet<usize>>,
    order: usize,
}

impl BuddyLine for BuddySet {
    const EMPTY: Self = Self {
        set: MaybeUninit::uninit(),
        order: 0,
    };

    fn init(&mut self, order: usize, base: usize) {
        self.order = order;
        println!("Buddies[{order}] init as base = {base} order = {order}");
    }

    fn take(&mut self, idx: usize) -> bool {
        println!("Buddies[{}] take at {idx}", self.order);
        unsafe { self.set.assume_init_mut() }.remove(&idx)
    }
}

impl OligarchyCollection for BuddySet {
    fn take_any(&mut self, align_order: usize, count: usize) -> Option<usize> {
        println!(
            "Buddies[{}] take {count} with align = {align_order}",
            self.order
        );
        assert!(count == 1);
        let set = unsafe { self.set.assume_init_mut() };
        if let Some(&i) = set.iter().next() {
            set.remove(&i);
            Some(i)
        } else {
            None
        }
    }

    fn put(&mut self, idx: usize) {
        println!("Buddies[{}] put oligarchy at {idx}", self.order);

        unsafe { self.set.assume_init_mut() }.insert(idx);
    }
}

impl BuddyCollection for BuddySet {
    fn take_any(&mut self, align_order: usize) -> Option<usize> {
        println!("Buddies[{}] take 1 with align = {align_order}", self.order);
        let set = unsafe { self.set.assume_init_mut() };
        if let Some(&i) = set.iter().next() {
            set.remove(&i);
            Some(i)
        } else {
            None
        }
    }

    fn put(&mut self, idx: usize) -> Option<usize> {
        println!("Buddies[{}] put buddy at = {idx}", self.order);
        let set = unsafe { self.set.assume_init_mut() };
        if set.remove(&(idx ^ 1)) {
            Some(idx >> 1)
        } else {
            set.insert(idx);
            None
        }
    }
}

impl fmt::Debug for BuddySet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", unsafe { self.set.assume_init_ref() })
    }
}