1#[cfg(not(feature = "std"))]
4extern crate alloc;
5
6use alloc::boxed::Box;
7use alloc::vec::Vec;
8
9use bincode::{Decode, Encode};
10use core::fmt;
11
12use core::fmt::Display;
13use core::iter::{Chain, Rev};
14use core::slice::{Iter as SliceIter, IterMut as SliceIterMut};
15use cu29_traits::{CopperListTuple, ErasedCuStampedData, ErasedCuStampedDataSet};
16use serde_derive::{Deserialize, Serialize};
17
18const MAX_TASKS: usize = 512;
19
20#[derive(Debug, Encode, Decode, PartialEq, Clone, Copy)]
23pub struct CopperLiskMask {
24 #[allow(dead_code)]
25 mask: [u128; MAX_TASKS / 128 + 1],
26}
27
28#[derive(Debug, Encode, Decode, Serialize, Deserialize, PartialEq, Copy, Clone)]
30pub enum CopperListState {
31 Free,
32 Initialized,
33 Processing,
34 DoneProcessing,
35 QueuedForSerialization,
36 BeingSerialized,
37}
38
39impl Display for CopperListState {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 CopperListState::Free => write!(f, "Free"),
43 CopperListState::Initialized => write!(f, "Initialized"),
44 CopperListState::Processing => write!(f, "Processing"),
45 CopperListState::DoneProcessing => write!(f, "DoneProcessing"),
46 CopperListState::QueuedForSerialization => write!(f, "QueuedForSerialization"),
47 CopperListState::BeingSerialized => write!(f, "BeingSerialized"),
48 }
49 }
50}
51
52#[derive(Debug, Encode, Decode, Serialize, Deserialize)]
55pub struct CopperList<P: CopperListTuple> {
56 pub id: u64,
57 #[bincode(skip, default = "deserialized_state")]
59 #[serde(skip, default = "deserialized_state")]
60 state: CopperListState,
61 pub msgs: P, }
63
64fn deserialized_state() -> CopperListState {
65 CopperListState::BeingSerialized
66}
67
68impl<P: CopperListTuple> Default for CopperList<P> {
69 fn default() -> Self {
70 CopperList {
71 id: 0,
72 state: CopperListState::Free,
73 msgs: P::default(),
74 }
75 }
76}
77
78impl<P: CopperListTuple> CopperList<P> {
79 pub fn new(id: u64, msgs: P) -> Self {
81 CopperList {
82 id,
83 state: CopperListState::Initialized,
84 msgs,
85 }
86 }
87
88 pub fn change_state(&mut self, new_state: CopperListState) {
89 self.state = new_state; }
91
92 pub fn get_state(&self) -> CopperListState {
93 self.state
94 }
95
96 #[doc(hidden)]
99 pub fn reset_for_runtime_use(&mut self, id: u64)
100 where
101 P: CuListZeroedInit,
102 {
103 self.id = id;
104 self.state = CopperListState::Initialized;
105 self.msgs.init_zeroed();
106 }
107
108 pub(crate) unsafe fn init_in_place(dst: *mut Self)
114 where
115 P: CuListZeroedInit,
116 {
117 unsafe {
120 core::ptr::addr_of_mut!((*dst).id).write(0);
121 core::ptr::addr_of_mut!((*dst).state).write(CopperListState::Free);
122 let msgs = core::ptr::addr_of_mut!((*dst).msgs);
123 let initialized = P::init_in_place(&mut *msgs.cast::<core::mem::MaybeUninit<P>>());
124 assert!(
125 core::ptr::eq(initialized, msgs),
126 "initializer returned a different slot"
127 );
128 }
129 }
130}
131
132impl<P: CopperListTuple> ErasedCuStampedDataSet for CopperList<P> {
133 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
134 self.msgs.cumsgs()
135 }
136}
137
138pub struct CuListsManager<P: CopperListTuple, const N: usize> {
142 data: Box<[CopperList<P>; N]>,
143 length: usize,
144 insertion_index: usize,
145 current_cl_id: u64,
146}
147
148impl<P: CopperListTuple + fmt::Debug, const N: usize> fmt::Debug for CuListsManager<P, N> {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 f.debug_struct("CuListsManager")
151 .field("data", &self.data)
152 .field("length", &self.length)
153 .field("insertion_index", &self.insertion_index)
154 .finish()
156 }
157}
158
159pub type Iter<'a, T> = Chain<Rev<SliceIter<'a, T>>, Rev<SliceIter<'a, T>>>;
160pub type IterMut<'a, T> = Chain<Rev<SliceIterMut<'a, T>>, Rev<SliceIterMut<'a, T>>>;
161pub type AscIter<'a, T> = Chain<SliceIter<'a, T>, SliceIter<'a, T>>;
162pub type AscIterMut<'a, T> = Chain<SliceIterMut<'a, T>, SliceIterMut<'a, T>>;
163
164pub trait CuListZeroedInit: CopperListTuple {
170 #[doc(hidden)]
172 const DISTRIBUTED: bool = false;
173
174 fn init_zeroed(&mut self);
176
177 #[doc(hidden)]
183 fn init_in_place(dst: &mut core::mem::MaybeUninit<Self>) -> &mut Self {
184 dst.write(Self::default())
185 }
186}
187
188impl<P: CopperListTuple + CuListZeroedInit, const N: usize> Default for CuListsManager<P, N> {
189 fn default() -> Self {
190 Self::new()
191 }
192}
193
194impl<P: CopperListTuple, const N: usize> CuListsManager<P, N> {
195 pub fn new() -> Self
196 where
197 P: CuListZeroedInit,
198 {
199 let mut slots = Vec::<CopperList<P>>::with_capacity(N);
200 for index in 0..N {
201 unsafe {
205 CopperList::init_in_place(slots.as_mut_ptr().add(index));
206 slots.set_len(index + 1);
207 }
208 }
209 let data = unsafe {
211 Box::from_raw(Box::into_raw(slots.into_boxed_slice()) as *mut [CopperList<P>; N])
212 };
213 CuListsManager {
214 data,
215 length: 0,
216 insertion_index: 0,
217 current_cl_id: 0,
218 }
219 }
220
221 #[inline]
224 pub fn len(&self) -> usize {
225 self.length
226 }
227
228 #[inline]
231 pub fn is_empty(&self) -> bool {
232 self.length == 0
233 }
234
235 #[inline]
238 pub fn is_full(&self) -> bool {
239 N == self.len()
240 }
241
242 #[inline]
245 pub fn clear(&mut self) {
246 self.insertion_index = 0;
247 self.length = 0;
248 }
249
250 #[inline]
251 pub fn create(&mut self) -> Option<&mut CopperList<P>>
252 where
253 P: CuListZeroedInit,
254 {
255 if self.is_full() {
256 return None;
257 }
258 let next_id = self.current_cl_id;
259 let result = &mut self.data[self.insertion_index];
260 self.insertion_index = (self.insertion_index + 1) % N;
261 self.length += 1;
262
263 result.reset_for_runtime_use(next_id);
265 self.current_cl_id += 1;
266
267 Some(result)
268 }
269
270 #[inline]
272 pub fn next_cl_id(&self) -> u64 {
273 self.current_cl_id
274 }
275
276 pub(crate) fn set_next_replay_id(&mut self, id: u64) {
277 debug_assert_eq!(self.length, 0);
278 self.current_cl_id = id;
279 }
280
281 #[inline]
285 pub fn last_cl_id(&self) -> u64 {
286 self.current_cl_id.saturating_sub(1)
287 }
288
289 #[inline]
291 pub fn peek(&self) -> Option<&CopperList<P>> {
292 if self.length == 0 {
293 return None;
294 }
295 let index = if self.insertion_index == 0 {
296 N - 1
297 } else {
298 self.insertion_index - 1
299 };
300 Some(&self.data[index])
301 }
302
303 #[inline]
304 #[allow(dead_code)]
305 fn drop_last(&mut self) {
306 if self.length == 0 {
307 return;
308 }
309 if self.insertion_index == 0 {
310 self.insertion_index = N - 1;
311 } else {
312 self.insertion_index -= 1;
313 }
314 self.length -= 1;
315 }
316
317 #[inline]
318 pub fn pop(&mut self) -> Option<&mut CopperList<P>> {
319 if self.length == 0 {
320 return None;
321 }
322 if self.insertion_index == 0 {
323 self.insertion_index = N - 1;
324 } else {
325 self.insertion_index -= 1;
326 }
327 self.length -= 1;
328 Some(&mut self.data[self.insertion_index])
329 }
330
331 #[inline]
336 pub fn iter(&self) -> Iter<'_, CopperList<P>> {
337 let (a, b) = self.data[0..self.length].split_at(self.insertion_index);
338 a.iter().rev().chain(b.iter().rev())
339 }
340
341 #[inline]
346 pub fn iter_mut(&mut self) -> IterMut<'_, CopperList<P>> {
347 let (a, b) = self.data[0..self.length].split_at_mut(self.insertion_index);
348 a.iter_mut().rev().chain(b.iter_mut().rev())
349 }
350
351 #[inline]
356 pub fn asc_iter(&self) -> AscIter<'_, CopperList<P>> {
357 let (a, b) = self.data[0..self.length].split_at(self.insertion_index);
358 b.iter().chain(a.iter())
359 }
360
361 #[inline]
366 pub fn asc_iter_mut(&mut self) -> AscIterMut<'_, CopperList<P>> {
367 let (a, b) = self.data[0..self.length].split_at_mut(self.insertion_index);
368 b.iter_mut().chain(a.iter_mut())
369 }
370}
371
372#[repr(C, align(128))]
374#[derive(Default, Debug, Encode, Decode, Serialize, Deserialize)]
375#[serde(transparent)]
376#[doc(hidden)]
377pub struct MessageRegion<T> {
378 pub value: T,
379}
380
381impl<T> From<T> for MessageRegion<T> {
382 fn from(value: T) -> Self {
383 Self { value }
384 }
385}
386
387impl<T> core::ops::Deref for MessageRegion<T> {
388 type Target = T;
389
390 fn deref(&self) -> &Self::Target {
391 &self.value
392 }
393}
394
395impl<T> core::ops::DerefMut for MessageRegion<T> {
396 fn deref_mut(&mut self) -> &mut Self::Target {
397 &mut self.value
398 }
399}
400
401#[repr(C, align(128))]
403#[doc(hidden)]
404pub struct ComponentRegion<T> {
405 pub value: T,
406}
407
408impl<T> ComponentRegion<T> {
409 pub const fn new(value: T) -> Self {
410 Self { value }
411 }
412}
413
414impl<T> core::ops::Deref for ComponentRegion<T> {
415 type Target = T;
416
417 fn deref(&self) -> &Self::Target {
418 &self.value
419 }
420}
421
422impl<T> core::ops::DerefMut for ComponentRegion<T> {
423 fn deref_mut(&mut self) -> &mut Self::Target {
424 &mut self.value
425 }
426}
427
428impl<T: crate::cutask::Freezable> crate::cutask::Freezable for ComponentRegion<T> {
429 #[inline(always)]
430 fn freeze<E: bincode::enc::Encoder>(
431 &self,
432 encoder: &mut E,
433 ) -> Result<(), bincode::error::EncodeError> {
434 self.value.freeze(encoder)
435 }
436
437 #[inline(always)]
438 fn thaw<D: bincode::de::Decoder>(
439 &mut self,
440 decoder: &mut D,
441 ) -> Result<(), bincode::error::DecodeError> {
442 self.value.thaw(decoder)
443 }
444}
445
446#[cfg(test)]
447mod tests {
448 use super::*;
449 use cu29_traits::{ErasedCuStampedData, ErasedCuStampedDataSet, MatchingTasks};
450 use serde::{Deserialize, Serialize, Serializer};
451
452 #[derive(Debug, Encode, Decode, PartialEq, Clone, Copy, Serialize, Deserialize, Default)]
453 struct CuStampedDataSet(i32);
454
455 #[test]
456 fn independently_written_regions_are_cache_isolated() {
457 assert_eq!(core::mem::align_of::<MessageRegion<u8>>(), 128);
458 assert_eq!(core::mem::size_of::<MessageRegion<u8>>(), 128);
459 assert_eq!(core::mem::align_of::<ComponentRegion<u8>>(), 128);
460 assert_eq!(core::mem::size_of::<ComponentRegion<u8>>(), 128);
461
462 let messages = [MessageRegion::from(0u8), MessageRegion::from(1u8)];
463 let first = core::ptr::addr_of!(messages[0]) as usize;
464 let second = core::ptr::addr_of!(messages[1]) as usize;
465 assert_eq!(first % 128, 0);
466 assert_eq!(second - first, 128);
467 }
468
469 impl ErasedCuStampedDataSet for CuStampedDataSet {
470 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
471 Vec::new()
472 }
473 }
474
475 impl MatchingTasks for CuStampedDataSet {
476 fn get_all_task_ids() -> &'static [&'static str] {
477 &[]
478 }
479 }
480
481 impl CuListZeroedInit for CuStampedDataSet {
482 fn init_zeroed(&mut self) {}
483 }
484
485 #[derive(Debug, Default, Encode, Decode, Serialize, Deserialize)]
486 struct WrongSlot;
487
488 impl ErasedCuStampedDataSet for WrongSlot {
489 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
490 Vec::new()
491 }
492 }
493
494 impl MatchingTasks for WrongSlot {
495 fn get_all_task_ids() -> &'static [&'static str] {
496 &[]
497 }
498 }
499
500 impl CuListZeroedInit for WrongSlot {
501 fn init_zeroed(&mut self) {}
502
503 fn init_in_place(_dst: &mut core::mem::MaybeUninit<Self>) -> &mut Self {
504 Box::leak(Box::new(Self))
505 }
506 }
507
508 #[test]
509 #[should_panic(expected = "initializer returned a different slot")]
510 fn rejects_initializer_returning_another_slot() {
511 let _ = CuListsManager::<WrongSlot, 1>::new();
512 }
513
514 #[test]
515 fn serialization_omits_runtime_state() {
516 let expected =
517 bincode::encode_to_vec((42u64, CuStampedDataSet(123)), bincode::config::standard())
518 .unwrap();
519 for state in [
520 CopperListState::Free,
521 CopperListState::Initialized,
522 CopperListState::Processing,
523 CopperListState::DoneProcessing,
524 CopperListState::QueuedForSerialization,
525 CopperListState::BeingSerialized,
526 ] {
527 let mut list = CopperList::new(42, CuStampedDataSet(123));
528 list.change_state(state);
529 let bytes = bincode::encode_to_vec(&list, bincode::config::standard()).unwrap();
530 assert_eq!(bytes, expected);
531 let old_bytes =
532 bincode::encode_to_vec((list.id, state, &list.msgs), bincode::config::standard())
533 .unwrap();
534 assert_eq!(old_bytes.len(), bytes.len() + 1);
535 let (decoded, used): (CopperList<CuStampedDataSet>, usize) =
536 bincode::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
537 assert_eq!(decoded.id, list.id);
538 assert_eq!(decoded.msgs, list.msgs);
539 assert_eq!(decoded.get_state(), CopperListState::BeingSerialized);
540 assert_eq!(used, bytes.len());
541 let (borrowed, used): (CopperList<CuStampedDataSet>, usize) =
542 bincode::borrow_decode_from_slice(&bytes, bincode::config::standard()).unwrap();
543 assert_eq!(borrowed.get_state(), CopperListState::BeingSerialized);
544 assert_eq!(borrowed.msgs, list.msgs);
545 assert_eq!(used, bytes.len());
546 assert_eq!(list.get_state(), state);
547 #[cfg(feature = "std")]
548 {
549 let json = serde_json::to_value(&list).unwrap();
550 assert_eq!(json, serde_json::json!({"id": 42, "msgs": 123}));
551 let decoded: CopperList<CuStampedDataSet> = serde_json::from_value(json).unwrap();
552 assert_eq!(decoded.get_state(), CopperListState::BeingSerialized);
553 assert_eq!(decoded.msgs, list.msgs);
554 }
555 }
556 }
557
558 #[test]
559 fn empty_queue() {
560 let q = CuListsManager::<CuStampedDataSet, 5>::new();
561
562 assert!(q.is_empty());
563 assert!(q.iter().next().is_none());
564 assert!(q.asc_iter().next().is_none());
565 assert!(q.peek().is_none());
566 }
567
568 #[test]
569 fn partially_full_queue() {
570 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
571 q.create().unwrap().msgs.0 = 1;
572 q.create().unwrap().msgs.0 = 2;
573 q.create().unwrap().msgs.0 = 3;
574
575 assert!(!q.is_empty());
576 assert_eq!(q.len(), 3);
577
578 let res: Vec<i32> = q.iter().map(|x| x.msgs.0).collect();
579 assert_eq!(res, [3, 2, 1]);
580 }
581
582 #[test]
583 fn full_queue() {
584 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
585 q.create().unwrap().msgs.0 = 1;
586 q.create().unwrap().msgs.0 = 2;
587 q.create().unwrap().msgs.0 = 3;
588 q.create().unwrap().msgs.0 = 4;
589 q.create().unwrap().msgs.0 = 5;
590 assert_eq!(q.len(), 5);
591
592 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
593 assert_eq!(res, [5, 4, 3, 2, 1]);
594 }
595
596 #[test]
597 fn over_full_queue() {
598 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
599 q.create().unwrap().msgs.0 = 1;
600 q.create().unwrap().msgs.0 = 2;
601 q.create().unwrap().msgs.0 = 3;
602 q.create().unwrap().msgs.0 = 4;
603 q.create().unwrap().msgs.0 = 5;
604 assert!(q.create().is_none());
605 assert_eq!(q.len(), 5);
606
607 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
608 assert_eq!(res, [5, 4, 3, 2, 1]);
609 }
610
611 #[test]
612 fn clear() {
613 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
614 q.create().unwrap().msgs.0 = 1;
615 q.create().unwrap().msgs.0 = 2;
616 q.create().unwrap().msgs.0 = 3;
617 q.create().unwrap().msgs.0 = 4;
618 q.create().unwrap().msgs.0 = 5;
619 assert!(q.create().is_none());
620 assert_eq!(q.len(), 5);
621
622 q.clear();
623
624 assert_eq!(q.len(), 0);
625 assert!(q.iter().next().is_none());
626
627 q.create().unwrap().msgs.0 = 1;
628 q.create().unwrap().msgs.0 = 2;
629 q.create().unwrap().msgs.0 = 3;
630
631 assert_eq!(q.len(), 3);
632
633 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
634 assert_eq!(res, [3, 2, 1]);
635 }
636
637 #[test]
638 fn create_fresh_slot_starts_initialized_with_zeroed_payload() {
639 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
640
641 let cl = q.create().unwrap();
642 assert_eq!(cl.id, 0);
643 assert_eq!(cl.get_state(), CopperListState::Initialized);
644 assert_eq!(cl.msgs.0, 0);
645 assert_eq!(q.next_cl_id(), 1);
646 assert_eq!(q.last_cl_id(), 0);
647 }
648
649 #[test]
650 fn create_reused_slot_reinitializes_state_but_preserves_payload_storage() {
651 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
652
653 {
654 let cl = q.create().unwrap();
655 cl.msgs.0 = 41;
656 cl.change_state(CopperListState::Processing);
657 }
658
659 let popped = q.pop().unwrap();
660 assert_eq!(popped.id, 0);
661 assert_eq!(popped.get_state(), CopperListState::Processing);
662 assert_eq!(popped.msgs.0, 41);
663
664 let reused = q.create().unwrap();
665 assert_eq!(reused.id, 1);
666 assert_eq!(reused.get_state(), CopperListState::Initialized);
667 assert_eq!(reused.msgs.0, 41);
668 assert_eq!(q.next_cl_id(), 2);
669 assert_eq!(q.last_cl_id(), 1);
670 }
671
672 #[test]
673 fn mutable_iterator() {
674 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
675 q.create().unwrap().msgs.0 = 1;
676 q.create().unwrap().msgs.0 = 2;
677 q.create().unwrap().msgs.0 = 3;
678 q.create().unwrap().msgs.0 = 4;
679 q.create().unwrap().msgs.0 = 5;
680
681 for x in q.iter_mut() {
682 x.msgs.0 *= 2;
683 }
684
685 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
686 assert_eq!(res, [10, 8, 6, 4, 2]);
687 }
688
689 #[test]
690 fn mutable_iterator_non_wrapped_only_visits_active_slots() {
691 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
692 q.create().unwrap().msgs.0 = 1;
693 q.create().unwrap().msgs.0 = 2;
694 q.create().unwrap().msgs.0 = 3;
695
696 let mut visited = Vec::new();
697 for cl in q.iter_mut() {
698 visited.push(cl.id);
699 cl.msgs.0 *= 10;
700 }
701
702 assert_eq!(visited, vec![2, 1, 0]);
703 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
704 assert_eq!(res, [30, 20, 10]);
705 }
706
707 #[test]
708 fn test_drop_last() {
709 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
710 q.create().unwrap().msgs.0 = 1;
711 q.create().unwrap().msgs.0 = 2;
712 q.create().unwrap().msgs.0 = 3;
713 q.create().unwrap().msgs.0 = 4;
714 q.create().unwrap().msgs.0 = 5;
715 assert_eq!(q.len(), 5);
716
717 q.drop_last();
718 assert_eq!(q.len(), 4);
719
720 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
721 assert_eq!(res, [4, 3, 2, 1]);
722 }
723
724 #[test]
725 fn drop_last_on_empty_queue_is_a_noop() {
726 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
727
728 q.drop_last();
729
730 assert!(q.is_empty());
731 assert!(q.peek().is_none());
732 assert!(q.pop().is_none());
733 }
734
735 #[test]
736 fn drop_last_on_non_wrapped_queue_removes_most_recent_slot() {
737 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
738 q.create().unwrap().msgs.0 = 1;
739 q.create().unwrap().msgs.0 = 2;
740 q.create().unwrap().msgs.0 = 3;
741
742 q.drop_last();
743
744 assert_eq!(q.len(), 2);
745 assert_eq!(q.peek().unwrap().msgs.0, 2);
746 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
747 assert_eq!(res, [2, 1]);
748 }
749
750 #[test]
751 fn test_pop() {
752 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
753 q.create().unwrap().msgs.0 = 1;
754 q.create().unwrap().msgs.0 = 2;
755 q.create().unwrap().msgs.0 = 3;
756 q.create().unwrap().msgs.0 = 4;
757 q.create().unwrap().msgs.0 = 5;
758 assert_eq!(q.len(), 5);
759
760 let last = q.pop().unwrap();
761 assert_eq!(last.msgs.0, 5);
762 assert_eq!(q.len(), 4);
763
764 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
765 assert_eq!(res, [4, 3, 2, 1]);
766 }
767
768 #[test]
769 fn pop_on_empty_queue_returns_none() {
770 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
771
772 assert!(q.pop().is_none());
773 assert!(q.is_empty());
774 }
775
776 #[test]
777 fn test_peek() {
778 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
779 q.create().unwrap().msgs.0 = 1;
780 q.create().unwrap().msgs.0 = 2;
781 q.create().unwrap().msgs.0 = 3;
782 q.create().unwrap().msgs.0 = 4;
783 q.create().unwrap().msgs.0 = 5;
784 assert_eq!(q.len(), 5);
785
786 let last = q.peek().unwrap();
787 assert_eq!(last.msgs.0, 5);
788 assert_eq!(q.len(), 5);
789
790 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
791 assert_eq!(res, [5, 4, 3, 2, 1]);
792 }
793
794 #[test]
795 fn peek_on_empty_queue_returns_none() {
796 let q = CuListsManager::<CuStampedDataSet, 5>::new();
797
798 assert!(q.peek().is_none());
799 }
800
801 #[test]
802 fn next_and_last_cl_id_track_assigned_ids() {
803 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
804
805 assert_eq!(q.next_cl_id(), 0);
807 assert_eq!(q.last_cl_id(), 0);
808
809 let cl0 = q.create().unwrap();
810 assert_eq!(cl0.id, 0);
811 assert_eq!(q.next_cl_id(), 1);
812 assert_eq!(q.last_cl_id(), 0);
813
814 let cl1 = q.create().unwrap();
815 assert_eq!(cl1.id, 1);
816 assert_eq!(q.next_cl_id(), 2);
817 assert_eq!(q.last_cl_id(), 1);
818
819 let _ = q.pop().unwrap();
820 let cl2 = q.create().unwrap();
821 assert_eq!(cl2.id, 2);
822 assert_eq!(q.next_cl_id(), 3);
823 assert_eq!(q.last_cl_id(), 2);
824 }
825
826 #[test]
827 fn asc_iter_non_wrapped_returns_oldest_to_newest_without_free_slots() {
828 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
829 q.create().unwrap().msgs.0 = 10;
830 q.create().unwrap().msgs.0 = 20;
831 q.create().unwrap().msgs.0 = 30;
832
833 let res: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
834 assert_eq!(res, [10, 20, 30]);
835 }
836
837 #[test]
838 fn asc_iter_mut_non_wrapped_only_visits_active_slots_in_oldest_first_order() {
839 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
840 q.create().unwrap().msgs.0 = 10;
841 q.create().unwrap().msgs.0 = 20;
842 q.create().unwrap().msgs.0 = 30;
843
844 let mut visited = Vec::new();
845 for (offset, cl) in q.asc_iter_mut().enumerate() {
846 visited.push(cl.id);
847 cl.msgs.0 += offset as i32;
848 }
849
850 assert_eq!(visited, vec![0, 1, 2]);
851 let res: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
852 assert_eq!(res, [10, 21, 32]);
853 }
854
855 #[test]
856 fn asc_iter_wrapped_layout_tracks_reused_slots_in_ascending_order() {
857 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
858 for value in 1..=5 {
859 q.create().unwrap().msgs.0 = value;
860 }
861 assert_eq!(q.pop().unwrap().msgs.0, 5);
862 assert_eq!(q.pop().unwrap().msgs.0, 4);
863 q.create().unwrap().msgs.0 = 6;
864 q.create().unwrap().msgs.0 = 7;
865
866 let desc: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
867 assert_eq!(desc, [7, 6, 3, 2, 1]);
868
869 let asc: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
870 assert_eq!(asc, [1, 2, 3, 6, 7]);
871 }
872
873 #[test]
874 fn asc_iter_mut_wrapped_layout_updates_oldest_to_newest_order() {
875 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
876 for value in 1..=5 {
877 q.create().unwrap().msgs.0 = value;
878 }
879 let _ = q.pop().unwrap();
880 let _ = q.pop().unwrap();
881 q.create().unwrap().msgs.0 = 6;
882 q.create().unwrap().msgs.0 = 7;
883
884 let mut visited = Vec::new();
885 for (offset, cl) in q.asc_iter_mut().enumerate() {
886 visited.push(cl.id);
887 cl.msgs.0 += offset as i32;
888 }
889
890 assert_eq!(visited, vec![0, 1, 2, 5, 6]);
891 let asc: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
892 assert_eq!(asc, [1, 3, 5, 9, 11]);
893 }
894
895 #[derive(Decode, Encode, Debug, PartialEq, Clone, Copy)]
896 struct TestStruct {
897 content: [u8; 10_000_000],
898 }
899
900 impl Default for TestStruct {
901 fn default() -> Self {
902 TestStruct {
903 content: [0; 10_000_000],
904 }
905 }
906 }
907
908 impl ErasedCuStampedDataSet for TestStruct {
909 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
910 Vec::new()
911 }
912 }
913
914 impl Serialize for TestStruct {
915 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
916 where
917 S: Serializer,
918 {
919 serializer.serialize_i8(0)
920 }
921 }
922
923 impl MatchingTasks for TestStruct {
924 fn get_all_task_ids() -> &'static [&'static str] {
925 &[]
926 }
927 }
928
929 impl CuListZeroedInit for TestStruct {
930 fn init_zeroed(&mut self) {}
931
932 fn init_in_place(dst: &mut core::mem::MaybeUninit<Self>) -> &mut Self {
933 unsafe {
935 dst.as_mut_ptr().write_bytes(0, 1);
936 dst.assume_init_mut()
937 }
938 }
939 }
940
941 #[test]
942 fn be_sure_we_wont_stackoverflow_at_init() {
943 let _ = CuListsManager::<TestStruct, 3>::new();
944 }
945}