sans_io_runtime/task/
switcher.rs1use std::{marker::PhantomData, ops::Deref};
2
3use crate::collections::BitVec;
4
5pub trait TaskSwitcherChild<Out> {
28 type Time: Copy;
29 fn empty_event(&self) -> Out;
30 fn is_empty(&self) -> bool;
31 fn pop_output(&mut self, now: Self::Time) -> Option<Out>;
32}
33
34#[derive(Debug)]
35pub struct TaskSwitcherBranch<Task, Out> {
36 task_type: usize,
37 pub task: Task,
38 is_empty: bool,
40 _tmp: PhantomData<Out>,
41}
42
43impl<Task: Default, Out> TaskSwitcherBranch<Task, Out> {
44 pub fn default<TT: Into<usize>>(tt: TT) -> Self {
45 Self {
46 task_type: tt.into(),
47 task: Default::default(),
48 is_empty: false,
49 _tmp: Default::default(),
50 }
51 }
52}
53
54impl<Task, Out> TaskSwitcherBranch<Task, Out> {
55 pub fn new<TT: Into<usize>>(task: Task, tt: TT) -> Self {
56 Self {
57 task_type: tt.into(),
58 task,
59 is_empty: false,
60 _tmp: Default::default(),
61 }
62 }
63
64 pub fn input(&mut self, s: &mut TaskSwitcher) -> &mut Task {
65 s.flag_task(self.task_type);
66 &mut self.task
67 }
68}
69
70impl<Task: TaskSwitcherChild<Out>, Out> TaskSwitcherBranch<Task, Out> {
71 pub fn is_empty(&self) -> bool {
72 self.task.is_empty()
73 }
74
75 pub fn pop_output(&mut self, now: Task::Time, s: &mut TaskSwitcher) -> Option<Out> {
76 let out = self.task.pop_output(now);
77 if out.is_none() {
78 if !self.is_empty {
79 if self.task.is_empty() {
80 self.is_empty = true;
82 return Some(self.task.empty_event());
83 }
84 } else {
85 #[allow(clippy::collapsible_else_if)]
86 if !self.task.is_empty() {
87 self.is_empty = false;
88 }
89 }
90
91 s.finished(self.task_type);
92 }
93 out
94 }
95}
96
97impl<Task, Out> Deref for TaskSwitcherBranch<Task, Out> {
98 type Target = Task;
99
100 fn deref(&self) -> &Self::Target {
101 &self.task
102 }
103}
104
105#[derive(Debug)]
106pub struct TaskSwitcher {
107 bits: BitVec,
108}
109
110impl TaskSwitcher {
111 pub fn new(len: usize) -> Self {
112 Self {
113 bits: BitVec::news(len),
114 }
115 }
116
117 pub fn set_tasks(&mut self, tasks: usize) {
118 self.bits.set_len(tasks);
119 }
120
121 pub fn tasks(&self) -> usize {
122 self.bits.len()
123 }
124
125 pub fn current(&mut self) -> Option<usize> {
127 self.bits.first_set_index()
128 }
129
130 pub fn flag_all(&mut self) {
131 self.bits.set_all(true);
132 }
133
134 pub fn finished<I: Into<usize>>(&mut self, index: I) {
136 self.bits.set_bit(index.into(), false);
137 }
138
139 pub fn flag_task<I: Into<usize>>(&mut self, index: I) {
140 self.bits.set_bit(index.into(), true);
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::TaskSwitcher;
147
148 #[test]
149 fn queue_with_stack_like_style() {
150 let mut state = TaskSwitcher::new(5);
151 state.flag_all();
152
153 assert_eq!(state.current(), Some(0));
154 state.finished(0 as usize);
155 assert_eq!(state.current(), Some(1));
156 state.finished(1 as usize);
157 assert_eq!(state.current(), Some(2));
158 state.finished(2 as usize);
159 assert_eq!(state.current(), Some(3));
160 state.finished(3 as usize);
161 assert_eq!(state.current(), Some(4));
162 state.finished(4 as usize);
163 assert_eq!(state.current(), None);
164
165 state.flag_task(3 as usize);
166
167 assert_eq!(state.current(), Some(3));
168 state.finished(3 as usize);
169 assert_eq!(state.current(), None);
170 }
171
172 #[test]
173 fn queue_test2() {
174 let mut state = TaskSwitcher::new(2);
175 state.flag_all();
176 assert_eq!(state.current(), Some(0));
177 state.finished(0 as usize);
178 assert_eq!(state.current(), Some(1));
179 state.finished(1 as usize);
180 assert_eq!(state.current(), None);
181
182 state.flag_all();
184 assert_eq!(state.current(), Some(0));
185 state.finished(0 as usize);
186 assert_eq!(state.current(), Some(1));
187 state.finished(1 as usize);
188 assert_eq!(state.current(), None);
189 }
190
191 }