use std::alloc::Layout;
use std::ptr;
use std::ptr::NonNull;
use std::sync::atomic::{AtomicPtr, Ordering};
#[repr(C)]
#[derive(Debug)]
pub(super) struct ChunkFooter {
pub(super) bottom: NonNull<u8>,
pub(super) layout: Layout,
pub(super) prev: NonNull<ChunkFooter>,
pub(super) top: AtomicPtr<u8>,
pub(super) allocated_bytes: usize,
}
#[repr(transparent)]
pub(super) struct EmptyChunkFooter(ChunkFooter);
unsafe impl Sync for EmptyChunkFooter {}
pub(super) static EMPTY_CHUNK: EmptyChunkFooter = EmptyChunkFooter(ChunkFooter {
bottom: unsafe { NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut u8) },
layout: Layout::new::<ChunkFooter>(),
prev: unsafe {
NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut ChunkFooter)
},
top: AtomicPtr::new(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut u8),
allocated_bytes: 0,
});
impl EmptyChunkFooter {
pub(super) fn get(&'static self) -> AtomicPtr<ChunkFooter> {
AtomicPtr::new(&self.0 as *const ChunkFooter as *mut ChunkFooter)
}
pub(super) unsafe fn get_ptr(&'static self) -> *mut ChunkFooter {
&self.0 as *const ChunkFooter as *mut ChunkFooter
}
}
impl ChunkFooter {
#[cfg(test)]
fn get_current_top_and_allocated_size(&self) -> (*const u8, usize) {
let bottom = self.bottom.as_ptr() as *const u8;
let top = self.top.load(Ordering::SeqCst) as *const u8;
debug_assert!(bottom <= top);
debug_assert!(top <= self as *const ChunkFooter as *const u8);
let len = unsafe { (self as *const ChunkFooter as *const u8).offset_from(top) as usize };
(top, len)
}
pub(super) fn is_empty(&self) -> bool {
ptr::eq(self, EMPTY_CHUNK.get().load(Ordering::SeqCst))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_chunk_initialization_and_size() {
let empty_ref = unsafe { &*EMPTY_CHUNK.get_ptr() };
assert!(
empty_ref.is_empty(),
"EMPTY_CHUNK should be identified as empty"
);
assert_eq!(
empty_ref.allocated_bytes, 0,
"EMPTY_CHUNK should have 0 allocated bytes"
);
assert_eq!(
empty_ref.prev.as_ptr(),
empty_ref as *const _ as *mut _,
"EMPTY_CHUNK's prev should point to itself"
);
let (top_ptr, allocated_size) = empty_ref.get_current_top_and_allocated_size();
let expected_top_ptr = empty_ref as *const _ as *const u8;
assert_eq!(
top_ptr, expected_top_ptr,
"Top pointer should point to the end of the footer itself"
);
assert_eq!(
allocated_size, 0,
"Allocated size within the empty chunk should be 0"
);
}
}