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}