#![no_std]
use num_traits::{
int::PrimInt,
ops::wrapping::WrappingNeg,
};
#[derive(Clone)]
pub struct Luby<T: PrimInt + WrappingNeg>(T, T);
impl<T: PrimInt + WrappingNeg> Luby<T> {
pub fn new() -> Luby<T> {
Luby(T::zero(), T::zero())
}
}
impl<T: PrimInt + WrappingNeg> Iterator for Luby<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let (u, v) = (&mut self.0, &mut self.1);
if *u & u.wrapping_neg() == *v {
*u = u.checked_add(&T::one())?;
*v = T::one();
} else {
*v = v.checked_add(v)?;
}
Some(*v)
}
}
#[cfg(test)]
mod tests {
use crate::generic_test;
use core::fmt::Debug;
use num_traits::{
int::PrimInt,
ops::wrapping::WrappingNeg,
};
fn exhaust<T: PrimInt + WrappingNeg>() {
let luby = super::Luby::<u8>::new();
for _ in luby {}
}
generic_test!(exhaust, u8, u16, i8, i16);
fn prefix<T: PrimInt + WrappingNeg + Debug>() {
let luby = super::Luby::<T>::new();
for (i, j) in luby.zip(LUBY_PREFIX) {
assert_eq!(i, T::from(*j).unwrap());
}
}
generic_test!(prefix, u8, u16, u32, u64, i8, i16, i32, i64);
const LUBY_PREFIX: &[u8] = &[1, 1, 2,
1, 1, 2, 4,
1, 1, 2,
1, 1, 2, 4, 8,
1, 1, 2,
1, 1, 2, 4,
1, 1, 2,
1, 1, 2, 4, 8, 16,
1, 1, 2,
1, 1, 2, 4,
1, 1, 2,
1, 1, 2, 4, 8,
1, 1, 2,
1, 1, 2, 4,
1, 1, 2,
1, 1, 2, 4, 8, 16, 32,
1, 1, 2,
1, 1, 2, 4,
1, 1, 2,
1, 1, 2, 4, 8,
1, 1, 2,
1, 1, 2, 4,
1, 1, 2,
1, 1, 2, 4, 8, 16,
1, 1, 2,
1, 1, 2, 4,
1, 1, 2,
1, 1, 2, 4, 8];
}
#[cfg(test)]
#[macro_export]
macro_rules! generic_test {
($f:ident, $($t:ty),+) => {
paste::item! {
$(#[test]
fn [< $f _ $t >]() {
$f::<$t>()
})+
}
};
}