1use core::marker::PhantomData;
10use core::mem::MaybeUninit;
11use core::pin::Pin;
12use core::ptr::NonNull;
13
14use embassy_sync::blocking_mutex::raw::RawMutex;
15use rs_matter::utils::cell::RefCell;
16use rs_matter::utils::init::{init, zeroed, Init};
17use rs_matter::utils::sync::blocking::raw::MatterRawMutex;
18use rs_matter::utils::sync::blocking::Mutex;
19
20#[macro_export]
21macro_rules! alloc {
22 ($bump:expr, $obj:expr) => {
23 $bump.alloc($obj, concat!(file!(), ":", line!()))
24 };
25}
26
27#[macro_export]
28macro_rules! pin_alloc {
29 ($bump:expr, $obj:expr) => {
30 $bump.pin_alloc($obj, concat!(file!(), ":", line!()))
31 };
32}
33
34pub struct Bump<const N: usize, M = MatterRawMutex> {
36 inner: Mutex<RefCell<Inner<N>>, M>,
37}
38
39impl<const N: usize, M: RawMutex> Default for Bump<N, M> {
40 fn default() -> Self {
41 Self::new()
42 }
43}
44
45impl<const N: usize, M: RawMutex> Bump<N, M> {
46 pub const fn new() -> Self {
48 Self {
49 inner: Mutex::new(RefCell::new(Inner::new())),
50 }
51 }
52
53 pub fn init() -> impl Init<Self> {
55 init!(Self {
56 inner <- Mutex::init(RefCell::init(Inner::init())),
57 })
58 }
59
60 pub unsafe fn reset(&self) {
69 self.inner.lock(|inner| {
70 let mut inner = inner.borrow_mut();
71
72 inner.offset = 0;
73 });
74 }
75
76 pub fn pin_alloc<T>(&self, object: T, location: &str) -> Pin<BumpBox<'_, T>>
85 where
86 T: Sized,
87 {
88 let boxed = self.alloc(object, location);
89
90 boxed.into_pin()
91 }
92
93 pub fn alloc<T>(&self, object: T, location: &str) -> BumpBox<'_, T>
102 where
103 T: Sized,
104 {
105 self.inner.lock(|inner| {
106 let mut inner = inner.borrow_mut();
107
108 let size = core::mem::size_of_val(&object);
109
110 let offset = inner.offset;
111 let memory = unsafe { inner.memory.assume_init_mut() };
112
113 info!(
114 "BUMP[{}]: {}b (U:{}b/F:{}b)",
115 location,
116 size,
117 offset,
118 memory.len() - offset
119 );
120
121 let remaining = &mut memory[offset..];
122 let remaining_len = remaining.len();
123
124 let (t_buf, r_buf) = align_min::<T>(remaining, 1);
125
126 let ptr = unsafe {
128 let ptr = t_buf.as_ptr() as *mut T;
129 ptr.write(object);
130
131 NonNull::new_unchecked(ptr)
132 };
133
134 inner.offset += remaining_len - r_buf.len();
135
136 BumpBox {
137 ptr,
138 _allocator: PhantomData,
139 }
140 })
141 }
142}
143
144pub struct BumpBox<'a, T> {
146 ptr: NonNull<T>,
147 _allocator: core::marker::PhantomData<&'a ()>,
148}
149
150impl<T> BumpBox<'_, T> {
151 pub fn into_pin(self) -> Pin<Self> {
153 unsafe { Pin::new_unchecked(self) }
157 }
158}
159
160impl<T> core::ops::Deref for BumpBox<'_, T> {
161 type Target = T;
162
163 fn deref(&self) -> &Self::Target {
164 unsafe { self.ptr.as_ref() }
165 }
166}
167
168impl<T> core::ops::DerefMut for BumpBox<'_, T> {
169 fn deref_mut(&mut self) -> &mut Self::Target {
170 unsafe { self.ptr.as_mut() }
171 }
172}
173
174impl<T> Unpin for BumpBox<'_, T> {}
175
176impl<T> Drop for BumpBox<'_, T> {
177 fn drop(&mut self) {
178 unsafe {
180 self.ptr.as_ptr().drop_in_place();
181 }
182 }
183}
184
185struct Inner<const N: usize> {
186 memory: MaybeUninit<[u8; N]>,
187 offset: usize,
188}
189
190impl<const N: usize> Inner<N> {
191 const fn new() -> Self {
192 Self {
193 memory: MaybeUninit::uninit(),
194 offset: 0,
195 }
196 }
197
198 fn init() -> impl Init<Self> {
199 init!(Self {
200 memory <- zeroed(),
201 offset: 0,
202 })
203 }
204}
205
206fn align_min<T>(buf: &mut [u8], count: usize) -> (&mut [MaybeUninit<T>], &mut [u8]) {
207 if count == 0 || core::mem::size_of::<T>() == 0 {
208 return (&mut [], buf);
209 }
210
211 let (t_leading_buf0, t_buf, _) = unsafe { buf.align_to_mut::<MaybeUninit<T>>() };
212 if t_buf.len() < count {
213 panic!("Out of bump memory");
214 }
215
216 let t_buf = &mut t_buf[..count];
218 let t_leading_buf0_len = t_leading_buf0.len();
219 let t_buf_size = core::mem::size_of_val(t_buf);
220
221 let (buf0, remaining_buf) = buf.split_at_mut(t_leading_buf0_len + t_buf_size);
222
223 let (t_leading_buf, t_buf, t_remaining_buf) = unsafe { buf0.align_to_mut::<MaybeUninit<T>>() };
224 assert_eq!(t_leading_buf0_len, t_leading_buf.len());
225 assert_eq!(t_buf.len(), count);
226 assert!(t_remaining_buf.is_empty());
227
228 (t_buf, remaining_buf)
229}