use std::iter::Peekable;
use strum::IntoEnumIterator;
use crate::error::Result;
pub struct EnumCycle<T: IntoEnumIterator> {
inner: Peekable<Box<dyn Iterator<Item = T>>>,
}
impl<T: IntoEnumIterator + Clone + 'static> EnumCycle<T> {
pub fn new() -> Result<EnumCycle<T>> {
let all = T::iter().collect::<Vec<T>>();
if all.is_empty() {
bail!("enum to cycle must contain at least one variant!");
}
Ok(EnumCycle {
inner: (Box::new(all.into_iter().cycle()) as Box<dyn Iterator<Item = T>>).peekable(),
})
}
pub fn current(&mut self) -> &T {
self.inner.peek().unwrap()
}
pub fn next(&mut self) -> T {
self.inner.next().unwrap()
}
}
impl<T: IntoEnumIterator + PartialEq + Clone + 'static> EnumCycle<T> {
pub fn new_at(start: T) -> Result<EnumCycle<T>> {
let mut me = Self::new()?;
while *me.current() != start {
me.next();
}
Ok(me)
}
}
impl<T: IntoEnumIterator + PartialEq + Default + Clone + 'static> EnumCycle<T> {
pub fn new_at_default() -> Result<EnumCycle<T>> {
let start = T::default();
let mut me = Self::new()?;
while *me.current() != start {
me.next();
}
Ok(me)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_iterator() {
#[derive(Debug, Clone, strum::EnumIter)]
enum Empty {}
match EnumCycle::<Empty>::new() {
Ok(_) => panic!("should not be Ok"),
Err(e) => assert_eq!(
e.to_string(),
"enum to cycle must contain at least one variant!"
),
}
}
}