1mod error;
2
3use std::alloc::Layout;
4
5pub use error::*;
6
7pub const ALIGNMENT: usize = std::mem::size_of::<Allocation>();
8pub const MARKER_FREE: [u8; 8] = *b"Fr33Mmry";
9pub const MARKER_USED: [u8; 8] = *b"U53dMmry";
10
11#[repr(align(16))]
12struct Allocation {
13 marker: [u8; 8],
14 size: usize,
15}
16
17#[allow(clippy::cast_ptr_alignment)]
26pub fn alloc(size: usize) -> Result<*mut u8, AllocationError> {
27 let size = size
28 .checked_add(ALIGNMENT)
29 .ok_or(AllocationError::ArithmeticError)?
30 .checked_next_multiple_of(ALIGNMENT)
31 .ok_or(AllocationError::ArithmeticError)?;
32
33 let layout = Layout::from_size_align(size, ALIGNMENT)?;
34
35 let ptr = unsafe { std::alloc::alloc(layout) };
36
37 if ptr.is_null() {
38 return Err(AllocationError::OutOfMemory);
39 }
40
41 if 0 != (ptr as usize % ALIGNMENT) {
42 unsafe { std::alloc::dealloc(ptr, layout) };
43
44 return Err(AllocationError::ImproperAlignment);
45 }
46
47 let allocation = unsafe { &mut *(ptr.cast::<Allocation>()) };
48
49 allocation.marker = MARKER_USED;
50 allocation.size = size;
51
52 let ptr = unsafe { ptr.add(ALIGNMENT) };
53
54 Ok(ptr)
55}
56
57pub fn free<T>(ptr: *mut T) -> Result<(), DeallocationError> {
65 if ptr.is_null() {
66 return Err(DeallocationError::NullPtr);
67 }
68
69 let header_ptr = unsafe { ptr.cast::<u8>().sub(ALIGNMENT).cast::<Allocation>() };
70
71 if !header_ptr.is_aligned() {
72 return Err(DeallocationError::ImproperAlignment);
73 }
74
75 let allocation = unsafe { &mut *header_ptr };
76
77 if allocation.marker == MARKER_FREE {
78 return Err(DeallocationError::DoubleFree);
79 } else if allocation.marker != MARKER_USED {
80 return Err(DeallocationError::InvalidAllocation);
81 }
82
83 let layout = Layout::from_size_align(allocation.size, ALIGNMENT)?;
84
85 allocation.marker = MARKER_FREE;
86
87 unsafe { std::alloc::dealloc(header_ptr.cast(), layout) };
88
89 Ok(())
90}