use std::mem::{transmute_copy, size_of};
pub unsafe trait AllVariantsTakeNoParameters : Eq + Copy {}
pub struct EnumIter<T: AllVariantsTakeNoParameters> {
cur : T,
end : T,
done: bool,
}
impl<T: AllVariantsTakeNoParameters> EnumIter<T> {
#[inline]
pub fn new(start: T, end: T) -> EnumIter<T> {
assert!(size_of::<T>() == 1
|| size_of::<T>() == 2
|| size_of::<T>() == 4
|| size_of::<T>() == 8);
EnumIter {
cur: start,
end: end,
done: false,
}
}
}
macro_rules! next {
($ty : ty, $this: expr) => ({
let ret = $this.cur;
let cur: $ty = transmute_copy(&ret);
let next = cur + 1;
let next = transmute_copy(&next);
$this.cur = next;
ret
})
}
impl<T: AllVariantsTakeNoParameters> Iterator for EnumIter<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
if self.done {
None
} else {
let ret = unsafe {
match size_of::<T>() {
1 => next!(u8 , self),
2 => next!(u16, self),
4 => next!(u32, self),
8 => next!(u64, self),
_ => unreachable!()
}
};
self.done = ret == self.end;
Some(ret)
}
}
}
pub fn enum_iter<T: AllVariantsTakeNoParameters>(start: T, end: T) -> EnumIter<T> {
EnumIter::new(start, end)
}
#[cfg(test)]
mod test {
use super::{enum_iter, AllVariantsTakeNoParameters};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Test {
One,
Two,
Three,
}
unsafe impl AllVariantsTakeNoParameters for Test {}
#[test]
fn it_works() {
let mut vals = Vec::new();
let _ = Test::Two;
for x in enum_iter(Test::One, Test::Three) {
vals.push(x);
}
assert_eq!(format!("{:?}", vals), "[One, Two, Three]");
}
}