1#[cfg(not(feature = "std"))]
4extern crate alloc;
5
6use alloc::alloc::{alloc_zeroed, handle_alloc_error};
7use alloc::boxed::Box;
8use alloc::vec::Vec;
9use core::alloc::Layout;
10
11use bincode::{Decode, Encode};
12use core::fmt;
13
14use core::fmt::Display;
15use core::iter::{Chain, Rev};
16use core::slice::{Iter as SliceIter, IterMut as SliceIterMut};
17use cu29_traits::{CopperListTuple, ErasedCuStampedData, ErasedCuStampedDataSet};
18use serde_derive::{Deserialize, Serialize};
19
20const MAX_TASKS: usize = 512;
21
22#[derive(Debug, Encode, Decode, PartialEq, Clone, Copy)]
25pub struct CopperLiskMask {
26 #[allow(dead_code)]
27 mask: [u128; MAX_TASKS / 128 + 1],
28}
29
30#[derive(Debug, Encode, Decode, Serialize, Deserialize, PartialEq, Copy, Clone)]
32pub enum CopperListState {
33 Free,
34 Initialized,
35 Processing,
36 DoneProcessing,
37 QueuedForSerialization,
38 BeingSerialized,
39}
40
41impl Display for CopperListState {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 CopperListState::Free => write!(f, "Free"),
45 CopperListState::Initialized => write!(f, "Initialized"),
46 CopperListState::Processing => write!(f, "Processing"),
47 CopperListState::DoneProcessing => write!(f, "DoneProcessing"),
48 CopperListState::QueuedForSerialization => write!(f, "QueuedForSerialization"),
49 CopperListState::BeingSerialized => write!(f, "BeingSerialized"),
50 }
51 }
52}
53
54#[derive(Debug, Encode, Decode, Serialize, Deserialize)]
55pub struct CopperList<P: CopperListTuple> {
56 pub id: u64,
57 state: CopperListState,
58 pub msgs: P, }
60
61impl<P: CopperListTuple> Default for CopperList<P> {
62 fn default() -> Self {
63 CopperList {
64 id: 0,
65 state: CopperListState::Free,
66 msgs: P::default(),
67 }
68 }
69}
70
71impl<P: CopperListTuple> CopperList<P> {
72 pub fn new(id: u64, msgs: P) -> Self {
74 CopperList {
75 id,
76 state: CopperListState::Initialized,
77 msgs,
78 }
79 }
80
81 pub fn change_state(&mut self, new_state: CopperListState) {
82 self.state = new_state; }
84
85 pub fn get_state(&self) -> CopperListState {
86 self.state
87 }
88
89 #[doc(hidden)]
93 pub fn reset_for_runtime_use(&mut self, id: u64)
94 where
95 P: CuListZeroedInit,
96 {
97 self.id = id;
98 self.state = CopperListState::Initialized;
99 self.msgs.init_zeroed();
100 }
101}
102
103impl<P: CopperListTuple> ErasedCuStampedDataSet for CopperList<P> {
104 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
105 self.msgs.cumsgs()
106 }
107}
108
109pub struct CuListsManager<P: CopperListTuple, const N: usize> {
113 data: Box<[CopperList<P>; N]>,
114 length: usize,
115 insertion_index: usize,
116 current_cl_id: u64,
117}
118
119impl<P: CopperListTuple + fmt::Debug, const N: usize> fmt::Debug for CuListsManager<P, N> {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 f.debug_struct("CuListsManager")
122 .field("data", &self.data)
123 .field("length", &self.length)
124 .field("insertion_index", &self.insertion_index)
125 .finish()
127 }
128}
129
130pub type Iter<'a, T> = Chain<Rev<SliceIter<'a, T>>, Rev<SliceIter<'a, T>>>;
131pub type IterMut<'a, T> = Chain<Rev<SliceIterMut<'a, T>>, Rev<SliceIterMut<'a, T>>>;
132pub type AscIter<'a, T> = Chain<SliceIter<'a, T>, SliceIter<'a, T>>;
133pub type AscIterMut<'a, T> = Chain<SliceIterMut<'a, T>, SliceIterMut<'a, T>>;
134
135pub trait CuListZeroedInit: CopperListTuple {
138 fn init_zeroed(&mut self);
141}
142
143impl<P: CopperListTuple + CuListZeroedInit, const N: usize> Default for CuListsManager<P, N> {
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149impl<P: CopperListTuple, const N: usize> CuListsManager<P, N> {
150 pub fn new() -> Self
151 where
152 P: CuListZeroedInit,
153 {
154 let data = unsafe {
156 let layout = Layout::new::<[CopperList<P>; N]>();
157 let ptr = alloc_zeroed(layout) as *mut [CopperList<P>; N];
158 if ptr.is_null() {
159 handle_alloc_error(layout);
160 }
161 Box::from_raw(ptr)
162 };
163 let mut manager = CuListsManager {
164 data,
165 length: 0,
166 insertion_index: 0,
167 current_cl_id: 0,
168 };
169
170 for cl in manager.data.iter_mut() {
171 cl.msgs.init_zeroed();
172 }
173
174 manager
175 }
176
177 #[inline]
180 pub fn len(&self) -> usize {
181 self.length
182 }
183
184 #[inline]
187 pub fn is_empty(&self) -> bool {
188 self.length == 0
189 }
190
191 #[inline]
194 pub fn is_full(&self) -> bool {
195 N == self.len()
196 }
197
198 #[inline]
201 pub fn clear(&mut self) {
202 self.insertion_index = 0;
203 self.length = 0;
204 }
205
206 #[inline]
207 pub fn create(&mut self) -> Option<&mut CopperList<P>>
208 where
209 P: CuListZeroedInit,
210 {
211 if self.is_full() {
212 return None;
213 }
214 let next_id = self.current_cl_id;
215 let result = &mut self.data[self.insertion_index];
216 self.insertion_index = (self.insertion_index + 1) % N;
217 self.length += 1;
218
219 result.reset_for_runtime_use(next_id);
221 self.current_cl_id += 1;
222
223 Some(result)
224 }
225
226 #[inline]
228 pub fn next_cl_id(&self) -> u64 {
229 self.current_cl_id
230 }
231
232 #[inline]
236 pub fn last_cl_id(&self) -> u64 {
237 self.current_cl_id.saturating_sub(1)
238 }
239
240 #[inline]
242 pub fn peek(&self) -> Option<&CopperList<P>> {
243 if self.length == 0 {
244 return None;
245 }
246 let index = if self.insertion_index == 0 {
247 N - 1
248 } else {
249 self.insertion_index - 1
250 };
251 Some(&self.data[index])
252 }
253
254 #[inline]
255 #[allow(dead_code)]
256 fn drop_last(&mut self) {
257 if self.length == 0 {
258 return;
259 }
260 if self.insertion_index == 0 {
261 self.insertion_index = N - 1;
262 } else {
263 self.insertion_index -= 1;
264 }
265 self.length -= 1;
266 }
267
268 #[inline]
269 pub fn pop(&mut self) -> Option<&mut CopperList<P>> {
270 if self.length == 0 {
271 return None;
272 }
273 if self.insertion_index == 0 {
274 self.insertion_index = N - 1;
275 } else {
276 self.insertion_index -= 1;
277 }
278 self.length -= 1;
279 Some(&mut self.data[self.insertion_index])
280 }
281
282 #[inline]
287 pub fn iter(&self) -> Iter<'_, CopperList<P>> {
288 let (a, b) = self.data[0..self.length].split_at(self.insertion_index);
289 a.iter().rev().chain(b.iter().rev())
290 }
291
292 #[inline]
297 pub fn iter_mut(&mut self) -> IterMut<'_, CopperList<P>> {
298 let (a, b) = self.data[0..self.length].split_at_mut(self.insertion_index);
299 a.iter_mut().rev().chain(b.iter_mut().rev())
300 }
301
302 #[inline]
307 pub fn asc_iter(&self) -> AscIter<'_, CopperList<P>> {
308 let (a, b) = self.data[0..self.length].split_at(self.insertion_index);
309 b.iter().chain(a.iter())
310 }
311
312 #[inline]
317 pub fn asc_iter_mut(&mut self) -> AscIterMut<'_, CopperList<P>> {
318 let (a, b) = self.data[0..self.length].split_at_mut(self.insertion_index);
319 b.iter_mut().chain(a.iter_mut())
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326 use cu29_traits::{ErasedCuStampedData, ErasedCuStampedDataSet, MatchingTasks};
327 use serde::{Deserialize, Serialize, Serializer};
328
329 #[derive(Debug, Encode, Decode, PartialEq, Clone, Copy, Serialize, Deserialize, Default)]
330 struct CuStampedDataSet(i32);
331
332 impl ErasedCuStampedDataSet for CuStampedDataSet {
333 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
334 Vec::new()
335 }
336 }
337
338 impl MatchingTasks for CuStampedDataSet {
339 fn get_all_task_ids() -> &'static [&'static str] {
340 &[]
341 }
342 }
343
344 impl CuListZeroedInit for CuStampedDataSet {
345 fn init_zeroed(&mut self) {}
346 }
347
348 #[test]
349 fn empty_queue() {
350 let q = CuListsManager::<CuStampedDataSet, 5>::new();
351
352 assert!(q.is_empty());
353 assert!(q.iter().next().is_none());
354 assert!(q.asc_iter().next().is_none());
355 assert!(q.peek().is_none());
356 }
357
358 #[test]
359 fn partially_full_queue() {
360 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
361 q.create().unwrap().msgs.0 = 1;
362 q.create().unwrap().msgs.0 = 2;
363 q.create().unwrap().msgs.0 = 3;
364
365 assert!(!q.is_empty());
366 assert_eq!(q.len(), 3);
367
368 let res: Vec<i32> = q.iter().map(|x| x.msgs.0).collect();
369 assert_eq!(res, [3, 2, 1]);
370 }
371
372 #[test]
373 fn full_queue() {
374 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
375 q.create().unwrap().msgs.0 = 1;
376 q.create().unwrap().msgs.0 = 2;
377 q.create().unwrap().msgs.0 = 3;
378 q.create().unwrap().msgs.0 = 4;
379 q.create().unwrap().msgs.0 = 5;
380 assert_eq!(q.len(), 5);
381
382 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
383 assert_eq!(res, [5, 4, 3, 2, 1]);
384 }
385
386 #[test]
387 fn over_full_queue() {
388 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
389 q.create().unwrap().msgs.0 = 1;
390 q.create().unwrap().msgs.0 = 2;
391 q.create().unwrap().msgs.0 = 3;
392 q.create().unwrap().msgs.0 = 4;
393 q.create().unwrap().msgs.0 = 5;
394 assert!(q.create().is_none());
395 assert_eq!(q.len(), 5);
396
397 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
398 assert_eq!(res, [5, 4, 3, 2, 1]);
399 }
400
401 #[test]
402 fn clear() {
403 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
404 q.create().unwrap().msgs.0 = 1;
405 q.create().unwrap().msgs.0 = 2;
406 q.create().unwrap().msgs.0 = 3;
407 q.create().unwrap().msgs.0 = 4;
408 q.create().unwrap().msgs.0 = 5;
409 assert!(q.create().is_none());
410 assert_eq!(q.len(), 5);
411
412 q.clear();
413
414 assert_eq!(q.len(), 0);
415 assert!(q.iter().next().is_none());
416
417 q.create().unwrap().msgs.0 = 1;
418 q.create().unwrap().msgs.0 = 2;
419 q.create().unwrap().msgs.0 = 3;
420
421 assert_eq!(q.len(), 3);
422
423 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
424 assert_eq!(res, [3, 2, 1]);
425 }
426
427 #[test]
428 fn create_fresh_slot_starts_initialized_with_zeroed_payload() {
429 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
430
431 let cl = q.create().unwrap();
432 assert_eq!(cl.id, 0);
433 assert_eq!(cl.get_state(), CopperListState::Initialized);
434 assert_eq!(cl.msgs.0, 0);
435 assert_eq!(q.next_cl_id(), 1);
436 assert_eq!(q.last_cl_id(), 0);
437 }
438
439 #[test]
440 fn create_reused_slot_reinitializes_state_but_preserves_payload_storage() {
441 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
442
443 {
444 let cl = q.create().unwrap();
445 cl.msgs.0 = 41;
446 cl.change_state(CopperListState::Processing);
447 }
448
449 let popped = q.pop().unwrap();
450 assert_eq!(popped.id, 0);
451 assert_eq!(popped.get_state(), CopperListState::Processing);
452 assert_eq!(popped.msgs.0, 41);
453
454 let reused = q.create().unwrap();
455 assert_eq!(reused.id, 1);
456 assert_eq!(reused.get_state(), CopperListState::Initialized);
457 assert_eq!(reused.msgs.0, 41);
458 assert_eq!(q.next_cl_id(), 2);
459 assert_eq!(q.last_cl_id(), 1);
460 }
461
462 #[test]
463 fn mutable_iterator() {
464 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
465 q.create().unwrap().msgs.0 = 1;
466 q.create().unwrap().msgs.0 = 2;
467 q.create().unwrap().msgs.0 = 3;
468 q.create().unwrap().msgs.0 = 4;
469 q.create().unwrap().msgs.0 = 5;
470
471 for x in q.iter_mut() {
472 x.msgs.0 *= 2;
473 }
474
475 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
476 assert_eq!(res, [10, 8, 6, 4, 2]);
477 }
478
479 #[test]
480 fn mutable_iterator_non_wrapped_only_visits_active_slots() {
481 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
482 q.create().unwrap().msgs.0 = 1;
483 q.create().unwrap().msgs.0 = 2;
484 q.create().unwrap().msgs.0 = 3;
485
486 let mut visited = Vec::new();
487 for cl in q.iter_mut() {
488 visited.push(cl.id);
489 cl.msgs.0 *= 10;
490 }
491
492 assert_eq!(visited, vec![2, 1, 0]);
493 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
494 assert_eq!(res, [30, 20, 10]);
495 }
496
497 #[test]
498 fn test_drop_last() {
499 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
500 q.create().unwrap().msgs.0 = 1;
501 q.create().unwrap().msgs.0 = 2;
502 q.create().unwrap().msgs.0 = 3;
503 q.create().unwrap().msgs.0 = 4;
504 q.create().unwrap().msgs.0 = 5;
505 assert_eq!(q.len(), 5);
506
507 q.drop_last();
508 assert_eq!(q.len(), 4);
509
510 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
511 assert_eq!(res, [4, 3, 2, 1]);
512 }
513
514 #[test]
515 fn drop_last_on_empty_queue_is_a_noop() {
516 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
517
518 q.drop_last();
519
520 assert!(q.is_empty());
521 assert!(q.peek().is_none());
522 assert!(q.pop().is_none());
523 }
524
525 #[test]
526 fn drop_last_on_non_wrapped_queue_removes_most_recent_slot() {
527 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
528 q.create().unwrap().msgs.0 = 1;
529 q.create().unwrap().msgs.0 = 2;
530 q.create().unwrap().msgs.0 = 3;
531
532 q.drop_last();
533
534 assert_eq!(q.len(), 2);
535 assert_eq!(q.peek().unwrap().msgs.0, 2);
536 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
537 assert_eq!(res, [2, 1]);
538 }
539
540 #[test]
541 fn test_pop() {
542 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
543 q.create().unwrap().msgs.0 = 1;
544 q.create().unwrap().msgs.0 = 2;
545 q.create().unwrap().msgs.0 = 3;
546 q.create().unwrap().msgs.0 = 4;
547 q.create().unwrap().msgs.0 = 5;
548 assert_eq!(q.len(), 5);
549
550 let last = q.pop().unwrap();
551 assert_eq!(last.msgs.0, 5);
552 assert_eq!(q.len(), 4);
553
554 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
555 assert_eq!(res, [4, 3, 2, 1]);
556 }
557
558 #[test]
559 fn pop_on_empty_queue_returns_none() {
560 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
561
562 assert!(q.pop().is_none());
563 assert!(q.is_empty());
564 }
565
566 #[test]
567 fn test_peek() {
568 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
569 q.create().unwrap().msgs.0 = 1;
570 q.create().unwrap().msgs.0 = 2;
571 q.create().unwrap().msgs.0 = 3;
572 q.create().unwrap().msgs.0 = 4;
573 q.create().unwrap().msgs.0 = 5;
574 assert_eq!(q.len(), 5);
575
576 let last = q.peek().unwrap();
577 assert_eq!(last.msgs.0, 5);
578 assert_eq!(q.len(), 5);
579
580 let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
581 assert_eq!(res, [5, 4, 3, 2, 1]);
582 }
583
584 #[test]
585 fn peek_on_empty_queue_returns_none() {
586 let q = CuListsManager::<CuStampedDataSet, 5>::new();
587
588 assert!(q.peek().is_none());
589 }
590
591 #[test]
592 fn next_and_last_cl_id_track_assigned_ids() {
593 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
594
595 assert_eq!(q.next_cl_id(), 0);
597 assert_eq!(q.last_cl_id(), 0);
598
599 let cl0 = q.create().unwrap();
600 assert_eq!(cl0.id, 0);
601 assert_eq!(q.next_cl_id(), 1);
602 assert_eq!(q.last_cl_id(), 0);
603
604 let cl1 = q.create().unwrap();
605 assert_eq!(cl1.id, 1);
606 assert_eq!(q.next_cl_id(), 2);
607 assert_eq!(q.last_cl_id(), 1);
608
609 let _ = q.pop().unwrap();
610 let cl2 = q.create().unwrap();
611 assert_eq!(cl2.id, 2);
612 assert_eq!(q.next_cl_id(), 3);
613 assert_eq!(q.last_cl_id(), 2);
614 }
615
616 #[test]
617 fn asc_iter_non_wrapped_returns_oldest_to_newest_without_free_slots() {
618 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
619 q.create().unwrap().msgs.0 = 10;
620 q.create().unwrap().msgs.0 = 20;
621 q.create().unwrap().msgs.0 = 30;
622
623 let res: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
624 assert_eq!(res, [10, 20, 30]);
625 }
626
627 #[test]
628 fn asc_iter_mut_non_wrapped_only_visits_active_slots_in_oldest_first_order() {
629 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
630 q.create().unwrap().msgs.0 = 10;
631 q.create().unwrap().msgs.0 = 20;
632 q.create().unwrap().msgs.0 = 30;
633
634 let mut visited = Vec::new();
635 for (offset, cl) in q.asc_iter_mut().enumerate() {
636 visited.push(cl.id);
637 cl.msgs.0 += offset as i32;
638 }
639
640 assert_eq!(visited, vec![0, 1, 2]);
641 let res: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
642 assert_eq!(res, [10, 21, 32]);
643 }
644
645 #[test]
646 fn asc_iter_wrapped_layout_tracks_reused_slots_in_ascending_order() {
647 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
648 for value in 1..=5 {
649 q.create().unwrap().msgs.0 = value;
650 }
651 assert_eq!(q.pop().unwrap().msgs.0, 5);
652 assert_eq!(q.pop().unwrap().msgs.0, 4);
653 q.create().unwrap().msgs.0 = 6;
654 q.create().unwrap().msgs.0 = 7;
655
656 let desc: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
657 assert_eq!(desc, [7, 6, 3, 2, 1]);
658
659 let asc: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
660 assert_eq!(asc, [1, 2, 3, 6, 7]);
661 }
662
663 #[test]
664 fn asc_iter_mut_wrapped_layout_updates_oldest_to_newest_order() {
665 let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
666 for value in 1..=5 {
667 q.create().unwrap().msgs.0 = value;
668 }
669 let _ = q.pop().unwrap();
670 let _ = q.pop().unwrap();
671 q.create().unwrap().msgs.0 = 6;
672 q.create().unwrap().msgs.0 = 7;
673
674 let mut visited = Vec::new();
675 for (offset, cl) in q.asc_iter_mut().enumerate() {
676 visited.push(cl.id);
677 cl.msgs.0 += offset as i32;
678 }
679
680 assert_eq!(visited, vec![0, 1, 2, 5, 6]);
681 let asc: Vec<_> = q.asc_iter().map(|x| x.msgs.0).collect();
682 assert_eq!(asc, [1, 3, 5, 9, 11]);
683 }
684
685 #[derive(Decode, Encode, Debug, PartialEq, Clone, Copy)]
686 struct TestStruct {
687 content: [u8; 10_000_000],
688 }
689
690 impl Default for TestStruct {
691 fn default() -> Self {
692 TestStruct {
693 content: [0; 10_000_000],
694 }
695 }
696 }
697
698 impl ErasedCuStampedDataSet for TestStruct {
699 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
700 Vec::new()
701 }
702 }
703
704 impl Serialize for TestStruct {
705 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
706 where
707 S: Serializer,
708 {
709 serializer.serialize_i8(0)
710 }
711 }
712
713 impl MatchingTasks for TestStruct {
714 fn get_all_task_ids() -> &'static [&'static str] {
715 &[]
716 }
717 }
718
719 impl CuListZeroedInit for TestStruct {
720 fn init_zeroed(&mut self) {}
721 }
722
723 #[test]
724 fn be_sure_we_wont_stackoverflow_at_init() {
725 let _ = CuListsManager::<TestStruct, 3>::new();
726 }
727}