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)]
25pub fn alloc(size: usize) -> Result<*mut u8, AllocationError> {
26 use AllocationError::{ArithmeticError, OutOfMemory};
27
28 let size = size
29 .div_ceil(ALIGNMENT)
30 .checked_add(1)
31 .ok_or(ArithmeticError)?
32 .checked_mul(ALIGNMENT)
33 .ok_or(ArithmeticError)?;
34
35 let layout = Layout::from_size_align(size, ALIGNMENT)?;
36
37 let ptr = unsafe { std::alloc::alloc(layout) };
38
39 if ptr.is_null() {
40 Err(OutOfMemory)?;
41 }
42
43 let allocation = unsafe { &mut *(ptr.cast::<Allocation>()) };
44
45 allocation.marker = MARKER_USED;
46 allocation.size = size;
47
48 let ptr = unsafe { ptr.add(ALIGNMENT) };
49
50 Ok(ptr)
51}
52
53pub fn free<T>(ptr: *mut T) -> Result<(), DeallocationError> {
61 use DeallocationError::{DoubleFree, ImproperAlignment, InvalidAllocation, NullPtr};
62
63 if ptr.is_null() {
64 Err(NullPtr)?;
65 }
66
67 let ptr = ptr.cast::<Allocation>();
68
69 if !ptr.is_aligned() {
70 Err(ImproperAlignment)?;
71 }
72
73 let ptr = unsafe { ptr.sub(1) };
74 let allocation = unsafe { &mut *ptr };
75
76 if allocation.marker == MARKER_FREE {
77 Err(DoubleFree)?;
78 } else if allocation.marker != MARKER_USED {
79 Err(InvalidAllocation)?;
80 }
81
82 let layout = Layout::from_size_align(allocation.size, ALIGNMENT)?;
83
84 allocation.marker = MARKER_FREE;
85
86 unsafe { std::alloc::dealloc(ptr.cast(), layout) }
87
88 Ok(())
89}