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#[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#[derive(Debug, Clone)]
37pub struct RantSelector {
38 mode: SelectorMode,
40 index: usize,
42 count: usize,
44 parity: bool,
46 frozen: bool,
48 jump_table: Vec<usize>,
50}
51
52impl RantSelector {
53 #[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 #[inline]
68 pub fn into_handle(self) -> RantSelectorHandle {
69 self.into()
70 }
71
72 #[inline]
74 pub fn mode(&self) -> SelectorMode {
75 self.mode
76 }
77
78 #[inline]
80 pub fn index(&self) -> usize {
81 self.index
82 }
83
84 #[inline]
88 pub fn count(&self) -> usize {
89 self.count
90 }
91
92 #[inline]
95 pub fn parity(&self) -> bool {
96 self.parity
97 }
98
99 #[inline]
101 pub fn is_frozen(&self) -> bool {
102 self.frozen
103 }
104
105 #[inline]
107 pub fn set_frozen(&mut self, frozen: bool) {
108 self.frozen = frozen;
109 }
110
111 #[inline]
113 pub fn is_initialized(&self) -> bool {
114 self.count > 0
115 }
116
117 #[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 #[inline]
144 fn shuffle(&mut self, rng: &RantRng) {
145 let jump_table = &mut self.jump_table;
146 let n = self.count;
147
148 if jump_table.is_empty() {
150 jump_table.reserve(n);
151 jump_table.extend(0..n);
152 }
153
154 for i in 0..n {
156 jump_table.swap(i, rng.next_usize(n));
157 }
158 }
159
160 pub fn select(&mut self, elem_count: usize, rng: &RantRng) -> Result<usize, SelectorError> {
162 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 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 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 let jump_index = self.jump_table[cur_index];
234
235 if !self.frozen {
236 let cur_parity = self.parity;
237
238 if (cur_parity && cur_index == 0) || (!cur_parity && cur_index >= elem_count - 1) {
240 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#[derive(Debug)]
294pub enum SelectorError {
295 ElementCountMismatch { expected: usize, found: usize },
297 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#[derive(Debug, Copy, Clone, PartialEq)]
324#[repr(u8)]
325pub enum SelectorMode {
326 Random,
328 One,
330 Forward,
332 ForwardClamp,
334 ForwardMirror,
337 Reverse,
339 ReverseClamp,
341 ReverseMirror,
344 Deck,
346 DeckLoop,
348 DeckClamp,
350 DeckMirror,
353 Ping,
356 Pong,
359 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}