pub trait Cycle: Sized + Copy + PartialEq + 'static {
const VARIANTS: &'static [Self];
fn index(self) -> usize {
Self::VARIANTS.iter().position(|&x| x == self).unwrap_or(0)
}
fn from_index(index: usize) -> Self {
Self::VARIANTS[index % Self::VARIANTS.len()]
}
fn cycled(self, right: bool) -> Self {
let n = Self::VARIANTS.len();
Self::VARIANTS[(self.index() + if right { 1 } else { n - 1 }) % n]
}
}
#[cfg(test)]
mod tests {
use super::Cycle;
use crate::app::i18n::Lang;
use crate::app::match_setup::{GullPressure, MapChoice, RoundLength};
use crate::sim::BotLevel;
fn round_trips<T: Cycle + std::fmt::Debug>() {
for &x in T::VARIANTS {
assert_eq!(x.cycled(true).cycled(false), x, "{x:?}");
}
let mut x = T::VARIANTS[0];
for _ in 0..T::VARIANTS.len() {
x = x.cycled(true);
}
assert_eq!(x, T::VARIANTS[0]);
}
#[test]
fn every_config_enum_cycles_cleanly() {
round_trips::<MapChoice>();
round_trips::<GullPressure>();
round_trips::<RoundLength>();
round_trips::<Lang>();
round_trips::<BotLevel>();
}
}