1use core::cell::UnsafeCell;
9use core::fmt;
10use core::mem::MaybeUninit;
11use core::ops::{Deref, DerefMut};
12use core::ptr::NonNull;
13
14use core::sync::atomic::{AtomicU32, Ordering};
15
16use crate::config::PACKET_BUF_SIZE;
17use crate::meta::PacketMeta;
18
19#[cfg(not(test))]
20const PACKET_BUF_COUNT: usize = crate::config::PACKET_BUF_COUNT;
21#[cfg(test)]
24const PACKET_BUF_COUNT: usize = if crate::config::PACKET_BUF_COUNT > 1024 {
25 crate::config::PACKET_BUF_COUNT
26} else {
27 1024
28};
29
30const BITMAP_WORDS: usize = PACKET_BUF_COUNT.div_ceil(32);
31
32cfg_select! {
33 feature = "packet-buf-align-32" => { #[repr(C, align(32))] struct Data([u8; PACKET_BUF_SIZE]); }
34 feature = "packet-buf-align-16" => { #[repr(C, align(16))] struct Data([u8; PACKET_BUF_SIZE]); }
35 feature = "packet-buf-align-8" => { #[repr(C, align(8))] struct Data([u8; PACKET_BUF_SIZE]); }
36 feature = "packet-buf-align-4" => { #[repr(C, align(4))] struct Data([u8; PACKET_BUF_SIZE]); }
37 feature = "packet-buf-align-2" => { #[repr(C, align(2))] struct Data([u8; PACKET_BUF_SIZE]); }
38 _ => { #[repr(C, align(1))] struct Data([u8; PACKET_BUF_SIZE]); }
39}
40
41impl Deref for Data {
42 type Target = [u8; PACKET_BUF_SIZE];
43 fn deref(&self) -> &Self::Target {
44 &self.0
45 }
46}
47
48impl DerefMut for Data {
49 fn deref_mut(&mut self) -> &mut Self::Target {
50 &mut self.0
51 }
52}
53
54struct PacketBufInner {
55 headroom: u16,
57 len: u16,
59 meta: PacketMeta,
62 data: Data,
63}
64
65struct Pool {
66 used: [AtomicU32; BITMAP_WORDS],
68 slots: [UnsafeCell<MaybeUninit<PacketBufInner>>; PACKET_BUF_COUNT],
69}
70
71unsafe impl Sync for Pool {}
76
77static POOL: Pool = Pool {
78 used: [const { AtomicU32::new(0) }; BITMAP_WORDS],
79 slots: [const { UnsafeCell::new(MaybeUninit::zeroed()) }; PACKET_BUF_COUNT],
80};
81
82#[cfg(target_has_atomic = "32")]
84#[inline(never)]
85fn alloc_slot() -> Option<usize> {
86 for (w, word) in POOL.used.iter().enumerate() {
87 let mut cur = word.load(Ordering::Relaxed);
88 loop {
89 let bit = cur.trailing_ones() as usize;
90 if bit >= 32 {
91 break;
92 }
93 let index = w * 32 + bit;
94 if index >= PACKET_BUF_COUNT {
95 return None;
98 }
99 match word.compare_exchange_weak(cur, cur | (1 << bit), Ordering::Acquire, Ordering::Relaxed) {
102 Ok(_) => return Some(index),
103 Err(actual) => cur = actual,
104 }
105 }
106 }
107 None
108}
109
110#[cfg(target_has_atomic = "32")]
112#[inline(never)]
113fn free_slot(index: usize) {
114 POOL.used[index / 32].fetch_and(!(1 << (index % 32)), Ordering::Release);
115}
116
117#[cfg(not(target_has_atomic = "32"))]
125fn alloc_slot() -> Option<usize> {
126 critical_section::with(|_| {
127 for (w, word) in POOL.used.iter().enumerate() {
128 let cur = word.load(Ordering::Acquire);
129 let bit = cur.trailing_ones() as usize;
130 if bit >= 32 {
131 continue;
132 }
133 let index = w * 32 + bit;
134 if index >= PACKET_BUF_COUNT {
135 return None;
138 }
139 word.store(cur | (1 << bit), Ordering::Relaxed);
140 return Some(index);
141 }
142 None
143 })
144}
145
146#[cfg(not(target_has_atomic = "32"))]
148fn free_slot(index: usize) {
149 critical_section::with(|_| {
150 let word = &POOL.used[index / 32];
151 word.store(word.load(Ordering::Relaxed) & !(1 << (index % 32)), Ordering::Release);
152 })
153}
154
155pub struct PacketBuf {
161 inner: NonNull<PacketBufInner>,
162}
163
164unsafe impl Send for PacketBuf {}
166unsafe impl Sync for PacketBuf {}
167
168impl PacketBuf {
169 pub fn try_new() -> Option<Self> {
175 let index = alloc_slot()?;
176 let ptr = POOL.slots[index].get().cast::<PacketBufInner>();
177 unsafe {
182 (&raw mut (*ptr).headroom).write(0);
183 (&raw mut (*ptr).len).write(0);
184 (&raw mut (*ptr).meta).write(PacketMeta::default());
185 #[cfg(test)]
187 (*ptr).data.fill(0xa5);
188 }
189 Some(Self {
190 inner: unsafe { NonNull::new_unchecked(ptr) },
192 })
193 }
194
195 #[inline]
196 fn inner(&self) -> &PacketBufInner {
197 unsafe { self.inner.as_ref() }
199 }
200
201 #[inline]
202 fn inner_mut(&mut self) -> &mut PacketBufInner {
203 unsafe { self.inner.as_mut() }
206 }
207
208 pub fn meta(&self) -> PacketMeta {
215 self.inner().meta
216 }
217
218 pub fn meta_mut(&mut self) -> &mut PacketMeta {
220 &mut self.inner_mut().meta
221 }
222
223 pub fn set_meta(&mut self, meta: PacketMeta) {
225 self.inner_mut().meta = meta;
226 }
227
228 pub const fn capacity(&self) -> usize {
230 PACKET_BUF_SIZE
231 }
232
233 pub fn headroom(&self) -> usize {
235 self.inner().headroom as usize
236 }
237
238 pub fn len(&self) -> usize {
240 self.inner().len as usize
241 }
242
243 pub fn is_empty(&self) -> bool {
245 self.inner().len == 0
246 }
247
248 pub fn tailroom(&self) -> usize {
250 PACKET_BUF_SIZE - self.headroom() - self.len()
251 }
252
253 pub fn reserve(&mut self, headroom: usize) {
258 assert!(self.inner().len == 0);
259 assert!(headroom <= PACKET_BUF_SIZE);
260 self.inner_mut().headroom = headroom as u16;
261 }
262
263 pub fn push_front(&mut self, n: usize) {
268 assert!(n <= self.headroom());
269 let inner = self.inner_mut();
270 inner.headroom -= n as u16;
271 inner.len += n as u16;
272 }
273
274 pub fn pull_front(&mut self, n: usize) {
279 assert!(n <= self.len());
280 let inner = self.inner_mut();
281 inner.headroom += n as u16;
282 inner.len -= n as u16;
283 }
284
285 pub fn ensure_headroom(&mut self, headroom: usize) -> bool {
291 if self.headroom() >= headroom {
292 return true;
293 }
294 let inner = self.inner_mut();
295 let len = inner.len as usize;
296 if headroom + len > PACKET_BUF_SIZE {
297 return false;
298 }
299 let old = inner.headroom as usize;
300 inner.data.copy_within(old..old + len, headroom);
301 inner.headroom = headroom as u16;
302 true
303 }
304
305 pub fn set_len(&mut self, len: usize) {
310 assert!(self.headroom() + len <= PACKET_BUF_SIZE);
311 self.inner_mut().len = len as u16;
312 }
313
314 pub fn storage_mut(&mut self) -> &mut [u8] {
319 &mut self.inner_mut().data[..]
320 }
321}
322
323impl Drop for PacketBuf {
324 #[inline(never)] fn drop(&mut self) {
326 let base = POOL.slots.as_ptr() as usize;
327 let index =
328 (self.inner.as_ptr() as usize - base) / core::mem::size_of::<UnsafeCell<MaybeUninit<PacketBufInner>>>();
329 free_slot(index);
330 }
331}
332
333impl Deref for PacketBuf {
334 type Target = [u8];
335 fn deref(&self) -> &Self::Target {
336 let inner = self.inner();
337 let start = inner.headroom as usize;
338 let end = start + inner.len as usize;
339 &inner.data[start..end]
340 }
341}
342impl DerefMut for PacketBuf {
343 fn deref_mut(&mut self) -> &mut Self::Target {
344 let inner = self.inner_mut();
345 let start = inner.headroom as usize;
346 let end = start + inner.len as usize;
347 &mut inner.data[start..end]
348 }
349}
350
351impl fmt::Debug for PacketBuf {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 f.debug_struct("PacketBuf")
354 .field("headroom", &self.headroom())
355 .field("len", &self.len())
356 .finish()
357 }
358}
359
360#[cfg(feature = "defmt")]
361impl defmt::Format for PacketBuf {
362 fn format(&self, f: defmt::Formatter<'_>) {
363 defmt::write!(f, "PacketBuf {{ headroom: {}, len: {} }}", self.headroom(), self.len());
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370 use crate::config::PACKET_BUF_ALIGN;
371
372 #[test]
373 fn push_pull() {
374 let mut buf = PacketBuf::try_new().unwrap();
375 assert_eq!(buf.len(), 0);
376 assert_eq!(buf.headroom(), 0);
377 assert_eq!(buf.tailroom(), PACKET_BUF_SIZE);
378
379 buf.reserve(42);
380 assert_eq!(buf.headroom(), 42);
381 buf.set_len(100);
382 assert_eq!(buf.len(), 100);
383 assert_eq!(buf.tailroom(), PACKET_BUF_SIZE - 142);
384 buf.fill(0xaa);
385
386 buf.push_front(20);
387 assert_eq!(buf.headroom(), 22);
388 assert_eq!(buf.len(), 120);
389 assert_eq!(buf[20], 0xaa);
390
391 buf.pull_front(20);
392 assert_eq!(buf.headroom(), 42);
393 assert_eq!(buf.len(), 100);
394 assert_eq!(buf[0], 0xaa);
395 }
396
397 #[test]
398 fn ensure_headroom() {
399 let mut buf = PacketBuf::try_new().unwrap();
400 buf.reserve(10);
401 buf.set_len(4);
402 buf.copy_from_slice(&[1, 2, 3, 4]);
403
404 assert!(buf.ensure_headroom(4));
406 assert_eq!(buf.headroom(), 10);
407 assert_eq!(&*buf, &[1, 2, 3, 4]);
408
409 assert!(buf.ensure_headroom(20));
411 assert_eq!(buf.headroom(), 20);
412 assert_eq!(buf.len(), 4);
413 assert_eq!(&*buf, &[1, 2, 3, 4]);
414
415 assert!(buf.ensure_headroom(22));
417 assert_eq!(&*buf, &[1, 2, 3, 4]);
418
419 assert!(!buf.ensure_headroom(PACKET_BUF_SIZE - 3));
421 assert_eq!(buf.headroom(), 22);
422 assert_eq!(&*buf, &[1, 2, 3, 4]);
423 assert!(buf.ensure_headroom(PACKET_BUF_SIZE - 4));
424 assert_eq!(&*buf, &[1, 2, 3, 4]);
425 }
426
427 #[test]
428 #[should_panic]
429 fn push_beyond_headroom() {
430 let mut buf = PacketBuf::try_new().unwrap();
431 buf.push_front(1);
432 }
433
434 #[test]
438 fn storage_is_dma_shaped() {
439 let mut buf = PacketBuf::try_new().unwrap();
440 assert_eq!(buf.storage_mut().as_ptr() as usize % PACKET_BUF_ALIGN, 0);
441 assert_eq!(buf.storage_mut().len() % PACKET_BUF_ALIGN, 0);
442 assert!(buf.storage_mut().len() >= PACKET_BUF_SIZE);
443 }
444
445 #[test]
449 fn fresh_buffer_is_reset() {
450 let mut buf = PacketBuf::try_new().unwrap();
451 buf.reserve(100);
452 buf.set_len(200);
453 buf.fill(0xff);
454 drop(buf);
455
456 let buf = PacketBuf::try_new().unwrap();
457 assert_eq!(buf.len(), 0);
458 assert_eq!(buf.headroom(), 0);
459 assert_eq!(buf.meta(), PacketMeta::default());
460 }
461
462 #[cfg(feature = "packetmeta-id")]
465 #[test]
466 fn meta_travels_with_the_buffer() {
467 let mut buf = PacketBuf::try_new().unwrap();
468 assert_eq!(buf.meta(), PacketMeta::default());
469
470 buf.meta_mut().id = 0xdead_beef;
471 buf.reserve(20);
472 buf.set_len(10);
473 buf.push_front(20);
474 buf.pull_front(4);
475 assert_eq!(buf.meta().id, 0xdead_beef);
476
477 buf.set_meta(PacketMeta::default());
478 assert_eq!(buf.meta().id, 0);
479 }
480}