psyche_utils/
switch.rs

1//! Tool used to sequentialy switch between many options of same data.
2
3use serde::{Deserialize, Serialize};
4
5/// Collection that contains several versions/options of data so you can switch between them in
6/// sequential manner. It can be used to produce next data frame based on previous data frame.
7///
8/// # Example
9/// ```
10/// use psyche_utils::switch::Switch;
11///
12/// let mut switch = Switch::new(2, vec![1, 2, 4]);
13/// if let Some((prev, next)) = switch.iterate() {
14///     for i in 0..prev.len() {
15///         // next frame item equals sum of two neighbors.
16///         let start = i.max(1) - 1;
17///         let end = (i + 2).min(prev.len());
18///         next[i] = (start..end).map(|i| prev[i]).sum();
19///     }
20/// }
21/// assert_eq!(switch.get().unwrap(), &vec![3, 7, 6]);
22/// ```
23#[derive(Serialize, Deserialize)]
24pub struct Switch<T> {
25    index: usize,
26    options: Vec<T>,
27}
28
29impl<T> Switch<T> {
30    /// Creates new switch with number of options and cloned value applied for each of them.
31    ///
32    /// # Arguments
33    /// * `options` - Number of options that switch will hold.
34    /// * `value` - Initial value applied for each of options.
35    ///
36    /// # Return
37    /// Instance of switch.
38    ///
39    /// # Example
40    /// ```
41    /// use psyche_utils::switch::Switch;
42    ///
43    /// let switch = Switch::new(2, vec![1, 2, 4]);
44    /// ```
45    pub fn new(options: usize, value: T) -> Self
46    where
47        T: Clone,
48    {
49        Self {
50            index: 0,
51            options: vec![value; options],
52        }
53    }
54
55    /// Creates new switch with initial options values.
56    ///
57    /// # Note
58    /// Make sure that your options values have same length if they are for example arrays or
59    /// vectors or any other collection that needs to have same length across each iteration.
60    ///
61    /// # Arguments
62    /// * `options` - Initial values applied for options.
63    ///
64    /// # Return
65    /// Instance of switch.
66    ///
67    /// # Example
68    /// ```
69    /// use psyche_utils::switch::Switch;
70    ///
71    /// let switch = Switch::with_options(vec![
72    ///     vec![1, 2, 4],
73    ///     vec![3, 7, 6],
74    /// ]);
75    /// ```
76    pub fn with_options(options: Vec<T>) -> Self {
77        Self { index: 0, options }
78    }
79
80    /// Gets currently active option index.
81    ///
82    /// # Return
83    /// Index of currently active switch option.
84    ///
85    /// # Example
86    /// ```
87    /// use psyche_utils::switch::Switch;
88    ///
89    /// let mut switch = Switch::new(2, 0);
90    /// assert_eq!(switch.index(), 0);
91    /// switch.switch();
92    /// assert_eq!(switch.index(), 1);
93    /// switch.switch();
94    /// assert_eq!(switch.index(), 0);
95    /// ```
96    pub fn index(&self) -> usize {
97        self.index
98    }
99
100    /// Gets number of options that holds.
101    ///
102    /// # Return
103    /// Number of switch options.
104    ///
105    /// # Example
106    /// ```
107    /// use psyche_utils::switch::Switch;
108    ///
109    /// let mut switch = Switch::new(2, 0);
110    /// assert_eq!(switch.count(), 2);
111    /// ```
112    pub fn count(&self) -> usize {
113        self.options.len()
114    }
115
116    /// Switches to next option.
117    ///
118    /// # Example
119    /// ```
120    /// use psyche_utils::switch::Switch;
121    ///
122    /// let mut switch = Switch::with_options(vec![0, 1]);
123    /// assert_eq!(*switch.get().unwrap(), 0);
124    /// switch.switch();
125    /// assert_eq!(*switch.get().unwrap(), 1);
126    /// ```
127    pub fn switch(&mut self) {
128        if !self.options.is_empty() {
129            self.index = (self.index + 1) % self.options.len();
130        }
131    }
132
133    /// Switches to next option and returns pair of _previous_ and _next_ options.
134    ///
135    /// # Return
136    /// Pair of _previous_ and _next_ options if holds more than one.
137    ///
138    /// # Example
139    /// ```
140    /// use psyche_utils::switch::Switch;
141    ///
142    /// let mut switch = Switch::with_options(vec![0, 1]);
143    /// assert_eq!(switch.iterate().unwrap(), (&0, &mut 1));
144    /// ```
145    pub fn iterate(&mut self) -> Option<(&T, &mut T)> {
146        if !self.options.is_empty() {
147            let prev = self.index;
148            self.index = (self.index + 1) % self.options.len();
149            let next = self.index;
150            if prev != next {
151                unsafe {
152                    let prev_option_ptr = self.options.as_ptr().offset(prev as isize);
153                    let next_option_ptr = self.options.as_mut_ptr().offset(next as isize);
154                    return Some((
155                        prev_option_ptr.as_ref().unwrap(),
156                        next_option_ptr.as_mut().unwrap(),
157                    ));
158                }
159            }
160        }
161        None
162    }
163
164    /// Gets currently active option if any.
165    ///
166    /// # Return
167    /// Reference to currently active option.
168    ///
169    /// # Example
170    /// ```
171    /// use psyche_utils::switch::Switch;
172    ///
173    /// let mut switch = Switch::with_options(vec![0, 1]);
174    /// assert_eq!(switch.get().unwrap(), &0);
175    /// ```
176    pub fn get(&self) -> Option<&T> {
177        if !self.options.is_empty() {
178            Some(&self.options[self.index])
179        } else {
180            None
181        }
182    }
183
184    /// Gets currently active option if any.
185    ///
186    /// # Return
187    /// Mutable reference to currently active option.
188    ///
189    /// # Example
190    /// ```
191    /// use psyche_utils::switch::Switch;
192    ///
193    /// let mut switch = Switch::with_options(vec![0, 1]);
194    /// assert_eq!(switch.get_mut().unwrap(), &mut 0);
195    /// ```
196    pub fn get_mut(&mut self) -> Option<&mut T> {
197        if !self.options.is_empty() {
198            Some(&mut self.options[self.index])
199        } else {
200            None
201        }
202    }
203}
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208
209    #[test]
210    fn test_switch() {
211        let mut switch = Switch::with_options(vec![1, 2]);
212        assert_eq!(*switch.get().unwrap(), 1);
213        switch.switch();
214        assert_eq!(*switch.get().unwrap(), 2);
215        switch.switch();
216        assert_eq!(*switch.get().unwrap(), 1);
217        switch.switch();
218        assert_eq!(*switch.get().unwrap(), 2);
219        assert_eq!(switch.iterate().unwrap(), (&2, &mut 1))
220    }
221}