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