#[cfg(not(feature = "std"))]
extern crate alloc;
use alloc::alloc::{alloc_zeroed, handle_alloc_error};
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::alloc::Layout;
use bincode::{Decode, Encode};
use core::fmt;
use core::fmt::Display;
use core::iter::{Chain, Rev};
use core::slice::{Iter as SliceIter, IterMut as SliceIterMut};
use cu29_traits::{CopperListTuple, ErasedCuStampedData, ErasedCuStampedDataSet};
use serde_derive::{Deserialize, Serialize};
const MAX_TASKS: usize = 512;
#[derive(Debug, Encode, Decode, PartialEq, Clone, Copy)]
pub struct CopperLiskMask {
#[allow(dead_code)]
mask: [u128; MAX_TASKS / 128 + 1],
}
#[derive(Debug, Encode, Decode, Serialize, Deserialize, PartialEq, Copy, Clone)]
pub enum CopperListState {
Free,
Initialized,
Processing,
DoneProcessing,
QueuedForSerialization,
BeingSerialized,
}
impl Display for CopperListState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CopperListState::Free => write!(f, "Free"),
CopperListState::Initialized => write!(f, "Initialized"),
CopperListState::Processing => write!(f, "Processing"),
CopperListState::DoneProcessing => write!(f, "DoneProcessing"),
CopperListState::QueuedForSerialization => write!(f, "QueuedForSerialization"),
CopperListState::BeingSerialized => write!(f, "BeingSerialized"),
}
}
}
#[derive(Debug, Encode, Decode, Serialize, Deserialize)]
pub struct CopperList<P: CopperListTuple> {
pub id: u64,
state: CopperListState,
pub msgs: P, }
impl<P: CopperListTuple> Default for CopperList<P> {
fn default() -> Self {
CopperList {
id: 0,
state: CopperListState::Free,
msgs: P::default(),
}
}
}
impl<P: CopperListTuple> CopperList<P> {
pub fn new(id: u64, msgs: P) -> Self {
CopperList {
id,
state: CopperListState::Initialized,
msgs,
}
}
pub fn change_state(&mut self, new_state: CopperListState) {
self.state = new_state; }
pub fn get_state(&self) -> CopperListState {
self.state
}
}
impl<P: CopperListTuple> ErasedCuStampedDataSet for CopperList<P> {
fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
self.msgs.cumsgs()
}
}
pub struct CuListsManager<P: CopperListTuple, const N: usize> {
data: Box<[CopperList<P>; N]>,
length: usize,
insertion_index: usize,
current_cl_id: u64,
}
impl<P: CopperListTuple + fmt::Debug, const N: usize> fmt::Debug for CuListsManager<P, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CuListsManager")
.field("data", &self.data)
.field("length", &self.length)
.field("insertion_index", &self.insertion_index)
.finish()
}
}
pub type Iter<'a, T> = Chain<Rev<SliceIter<'a, T>>, Rev<SliceIter<'a, T>>>;
pub type IterMut<'a, T> = Chain<Rev<SliceIterMut<'a, T>>, Rev<SliceIterMut<'a, T>>>;
pub type AscIter<'a, T> = Chain<SliceIter<'a, T>, SliceIter<'a, T>>;
pub type AscIterMut<'a, T> = Chain<SliceIterMut<'a, T>, SliceIterMut<'a, T>>;
pub trait CuListZeroedInit: CopperListTuple {
fn init_zeroed(&mut self);
}
impl<P: CopperListTuple + CuListZeroedInit, const N: usize> Default for CuListsManager<P, N> {
fn default() -> Self {
Self::new()
}
}
impl<P: CopperListTuple, const N: usize> CuListsManager<P, N> {
pub fn new() -> Self
where
P: CuListZeroedInit,
{
let data = unsafe {
let layout = Layout::new::<[CopperList<P>; N]>();
let ptr = alloc_zeroed(layout) as *mut [CopperList<P>; N];
if ptr.is_null() {
handle_alloc_error(layout);
}
Box::from_raw(ptr)
};
let mut manager = CuListsManager {
data,
length: 0,
insertion_index: 0,
current_cl_id: 0,
};
for cl in manager.data.iter_mut() {
cl.msgs.init_zeroed();
}
manager
}
#[inline]
pub fn len(&self) -> usize {
self.length
}
#[inline]
pub fn is_empty(&self) -> bool {
self.length == 0
}
#[inline]
pub fn is_full(&self) -> bool {
N == self.len()
}
#[inline]
pub fn clear(&mut self) {
self.insertion_index = 0;
self.length = 0;
}
#[inline]
pub fn create(&mut self) -> Option<&mut CopperList<P>> {
if self.is_full() {
return None;
}
let result = &mut self.data[self.insertion_index];
self.insertion_index = (self.insertion_index + 1) % N;
self.length += 1;
result.id = self.current_cl_id;
self.current_cl_id += 1;
Some(result)
}
#[inline]
pub fn next_cl_id(&self) -> u64 {
self.current_cl_id
}
#[inline]
pub fn last_cl_id(&self) -> u64 {
self.current_cl_id.saturating_sub(1)
}
#[inline]
pub fn peek(&self) -> Option<&CopperList<P>> {
if self.length == 0 {
return None;
}
let index = if self.insertion_index == 0 {
N - 1
} else {
self.insertion_index - 1
};
Some(&self.data[index])
}
#[inline]
#[allow(dead_code)]
fn drop_last(&mut self) {
if self.length == 0 {
return;
}
if self.insertion_index == 0 {
self.insertion_index = N - 1;
} else {
self.insertion_index -= 1;
}
self.length -= 1;
}
#[inline]
pub fn pop(&mut self) -> Option<&mut CopperList<P>> {
if self.length == 0 {
return None;
}
if self.insertion_index == 0 {
self.insertion_index = N - 1;
} else {
self.insertion_index -= 1;
}
self.length -= 1;
Some(&mut self.data[self.insertion_index])
}
#[inline]
pub fn iter(&self) -> Iter<'_, CopperList<P>> {
let (a, b) = self.data[0..self.length].split_at(self.insertion_index);
a.iter().rev().chain(b.iter().rev())
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, CopperList<P>> {
let (a, b) = self.data.split_at_mut(self.insertion_index);
a.iter_mut().rev().chain(b.iter_mut().rev())
}
#[inline]
pub fn asc_iter(&self) -> AscIter<'_, CopperList<P>> {
let (a, b) = self.data.split_at(self.insertion_index);
b.iter().chain(a.iter())
}
#[inline]
pub fn asc_iter_mut(&mut self) -> AscIterMut<'_, CopperList<P>> {
let (a, b) = self.data.split_at_mut(self.insertion_index);
b.iter_mut().chain(a.iter_mut())
}
}
#[cfg(test)]
mod tests {
use super::*;
use cu29_traits::{ErasedCuStampedData, ErasedCuStampedDataSet, MatchingTasks};
use serde::{Deserialize, Serialize, Serializer};
#[derive(Debug, Encode, Decode, PartialEq, Clone, Copy, Serialize, Deserialize, Default)]
struct CuStampedDataSet(i32);
impl ErasedCuStampedDataSet for CuStampedDataSet {
fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
Vec::new()
}
}
impl MatchingTasks for CuStampedDataSet {
fn get_all_task_ids() -> &'static [&'static str] {
&[]
}
}
impl CuListZeroedInit for CuStampedDataSet {
fn init_zeroed(&mut self) {}
}
#[test]
fn empty_queue() {
let q = CuListsManager::<CuStampedDataSet, 5>::new();
assert!(q.is_empty());
assert!(q.iter().next().is_none());
}
#[test]
fn partially_full_queue() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
assert!(!q.is_empty());
assert_eq!(q.len(), 3);
let res: Vec<i32> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [3, 2, 1]);
}
#[test]
fn full_queue() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
q.create().unwrap().msgs.0 = 4;
q.create().unwrap().msgs.0 = 5;
assert_eq!(q.len(), 5);
let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [5, 4, 3, 2, 1]);
}
#[test]
fn over_full_queue() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
q.create().unwrap().msgs.0 = 4;
q.create().unwrap().msgs.0 = 5;
assert!(q.create().is_none());
assert_eq!(q.len(), 5);
let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [5, 4, 3, 2, 1]);
}
#[test]
fn clear() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
q.create().unwrap().msgs.0 = 4;
q.create().unwrap().msgs.0 = 5;
assert!(q.create().is_none());
assert_eq!(q.len(), 5);
q.clear();
assert_eq!(q.len(), 0);
assert!(q.iter().next().is_none());
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
assert_eq!(q.len(), 3);
let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [3, 2, 1]);
}
#[test]
fn mutable_iterator() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
q.create().unwrap().msgs.0 = 4;
q.create().unwrap().msgs.0 = 5;
for x in q.iter_mut() {
x.msgs.0 *= 2;
}
let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [10, 8, 6, 4, 2]);
}
#[test]
fn test_drop_last() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
q.create().unwrap().msgs.0 = 4;
q.create().unwrap().msgs.0 = 5;
assert_eq!(q.len(), 5);
q.drop_last();
assert_eq!(q.len(), 4);
let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [4, 3, 2, 1]);
}
#[test]
fn test_pop() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
q.create().unwrap().msgs.0 = 4;
q.create().unwrap().msgs.0 = 5;
assert_eq!(q.len(), 5);
let last = q.pop().unwrap();
assert_eq!(last.msgs.0, 5);
assert_eq!(q.len(), 4);
let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [4, 3, 2, 1]);
}
#[test]
fn test_peek() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
q.create().unwrap().msgs.0 = 1;
q.create().unwrap().msgs.0 = 2;
q.create().unwrap().msgs.0 = 3;
q.create().unwrap().msgs.0 = 4;
q.create().unwrap().msgs.0 = 5;
assert_eq!(q.len(), 5);
let last = q.peek().unwrap();
assert_eq!(last.msgs.0, 5);
assert_eq!(q.len(), 5);
let res: Vec<_> = q.iter().map(|x| x.msgs.0).collect();
assert_eq!(res, [5, 4, 3, 2, 1]);
}
#[test]
fn next_and_last_cl_id_track_assigned_ids() {
let mut q = CuListsManager::<CuStampedDataSet, 5>::new();
assert_eq!(q.next_cl_id(), 0);
assert_eq!(q.last_cl_id(), 0);
let cl0 = q.create().unwrap();
assert_eq!(cl0.id, 0);
assert_eq!(q.next_cl_id(), 1);
assert_eq!(q.last_cl_id(), 0);
let cl1 = q.create().unwrap();
assert_eq!(cl1.id, 1);
assert_eq!(q.next_cl_id(), 2);
assert_eq!(q.last_cl_id(), 1);
}
#[derive(Decode, Encode, Debug, PartialEq, Clone, Copy)]
struct TestStruct {
content: [u8; 10_000_000],
}
impl Default for TestStruct {
fn default() -> Self {
TestStruct {
content: [0; 10_000_000],
}
}
}
impl ErasedCuStampedDataSet for TestStruct {
fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData> {
Vec::new()
}
}
impl Serialize for TestStruct {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_i8(0)
}
}
impl MatchingTasks for TestStruct {
fn get_all_task_ids() -> &'static [&'static str] {
&[]
}
}
impl CuListZeroedInit for TestStruct {
fn init_zeroed(&mut self) {}
}
#[test]
fn be_sure_we_wont_stackoverflow_at_init() {
let _ = CuListsManager::<TestStruct, 3>::new();
}
}