1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
use std::{marker::PhantomData, ops::Deref};

use crate::collections::BitVec;

/// Task group outputs state
/// This is used for jumping between multi groups of tasks
/// For example, we have two group G1 and G2,
/// Each cycle we need to call G1.output until it returns None, then we call G2.output until it returns None, then we will have this cycle is finished
/// Then we will start a new cycle and it loop like that
///
/// ```rust
/// use std::time::Instant;
/// use sans_io_runtime::TaskSwitcher;
///
/// // This will create a task switcher with 2 tasks, use 2 bytes, we can adjust max to 16 tasks
/// let mut switcher = TaskSwitcher::new(2);
///
///
/// //we need to pop task index from wait queue
/// switcher.flag_task(0 as usize);
/// assert_eq!(switcher.current(), Some(0));
/// switcher.finished(0 as usize);
/// assert_eq!(switcher.current(), None);
///
/// ```

pub trait TaskSwitcherChild<Out> {
    type Time: Copy;
    fn pop_output(&mut self, now: Self::Time) -> Option<Out>;
}
pub struct TaskSwitcherBranch<Task, Out> {
    task_type: usize,
    task: Task,
    _tmp: PhantomData<Out>,
}

impl<Task: Default, Out> TaskSwitcherBranch<Task, Out> {
    pub fn default<TT: Into<usize>>(tt: TT) -> Self {
        Self {
            task_type: tt.into(),
            task: Default::default(),
            _tmp: Default::default(),
        }
    }
}

impl<Task, Out> TaskSwitcherBranch<Task, Out> {
    pub fn new<TT: Into<usize>>(task: Task, tt: TT) -> Self {
        Self {
            task_type: tt.into(),
            task,
            _tmp: Default::default(),
        }
    }

    pub fn input(&mut self, s: &mut TaskSwitcher) -> &mut Task {
        s.flag_task(self.task_type);
        &mut self.task
    }
}

impl<Task: TaskSwitcherChild<Out>, Out> TaskSwitcherBranch<Task, Out> {
    pub fn pop_output(&mut self, now: Task::Time, s: &mut TaskSwitcher) -> Option<Out> {
        let out = self.task.pop_output(now);
        if out.is_none() {
            s.finished(self.task_type);
        }
        out
    }
}

impl<Task: TaskSwitcherChild<Out>, Out> Deref for TaskSwitcherBranch<Task, Out> {
    type Target = Task;

    fn deref(&self) -> &Self::Target {
        &self.task
    }
}

pub struct TaskSwitcher {
    bits: BitVec,
}

impl TaskSwitcher {
    pub fn new(len: usize) -> Self {
        Self {
            bits: BitVec::news(len),
        }
    }

    pub fn set_tasks(&mut self, tasks: usize) {
        self.bits.set_len(tasks);
    }

    pub fn tasks(&self) -> usize {
        self.bits.len()
    }

    /// Returns the current index of the task group, if it's not finished. Otherwise, returns None.
    pub fn current(&mut self) -> Option<usize> {
        self.bits.first_set_index()
    }

    pub fn flag_all(&mut self) {
        self.bits.set_all(true);
    }

    /// Flag that the current task group is finished.
    pub fn finished<I: Into<usize>>(&mut self, index: I) {
        self.bits.set_bit(index.into(), false);
    }

    pub fn flag_task<I: Into<usize>>(&mut self, index: I) {
        self.bits.set_bit(index.into(), true);
    }
}

#[cfg(test)]
mod tests {
    use crate::TaskSwitcher;

    #[test]
    fn queue_with_stack_like_style() {
        let mut state = TaskSwitcher::new(5);
        state.flag_all();

        assert_eq!(state.current(), Some(0));
        state.finished(0 as usize);
        assert_eq!(state.current(), Some(1));
        state.finished(1 as usize);
        assert_eq!(state.current(), Some(2));
        state.finished(2 as usize);
        assert_eq!(state.current(), Some(3));
        state.finished(3 as usize);
        assert_eq!(state.current(), Some(4));
        state.finished(4 as usize);
        assert_eq!(state.current(), None);

        state.flag_task(3 as usize);

        assert_eq!(state.current(), Some(3));
        state.finished(3 as usize);
        assert_eq!(state.current(), None);
    }

    #[test]
    fn queue_test2() {
        let mut state = TaskSwitcher::new(2);
        state.flag_all();
        assert_eq!(state.current(), Some(0));
        state.finished(0 as usize);
        assert_eq!(state.current(), Some(1));
        state.finished(1 as usize);
        assert_eq!(state.current(), None);

        // next cycle
        state.flag_all();
        assert_eq!(state.current(), Some(0));
        state.finished(0 as usize);
        assert_eq!(state.current(), Some(1));
        state.finished(1 as usize);
        assert_eq!(state.current(), None);
    }

    //TODO test TaskSwitcherChild
}