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
//! Stepping through a fixed set of choices, wrapping at either end.
/// The choice `delta` steps after `current`, wrapping around `choices`.
pub fn cycled<T: Copy + PartialEq>(choices: &[T], current: T, delta: i8) -> T {
let position = choices
.iter()
.position(|choice| *choice == current)
.expect("the current choice is among the choices");
choices[(position as isize + isize::from(delta)).rem_euclid(choices.len() as isize) as usize]
}
/// Declares an enum stepped through its variants in the order written: `CHOICES`
/// lists them, and `cycle` steps `delta` of them on, wrapping at either end.
macro_rules! cyclic {
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$($(#[$variant_meta:meta])* $variant:ident $(= $discriminant:tt)?),+ $(,)?
}
) => {
$(#[$meta])*
$vis enum $name {
$($(#[$variant_meta])* $variant $(= $discriminant)?),+
}
impl $name {
/// Every choice, in the order stepped through.
$vis const CHOICES: &[Self] = &[$(Self::$variant),+];
/// The choice `delta` steps on from this one, wrapping around.
#[allow(dead_code)] // a tab's rows are listed, never stepped
$vis fn cycle(self, delta: i8) -> Self {
$crate::ui::cycle::cycled(Self::CHOICES, self, delta)
}
}
};
}
pub(crate) use cyclic;