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)]
53pub struct CopperList<P: CopperListTuple> {
54 pub id: u64,
55 state: CopperListState,
56 pub msgs: P, }
58
59impl<P: CopperListTuple> Default for CopperList<P> {
60 fn default() -> Self {
61 CopperList {
62 id: 0,
63 state: CopperListState::Free,
64 msgs: P::default(),
65 }
66 }
67}
68
69impl<P: CopperListTuple> CopperList<P> {
70 pub fn new(id: u64, msgs: P) -> Self {
72 CopperList {
73 id,
74 state: CopperListState::Initialized,
75 msgs,
76 }
77 }
78
79 pub fn change_state(&mut self, new_state: CopperListState) {
80 self.state = new_state; }
82
83 pub fn get_state(&self) -> CopperListState {
84 self.state
85 }
86
87 #[doc(hidden)]
90 pub fn reset_for_runtime_use(&mut self, id: u64)
91 where
92 P: CuListZeroedInit,
93 {
94 self.id = id;
95 self.state = CopperListState::Initialized;
96 self.msgs.init_zeroed();
97 }
98
99 pub(crate) unsafe fn init_in_place(dst: *mut Self)
105 where
106 P: CuListZeroedInit,
107 {
108 unsafe {
111 core::ptr::addr_of_mut!((*dst).id).write(0);
112 core::ptr::addr_of_mut!((*dst).state).write(CopperListState::Free);
113 let msgs = core::ptr::addr_of_mut!((*dst).msgs);
114 let initialized = P::init_in_place(&mut *msgs.cast::<core::mem::MaybeUninit<P>>());
115 assert!(
116 core::ptr::eq(initialized, msgs),
117 "initializer returned a different slot"
118 );
119 }
120 }
121}
122
123impl<P: CopperListTuple> ErasedCuStampedDataSet for CopperList<P> {
124 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
125 self.msgs.cumsgs()
126 }
127}
128
129pub struct CuListsManager<P: CopperListTuple, const N: usize> {
133 data: Box<[CopperList<P>; N]>,
134 length: usize,
135 insertion_index: usize,
136 current_cl_id: u64,
137}
138
139impl<P: CopperListTuple + fmt::Debug, const N: usize> fmt::Debug for CuListsManager<P, N> {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 f.debug_struct("CuListsManager")
142 .field("data", &self.data)
143 .field("length", &self.length)
144 .field("insertion_index", &self.insertion_index)
145 .finish()
147 }
148}
149
150pub type Iter<'a, T> = Chain<Rev<SliceIter<'a, T>>, Rev<SliceIter<'a, T>>>;
151pub type IterMut<'a, T> = Chain<Rev<SliceIterMut<'a, T>>, Rev<SliceIterMut<'a, T>>>;
152pub type AscIter<'a, T> = Chain<SliceIter<'a, T>, SliceIter<'a, T>>;
153pub type AscIterMut<'a, T> = Chain<SliceIterMut<'a, T>, SliceIterMut<'a, T>>;
154
155pub trait CuListZeroedInit: CopperListTuple {
161 fn init_zeroed(&mut self);
163
164 #[doc(hidden)]
170 fn init_in_place(dst: &mut core::mem::MaybeUninit<Self>) -> &mut Self {
171 dst.write(Self::default())
172 }
173}
174
175impl<P: CopperListTuple + CuListZeroedInit, const N: usize> Default for CuListsManager<P, N> {
176 fn default() -> Self {
177 Self::new()
178 }
179}
180
181impl<P: CopperListTuple, const N: usize> CuListsManager<P, N> {
182 pub fn new() -> Self
183 where
184 P: CuListZeroedInit,
185 {
186 let mut slots = Vec::<CopperList<P>>::with_capacity(N);
187 for index in 0..N {
188 unsafe {
192 CopperList::init_in_place(slots.as_mut_ptr().add(index));
193 slots.set_len(index + 1);
194 }
195 }
196 let data = unsafe {
198 Box::from_raw(Box::into_raw(slots.into_boxed_slice()) as *mut [CopperList<P>; N])
199 };
200 CuListsManager {
201 data,
202 length: 0,
203 insertion_index: 0,
204 current_cl_id: 0,
205 }
206 }
207
208 #[inline]
211 pub fn len(&self) -> usize {
212 self.length
213 }
214
215 #[inline]
218 pub fn is_empty(&self) -> bool {
219 self.length == 0
220 }
221
222 #[inline]
225 pub fn is_full(&self) -> bool {
226 N == self.len()
227 }
228
229 #[inline]
232 pub fn clear(&mut self) {
233 self.insertion_index = 0;
234 self.length = 0;
235 }
236
237 #[inline]
238 pub fn create(&mut self) -> Option<&mut CopperList<P>>
239 where
240 P: CuListZeroedInit,
241 {
242 if self.is_full() {
243 return None;
244 }
245 let next_id = self.current_cl_id;
246 let result = &mut self.data[self.insertion_index];
247 self.insertion_index = (self.insertion_index + 1) % N;
248 self.length += 1;
249
250 result.reset_for_runtime_use(next_id);
252 self.current_cl_id += 1;
253
254 Some(result)
255 }
256
257 #[inline]
259 pub fn next_cl_id(&self) -> u64 {
260 self.current_cl_id
261 }
262
263 #[inline]
267 pub fn last_cl_id(&self) -> u64 {
268 self.current_cl_id.saturating_sub(1)
269 }
270
271 #[inline]
273 pub fn peek(&self) -> Option<&CopperList<P>> {
274 if self.length == 0 {
275 return None;
276 }
277 let index = if self.insertion_index == 0 {
278 N - 1
279 } else {
280 self.insertion_index - 1
281 };
282 Some(&self.data[index])
283 }
284
285 #[inline]
286 #[allow(dead_code)]
287 fn drop_last(&mut self) {
288 if self.length == 0 {
289 return;
290 }
291 if self.insertion_index == 0 {
292 self.insertion_index = N - 1;
293 } else {
294 self.insertion_index -= 1;
295 }
296 self.length -= 1;
297 }
298
299 #[inline]
300 pub fn pop(&mut self) -> Option<&mut CopperList<P>> {
301 if self.length == 0 {
302 return None;
303 }
304 if self.insertion_index == 0 {
305 self.insertion_index = N - 1;
306 } else {
307 self.insertion_index -= 1;
308 }
309 self.length -= 1;
310 Some(&mut self.data[self.insertion_index])
311 }
312
313 #[inline]
318 pub fn iter(&self) -> Iter<'_, CopperList<P>> {
319 let (a, b) = self.data[0..self.length].split_at(self.insertion_index);
320 a.iter().rev().chain(b.iter().rev())
321 }
322
323 #[inline]
328 pub fn iter_mut(&mut self) -> IterMut<'_, CopperList<P>> {
329 let (a, b) = self.data[0..self.length].split_at_mut(self.insertion_index);
330 a.iter_mut().rev().chain(b.iter_mut().rev())
331 }
332
333 #[inline]
338 pub fn asc_iter(&self) -> AscIter<'_, CopperList<P>> {
339 let (a, b) = self.data[0..self.length].split_at(self.insertion_index);
340 b.iter().chain(a.iter())
341 }
342
343 #[inline]
348 pub fn asc_iter_mut(&mut self) -> AscIterMut<'_, CopperList<P>> {
349 let (a, b) = self.data[0..self.length].split_at_mut(self.insertion_index);
350 b.iter_mut().chain(a.iter_mut())
351 }
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357 use cu29_traits::{ErasedCuStampedData, ErasedCuStampedDataSet, MatchingTasks};
358 use serde::{Deserialize, Serialize, Serializer};
359
360 #[derive(Debug, Encode, Decode, PartialEq, Clone, Copy, Serialize, Deserialize, Default)]
361 struct CuStampedDataSet(i32);
362
363 impl ErasedCuStampedDataSet for CuStampedDataSet {
364 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
365 Vec::new()
366 }
367 }
368
369 impl MatchingTasks for CuStampedDataSet {
370 fn get_all_task_ids() -> &'static [&'static str] {
371 &[]
372 }
373 }
374
375 impl CuListZeroedInit for CuStampedDataSet {
376 fn init_zeroed(&mut self) {}
377 }
378
379 #[derive(Debug, Default, Encode, Decode, Serialize, Deserialize)]
380 struct WrongSlot;
381
382 impl ErasedCuStampedDataSet for WrongSlot {
383 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
384 Vec::new()
385 }
386 }
387
388 impl MatchingTasks for WrongSlot {
389 fn get_all_task_ids() -> &'static [&'static str] {
390 &[]
391 }
392 }
393
394 impl CuListZeroedInit for WrongSlot {
395 fn init_zeroed(&mut self) {}
396
397 fn init_in_place(_dst: &mut core::mem::MaybeUninit<Self>) -> &mut Self {
398 Box::leak(Box::new(Self))
399 }
400 }
401
402 #[test]
403 #[should_panic(expected = "initializer returned a different slot")]
404 fn rejects_initializer_returning_another_slot() {
405 let _ = CuListsManager::<WrongSlot, 1>::new();
406 }
407
408 #[test]
409 fn empty_queue() {
410 let q = CuListsManager::<CuStampedDataSet, 5>::new();
411
412 assert!(q.is_empty());
413 assert!(q.iter().next().is_none());
414 assert!(q.asc_iter().next().is_none());
415 assert!(q.peek().is_none());
416 }
417
418 #[test]
419 fn partially_full_queue() {
420 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
421 q.create().unwrap().msgs.0 = 1;
422 q.create().unwrap().msgs.0 = 2;
423 q.create().unwrap().msgs.0 = 3;
424
425 assert!(!q.is_empty());
426 assert_eq!(q.len(), 3);
427
428 let res: Vec<i32> = q.iter().map(|x| x.msgs.0).collect();
429 assert_eq!(res, [3, 2, 1]);
430 }
431
432 #[test]
433 fn full_queue() {
434 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
435 q.create().unwrap().msgs.0 = 1;
436 q.create().unwrap().msgs.0 = 2;
437 q.create().unwrap().msgs.0 = 3;
438 q.create().unwrap().msgs.0 = 4;
439 q.create().unwrap().msgs.0 = 5;
440 assert_eq!(q.len(), 5);
441
442 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
443 assert_eq!(res, [5, 4, 3, 2, 1]);
444 }
445
446 #[test]
447 fn over_full_queue() {
448 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
449 q.create().unwrap().msgs.0 = 1;
450 q.create().unwrap().msgs.0 = 2;
451 q.create().unwrap().msgs.0 = 3;
452 q.create().unwrap().msgs.0 = 4;
453 q.create().unwrap().msgs.0 = 5;
454 assert!(q.create().is_none());
455 assert_eq!(q.len(), 5);
456
457 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
458 assert_eq!(res, [5, 4, 3, 2, 1]);
459 }
460
461 #[test]
462 fn clear() {
463 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
464 q.create().unwrap().msgs.0 = 1;
465 q.create().unwrap().msgs.0 = 2;
466 q.create().unwrap().msgs.0 = 3;
467 q.create().unwrap().msgs.0 = 4;
468 q.create().unwrap().msgs.0 = 5;
469 assert!(q.create().is_none());
470 assert_eq!(q.len(), 5);
471
472 q.clear();
473
474 assert_eq!(q.len(), 0);
475 assert!(q.iter().next().is_none());
476
477 q.create().unwrap().msgs.0 = 1;
478 q.create().unwrap().msgs.0 = 2;
479 q.create().unwrap().msgs.0 = 3;
480
481 assert_eq!(q.len(), 3);
482
483 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
484 assert_eq!(res, [3, 2, 1]);
485 }
486
487 #[test]
488 fn create_fresh_slot_starts_initialized_with_zeroed_payload() {
489 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
490
491 let cl = q.create().unwrap();
492 assert_eq!(cl.id, 0);
493 assert_eq!(cl.get_state(), CopperListState::Initialized);
494 assert_eq!(cl.msgs.0, 0);
495 assert_eq!(q.next_cl_id(), 1);
496 assert_eq!(q.last_cl_id(), 0);
497 }
498
499 #[test]
500 fn create_reused_slot_reinitializes_state_but_preserves_payload_storage() {
501 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
502
503 {
504 let cl = q.create().unwrap();
505 cl.msgs.0 = 41;
506 cl.change_state(CopperListState::Processing);
507 }
508
509 let popped = q.pop().unwrap();
510 assert_eq!(popped.id, 0);
511 assert_eq!(popped.get_state(), CopperListState::Processing);
512 assert_eq!(popped.msgs.0, 41);
513
514 let reused = q.create().unwrap();
515 assert_eq!(reused.id, 1);
516 assert_eq!(reused.get_state(), CopperListState::Initialized);
517 assert_eq!(reused.msgs.0, 41);
518 assert_eq!(q.next_cl_id(), 2);
519 assert_eq!(q.last_cl_id(), 1);
520 }
521
522 #[test]
523 fn mutable_iterator() {
524 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
525 q.create().unwrap().msgs.0 = 1;
526 q.create().unwrap().msgs.0 = 2;
527 q.create().unwrap().msgs.0 = 3;
528 q.create().unwrap().msgs.0 = 4;
529 q.create().unwrap().msgs.0 = 5;
530
531 for x in q.iter_mut() {
532 x.msgs.0 *= 2;
533 }
534
535 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
536 assert_eq!(res, [10, 8, 6, 4, 2]);
537 }
538
539 #[test]
540 fn mutable_iterator_non_wrapped_only_visits_active_slots() {
541 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
542 q.create().unwrap().msgs.0 = 1;
543 q.create().unwrap().msgs.0 = 2;
544 q.create().unwrap().msgs.0 = 3;
545
546 let mut visited = Vec::new();
547 for cl in q.iter_mut() {
548 visited.push(cl.id);
549 cl.msgs.0 *= 10;
550 }
551
552 assert_eq!(visited, vec![2, 1, 0]);
553 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
554 assert_eq!(res, [30, 20, 10]);
555 }
556
557 #[test]
558 fn test_drop_last() {
559 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
560 q.create().unwrap().msgs.0 = 1;
561 q.create().unwrap().msgs.0 = 2;
562 q.create().unwrap().msgs.0 = 3;
563 q.create().unwrap().msgs.0 = 4;
564 q.create().unwrap().msgs.0 = 5;
565 assert_eq!(q.len(), 5);
566
567 q.drop_last();
568 assert_eq!(q.len(), 4);
569
570 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
571 assert_eq!(res, [4, 3, 2, 1]);
572 }
573
574 #[test]
575 fn drop_last_on_empty_queue_is_a_noop() {
576 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
577
578 q.drop_last();
579
580 assert!(q.is_empty());
581 assert!(q.peek().is_none());
582 assert!(q.pop().is_none());
583 }
584
585 #[test]
586 fn drop_last_on_non_wrapped_queue_removes_most_recent_slot() {
587 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
588 q.create().unwrap().msgs.0 = 1;
589 q.create().unwrap().msgs.0 = 2;
590 q.create().unwrap().msgs.0 = 3;
591
592 q.drop_last();
593
594 assert_eq!(q.len(), 2);
595 assert_eq!(q.peek().unwrap().msgs.0, 2);
596 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
597 assert_eq!(res, [2, 1]);
598 }
599
600 #[test]
601 fn test_pop() {
602 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
603 q.create().unwrap().msgs.0 = 1;
604 q.create().unwrap().msgs.0 = 2;
605 q.create().unwrap().msgs.0 = 3;
606 q.create().unwrap().msgs.0 = 4;
607 q.create().unwrap().msgs.0 = 5;
608 assert_eq!(q.len(), 5);
609
610 let last = q.pop().unwrap();
611 assert_eq!(last.msgs.0, 5);
612 assert_eq!(q.len(), 4);
613
614 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
615 assert_eq!(res, [4, 3, 2, 1]);
616 }
617
618 #[test]
619 fn pop_on_empty_queue_returns_none() {
620 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
621
622 assert!(q.pop().is_none());
623 assert!(q.is_empty());
624 }
625
626 #[test]
627 fn test_peek() {
628 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
629 q.create().unwrap().msgs.0 = 1;
630 q.create().unwrap().msgs.0 = 2;
631 q.create().unwrap().msgs.0 = 3;
632 q.create().unwrap().msgs.0 = 4;
633 q.create().unwrap().msgs.0 = 5;
634 assert_eq!(q.len(), 5);
635
636 let last = q.peek().unwrap();
637 assert_eq!(last.msgs.0, 5);
638 assert_eq!(q.len(), 5);
639
640 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
641 assert_eq!(res, [5, 4, 3, 2, 1]);
642 }
643
644 #[test]
645 fn peek_on_empty_queue_returns_none() {
646 let q = CuListsManager::<CuStampedDataSet, 5>::new();
647
648 assert!(q.peek().is_none());
649 }
650
651 #[test]
652 fn next_and_last_cl_id_track_assigned_ids() {
653 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
654
655 assert_eq!(q.next_cl_id(), 0);
657 assert_eq!(q.last_cl_id(), 0);
658
659 let cl0 = q.create().unwrap();
660 assert_eq!(cl0.id, 0);
661 assert_eq!(q.next_cl_id(), 1);
662 assert_eq!(q.last_cl_id(), 0);
663
664 let cl1 = q.create().unwrap();
665 assert_eq!(cl1.id, 1);
666 assert_eq!(q.next_cl_id(), 2);
667 assert_eq!(q.last_cl_id(), 1);
668
669 let _ = q.pop().unwrap();
670 let cl2 = q.create().unwrap();
671 assert_eq!(cl2.id, 2);
672 assert_eq!(q.next_cl_id(), 3);
673 assert_eq!(q.last_cl_id(), 2);
674 }
675
676 #[test]
677 fn asc_iter_non_wrapped_returns_oldest_to_newest_without_free_slots() {
678 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
679 q.create().unwrap().msgs.0 = 10;
680 q.create().unwrap().msgs.0 = 20;
681 q.create().unwrap().msgs.0 = 30;
682
683 let res: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
684 assert_eq!(res, [10, 20, 30]);
685 }
686
687 #[test]
688 fn asc_iter_mut_non_wrapped_only_visits_active_slots_in_oldest_first_order() {
689 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
690 q.create().unwrap().msgs.0 = 10;
691 q.create().unwrap().msgs.0 = 20;
692 q.create().unwrap().msgs.0 = 30;
693
694 let mut visited = Vec::new();
695 for (offset, cl) in q.asc_iter_mut().enumerate() {
696 visited.push(cl.id);
697 cl.msgs.0 += offset as i32;
698 }
699
700 assert_eq!(visited, vec![0, 1, 2]);
701 let res: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
702 assert_eq!(res, [10, 21, 32]);
703 }
704
705 #[test]
706 fn asc_iter_wrapped_layout_tracks_reused_slots_in_ascending_order() {
707 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
708 for value in 1..=5 {
709 q.create().unwrap().msgs.0 = value;
710 }
711 assert_eq!(q.pop().unwrap().msgs.0, 5);
712 assert_eq!(q.pop().unwrap().msgs.0, 4);
713 q.create().unwrap().msgs.0 = 6;
714 q.create().unwrap().msgs.0 = 7;
715
716 let desc: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
717 assert_eq!(desc, [7, 6, 3, 2, 1]);
718
719 let asc: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
720 assert_eq!(asc, [1, 2, 3, 6, 7]);
721 }
722
723 #[test]
724 fn asc_iter_mut_wrapped_layout_updates_oldest_to_newest_order() {
725 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
726 for value in 1..=5 {
727 q.create().unwrap().msgs.0 = value;
728 }
729 let _ = q.pop().unwrap();
730 let _ = q.pop().unwrap();
731 q.create().unwrap().msgs.0 = 6;
732 q.create().unwrap().msgs.0 = 7;
733
734 let mut visited = Vec::new();
735 for (offset, cl) in q.asc_iter_mut().enumerate() {
736 visited.push(cl.id);
737 cl.msgs.0 += offset as i32;
738 }
739
740 assert_eq!(visited, vec![0, 1, 2, 5, 6]);
741 let asc: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
742 assert_eq!(asc, [1, 3, 5, 9, 11]);
743 }
744
745 #[derive(Decode, Encode, Debug, PartialEq, Clone, Copy)]
746 struct TestStruct {
747 content: [u8; 10_000_000],
748 }
749
750 impl Default for TestStruct {
751 fn default() -> Self {
752 TestStruct {
753 content: [0; 10_000_000],
754 }
755 }
756 }
757
758 impl ErasedCuStampedDataSet for TestStruct {
759 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
760 Vec::new()
761 }
762 }
763
764 impl Serialize for TestStruct {
765 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
766 where
767 S: Serializer,
768 {
769 serializer.serialize_i8(0)
770 }
771 }
772
773 impl MatchingTasks for TestStruct {
774 fn get_all_task_ids() -> &'static [&'static str] {
775 &[]
776 }
777 }
778
779 impl CuListZeroedInit for TestStruct {
780 fn init_zeroed(&mut self) {}
781
782 fn init_in_place(dst: &mut core::mem::MaybeUninit<Self>) -> &mut Self {
783 unsafe {
785 dst.as_mut_ptr().write_bytes(0, 1);
786 dst.assume_init_mut()
787 }
788 }
789 }
790
791 #[test]
792 fn be_sure_we_wont_stackoverflow_at_init() {
793 let _ = CuListsManager::<TestStruct, 3>::new();
794 }
795}