rant/
selector.rs

1use std::{ops::Deref, rc::Rc, cell::RefCell, fmt::Display, error::Error};
2
3use crate::{rng::RantRng, ValueError, TryFromRant, RantValue, runtime::{RuntimeError, IntoRuntimeResult}};
4
5/// Reference handle for a Rant selector.
6#[derive(Debug, Clone)]
7pub struct RantSelectorHandle(Rc<RefCell<RantSelector>>);
8
9impl RantSelectorHandle {
10  pub fn cloned(&self) -> Self {
11    Self(Rc::new(RefCell::new((*self.0.borrow()).clone())))
12  }
13}
14
15impl Deref for RantSelectorHandle {
16  type Target = RefCell<RantSelector>;
17
18  fn deref(&self) -> &Self::Target {
19    &self.0
20  }
21}
22
23impl PartialEq for RantSelectorHandle {
24  fn eq(&self, other: &Self) -> bool {
25    self.0.as_ptr() == other.0.as_ptr()
26  }
27}
28
29impl From<RantSelector> for RantSelectorHandle {
30  fn from(sel: RantSelector) -> Self {
31    Self(Rc::new(RefCell::new(sel)))
32  }
33}
34
35/// Represents a Rant selector instance used by the resolver to select block branches.
36#[derive(Debug, Clone)]
37pub struct RantSelector {
38  /// Mode of the selector
39  mode: SelectorMode,
40  /// Current iteration of the selector
41  index: usize,
42  /// Element count of the selector
43  count: usize,
44  /// True if the pass is odd (used by modes with alternating pass behaviors, such as mirror modes)
45  parity: bool,
46  /// If set to true, keeps selecting the last selected index.
47  frozen: bool,
48  /// Jump table used by some selector modes (won't allocate if unused)
49  jump_table: Vec<usize>,
50}
51
52impl RantSelector {
53  /// Creates a new selector.
54  #[inline]
55  pub fn new(mode: SelectorMode) -> Self {
56    Self {
57      mode,
58      index: 0,
59      count: 0,
60      frozen: false,
61      parity: false,
62      jump_table: Default::default(),
63    }
64  }
65
66  /// Converts the instance into a handle.
67  #[inline]
68  pub fn into_handle(self) -> RantSelectorHandle {
69    self.into()
70  }
71
72  /// The mode assigned to the selector.
73  #[inline]
74  pub fn mode(&self) -> SelectorMode {
75    self.mode
76  }
77
78  /// The next index to be selected.
79  #[inline]
80  pub fn index(&self) -> usize {
81    self.index
82  }
83
84  /// The number of block elements that this selector is initialized for.
85  /// 
86  /// A value of 0 indicates that the selector is uninitialized (as selecting over 0 branches is impossible).
87  #[inline]
88  pub fn count(&self) -> usize {
89    self.count
90  }
91
92  /// Indicates the parity state of the selector. Some selectors use two alternating passes (such as mirror modes).
93  /// The parity indicates which of these passes is currently active.
94  #[inline]
95  pub fn parity(&self) -> bool {
96    self.parity
97  }
98
99  /// Indicates whether the selector is frozen.
100  #[inline]
101  pub fn is_frozen(&self) -> bool {
102    self.frozen
103  }
104
105  /// Sets the frozen state of the selector.
106  #[inline]
107  pub fn set_frozen(&mut self, frozen: bool) {
108    self.frozen = frozen;
109  }
110
111  /// Indicates whether the selector has been initialized with [`Selector::init`].
112  #[inline]
113  pub fn is_initialized(&self) -> bool {
114    self.count > 0
115  }
116
117  /// Initializes the selector state using the specified element count.
118  #[inline]
119  pub fn init(&mut self, rng: &RantRng, elem_count: usize) -> Result<(), SelectorError> {
120    if elem_count == 0 {
121      return Err(SelectorError::InvalidElementCount(0))
122    }
123
124    self.count = elem_count;
125    
126    match self.mode {
127      SelectorMode::Random | SelectorMode::One | SelectorMode::NoDouble => {
128        self.index = rng.next_usize(elem_count);
129      },
130      SelectorMode::Forward | SelectorMode::ForwardClamp | SelectorMode::ForwardMirror | SelectorMode::Ping |
131      SelectorMode::Reverse | SelectorMode::ReverseClamp | SelectorMode::ReverseMirror | SelectorMode::Pong => {
132        self.index = 0;
133      },
134      SelectorMode::Deck | SelectorMode::DeckLoop | SelectorMode::DeckClamp | SelectorMode::DeckMirror => {
135        self.shuffle(rng);
136      },
137    }
138
139    Ok(())
140  }
141
142  /// SHuffles the branch indices in the selector's jump table.
143  #[inline]
144  fn shuffle(&mut self, rng: &RantRng) {
145    let jump_table = &mut self.jump_table;
146    let n = self.count;
147
148    // Populate the jump table if it isn't already
149    if jump_table.is_empty() {
150      jump_table.reserve(n);
151      jump_table.extend(0..n);
152    }
153
154    // Perform a Fisher-Yates shuffle
155    for i in 0..n {
156      jump_table.swap(i, rng.next_usize(n));
157    }
158  }
159
160  /// Returns the next branch index and advances the selector state.
161  pub fn select(&mut self, elem_count: usize, rng: &RantRng) -> Result<usize, SelectorError> {
162    // Initialize and sanity check
163    if !self.is_initialized() {
164      self.init(rng, elem_count)?;
165    } else if elem_count != self.count {
166      return Err(SelectorError::ElementCountMismatch { 
167        expected: self.count,
168        found: elem_count,
169      })
170    }
171
172    let cur_index = self.index;
173    let cur_index_inv = self.count.saturating_sub(cur_index).saturating_sub(1);
174
175    macro_rules! next_index {
176      ($v:expr) => {
177        if !self.frozen {
178          self.index = $v;
179        }
180      }
181    }
182
183    macro_rules! next_parity {
184      ($v:expr) => {
185        if !self.frozen {
186          self.parity = $v;
187        }
188      }
189    }
190
191    // Iterate the selector
192    match self.mode {
193      SelectorMode::Random => {
194        next_index!(rng.next_usize(elem_count));
195      },
196      SelectorMode::One => {},
197      mode @ (SelectorMode::Forward | SelectorMode::Reverse) => {
198        next_index!((cur_index + 1) % elem_count);
199        if mode == SelectorMode::Reverse { return Ok(cur_index_inv) }
200      },
201      mode @ (SelectorMode::ForwardClamp | SelectorMode::ReverseClamp) => {
202        next_index!((cur_index + 1).min(elem_count - 1));
203        if mode == SelectorMode::ReverseClamp { return Ok(cur_index_inv) }
204      },
205      mode @ (SelectorMode::ForwardMirror | SelectorMode::ReverseMirror) => {
206        let prev_parity = self.parity;
207        if (prev_parity && cur_index == 0) || (!prev_parity && cur_index == elem_count - 1) {
208          next_parity!(!prev_parity);
209        } else if self.parity {
210          next_index!(cur_index.saturating_sub(1));
211        } else {
212          next_index!((cur_index + 1) % elem_count);
213        }
214        if mode == SelectorMode::ReverseMirror { return Ok(cur_index_inv) }
215      },
216      SelectorMode::Deck => {
217        // Store the return value before reshuffling to avoid accidental early duplicates
218        let jump_index = self.jump_table[cur_index];
219
220        if !self.frozen {
221          if cur_index >= elem_count - 1 {
222            self.shuffle(rng);
223            next_index!(0);
224          } else {
225            next_index!(cur_index + 1);
226          }
227        }
228
229        return Ok(jump_index)
230      },
231      SelectorMode::DeckMirror => {
232        // Store the return value before reshuffling to avoid accidental early duplicates
233        let jump_index = self.jump_table[cur_index];
234        
235        if !self.frozen {
236          let cur_parity = self.parity;
237          
238          // Flip parity after boundary elements
239          if (cur_parity && cur_index == 0) || (!cur_parity && cur_index >= elem_count - 1) {
240            // If previous parity was odd, reshuffle
241            if cur_parity {
242              self.shuffle(rng);
243            }
244            
245            next_parity!(!cur_parity);
246          } else if self.parity {
247            next_index!(cur_index.saturating_sub(1));
248          } else {
249            next_index!((cur_index + 1).min(elem_count - 1))
250          }
251        }
252
253        return Ok(jump_index)
254      },
255      SelectorMode::DeckLoop => {
256        next_index!((cur_index + 1) % elem_count);
257        return Ok(self.jump_table[cur_index])
258      },
259      SelectorMode::DeckClamp => {
260        next_index!((cur_index + 1).min(elem_count - 1));
261        return Ok(self.jump_table[cur_index])
262      },
263      mode @ (SelectorMode::Ping | SelectorMode::Pong) => {
264        if !self.frozen {
265          let prev_parity = self.parity;
266          if (prev_parity && cur_index == 0) || (!prev_parity && cur_index >= elem_count - 1) {
267            next_parity!(!prev_parity);
268          }
269
270          if self.parity {
271            next_index!(cur_index.saturating_sub(1));
272          } else {
273            next_index!((cur_index + 1) % elem_count);
274          }
275        }
276
277        if mode == SelectorMode::Pong { return Ok(cur_index_inv) }
278      },
279      SelectorMode::NoDouble => {
280        next_index!(if elem_count > 1 {
281          (cur_index + 1 + rng.next_usize(elem_count - 1)) % elem_count
282        } else {
283          0
284        });
285      },
286    }
287
288    Ok(cur_index)
289  }
290}
291
292/// Represents error states of a selector.
293#[derive(Debug)]
294pub enum SelectorError {
295  /// The requested element count was different than what the selector was initialized for.
296  ElementCountMismatch { expected: usize, found: usize },
297  /// The specified element count is not supported.
298  InvalidElementCount(usize),
299}
300
301impl Error for SelectorError {}
302
303impl Display for SelectorError {
304  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
305    match self {
306      SelectorError::ElementCountMismatch { expected, found } => write!(f, "selector expected {} elements, but found {}", expected, found),
307      SelectorError::InvalidElementCount(n) => write!(f, "selector does not support blocks of size {}", n),
308    }
309  }
310}
311
312impl<T> IntoRuntimeResult<T> for Result<T, SelectorError> {
313  fn into_runtime_result(self) -> super::RuntimeResult<T> {
314    self.map_err(|err| RuntimeError {
315      error_type: super::RuntimeErrorType::SelectorError(err),
316      description: None,
317      stack_trace: None,
318    })
319  }
320}
321
322/// Defines available branch selection modes for selectors.
323#[derive(Debug, Copy, Clone, PartialEq)]
324#[repr(u8)]
325pub enum SelectorMode {
326  /// Selects a random element each time.
327  Random,
328  /// Selects the same, random element each time.
329  One,
330  /// Selects each element in a wrapping sequence from left to right.
331  Forward,
332  /// Selects each element from left to right, then repeats the right-most element.
333  ForwardClamp,
334  /// Selects each element from left to right, then right to left, and repeats.
335  /// Boundary elements are repeated.
336  ForwardMirror,
337  /// Selects each element in a wrapping reverse sequence from right to left.
338  Reverse,
339  /// Selects each element from right to left, then repeats the left-most element.
340  ReverseClamp,
341  /// Selects each element from right to left, then left to right, and repeats.
342  /// Boundary elements are repeated.
343  ReverseMirror,
344  /// Selects each element once in a random sequence, then reshuffles.
345  Deck,
346  /// Selects each element once in a wrapping random sequence, without reshuffling.
347  DeckLoop,
348  /// Selects each element once in a random sequence, repeating the final element.
349  DeckClamp,
350  /// Selects each element once in a random sequence, then selects the same sequence backwards, then reshuffles and repeats.
351  /// Mirror boundary elements are repeated.
352  DeckMirror,
353  /// Selects each element from left to right, switching directions each time a boundary element is reached.
354  /// Boundary elements are not repeated.
355  Ping,
356  /// Selects each element from right to left, switching directions each time a boundary element is reached.
357  /// Boundary elements are not repeated.
358  Pong,
359  /// Ensures that no one element index is selected twice in a row.
360  NoDouble,
361}
362
363impl TryFromRant for SelectorMode {
364  fn try_from_rant(val: RantValue) -> Result<Self, ValueError> {
365    match &val {
366      RantValue::String(s) => {
367        Ok(match s.as_str() {
368          "random" =>         SelectorMode::Random,
369          "one" =>            SelectorMode::One,
370          "forward" =>        SelectorMode::Forward,
371          "forward-clamp" =>  SelectorMode::ForwardClamp,
372          "forward-mirror" => SelectorMode::ForwardMirror,
373          "reverse" =>        SelectorMode::Reverse,
374          "reverse-clamp" =>  SelectorMode::ReverseClamp,
375          "reverse-mirror" => SelectorMode::ReverseMirror,
376          "deck" =>           SelectorMode::Deck,
377          "deck-loop" =>      SelectorMode::DeckLoop,
378          "deck-clamp" =>     SelectorMode::DeckClamp,
379          "deck-mirror" =>    SelectorMode::DeckMirror,
380          "ping" =>           SelectorMode::Ping,
381          "pong" =>           SelectorMode::Pong,
382          "no-double" =>      SelectorMode::NoDouble,
383          invalid => return Err(ValueError::InvalidConversion {
384            from: val.type_name(),
385            to: "selector mode",
386            message: Some(format!("invalid selector mode: '{invalid}'"))
387          })
388        })
389      },
390      _ => Err(ValueError::InvalidConversion {
391        from: val.type_name(),
392        to: "selector mode",
393        message: None,
394      })
395    }
396  }
397}