slab_allocator_rs 1.0.2

Slab allocator for no_std systems. Uses multiple slabs with blocks of different sizes and a buddy system allocator for blocks larger than 4096 bytes. Updated to latest nightly rust
Documentation
use alloc::alloc::Layout;
use core::ptr::NonNull;

pub struct Slab {
  block_size: usize,
  free_block_list: FreeBlockList,
}

impl Slab {
  pub unsafe fn new(start_addr: usize, slab_size: usize, block_size: usize) -> Slab {
    let num_of_blocks = slab_size / block_size;
    Slab {
      block_size,
      free_block_list: FreeBlockList::new(start_addr, block_size, num_of_blocks),
    }
  }

  pub unsafe fn grow(&mut self, start_addr: usize, slab_size: usize) {
    let num_of_blocks = slab_size / self.block_size;
    let mut block_list = FreeBlockList::new(start_addr, self.block_size, num_of_blocks);
    while let Some(block) = block_list.pop() {
      self.free_block_list.push(block);
    }
  }

  //patched this to return `Err(())`, as the function calling this expects to return this too, because of a change in the linked list allocator
  pub fn allocate(&mut self, _layout: Layout) -> Result<NonNull<u8>, ()> {
    match self.free_block_list.pop() {
      Some(block) => Ok(unsafe { NonNull::new_unchecked(block.addr() as *mut u8) }),
      None => Err(()), //Err(AllocErr)
    }
  }

  /// Safety: ptr must have been previously allocated by self.
  pub unsafe fn deallocate(&mut self, ptr: NonNull<u8>) {
    // Since ptr was allocated by self, its alignment must be at least
    // the alignment of FreeBlock. Casting a less aligned pointer to
    // &mut FreeBlock would be undefined behavior.
    #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] let ptr = ptr.as_ptr() as *mut FreeBlock;
    self.free_block_list.push(&mut *ptr);
  }
}

struct FreeBlockList {
  len: usize,
  head: Option<&'static mut FreeBlock>,
}

impl FreeBlockList {
  unsafe fn new(start_addr: usize, block_size: usize, num_of_blocks: usize) -> FreeBlockList {
    let mut new_list = FreeBlockList { len: 0, head: None };
    for i in (0..num_of_blocks).rev() {
      let new_block = (start_addr + i * block_size) as *mut FreeBlock;
      new_list.push(&mut *new_block);
    }
    new_list
  }

  fn pop(&mut self) -> Option<&'static mut FreeBlock> {
    self.head.take().map(|node| {
      self.head = node.next.take();
      self.len -= 1;
      node
    })
  }

  fn push(&mut self, free_block: &'static mut FreeBlock) {
    free_block.next = self.head.take();
    self.len += 1;
    self.head = Some(free_block);
  }
}

impl Drop for FreeBlockList {
  fn drop(&mut self) {
    while self.pop().is_some() {}
  }
}

struct FreeBlock {
  next: Option<&'static mut FreeBlock>,
}

impl FreeBlock {
  fn addr(&self) -> usize {
    self as *const _ as usize
  }
}