use crate::Iterstats;
pub trait Range<A = Self>: Sized {
type Output;
fn range<I: Iterator<Item = A>>(iter: I) -> Option<(Self::Output, Self::Output)>;
}
macro_rules! range_impl {
($typ:ty) => {
impl Range for $typ {
type Output = $typ;
fn range<I: Iterator<Item = Self>>(iter: I) -> Option<(Self::Output, Self::Output)> {
let mut range = None;
for item in iter {
if let Some((min, max)) = &mut range {
if item < *min {
*min = item;
}
if item > *max {
*max = item;
}
} else {
range = Some((item, item));
}
}
range
}
}
impl Range for &$typ {
type Output = $typ;
fn range<I: Iterator<Item = Self>>(iter: I) -> Option<(Self::Output, Self::Output)> {
iter.map(|i| *i).range()
}
}
};
}
range_impl!(f64);
range_impl!(f32);
range_impl!(u128);
range_impl!(u64);
range_impl!(u32);
range_impl!(u16);
range_impl!(u8);
range_impl!(usize);
range_impl!(i128);
range_impl!(i64);
range_impl!(i32);
range_impl!(i16);
range_impl!(i8);
range_impl!(isize);
#[cfg(test)]
mod tests {
use super::*;
use paste::paste;
macro_rules! test_range {
($name:ident: $typ:ty as $iter:expr ; iter => None) => {
paste! {
#[test]
fn [<$name _iter>]() {
let range = <&$typ>::range($iter.iter());
assert!(range.is_none())
}
}
};
($name:ident: $typ:ty as $iter:expr ; into_iter => None) => {
paste! {
#[test]
fn [<$name _into_iter>]() {
let range = $typ::range($iter.into_iter());
assert!(range.is_none())
}
}
};
($name:ident: $typ:ty as $iter:expr => None) => {
test_range!($name: $typ as $iter; iter => None);
test_range!($name: $typ as $iter; into_iter => None);
};
($name:ident: $typ:ty as $iter:expr ; iter => ($min:expr, $max:expr)) => {
paste! {
#[test]
fn [<$name _iter>]() {
let (min, max) = <&$typ>::range($iter.iter()).unwrap();
assert_eq!(min, $min);
assert_eq!(max, $max)
}
}
};
($name:ident: $typ:ty as $iter:expr ; into_iter => ($min:expr, $max:expr)) => {
paste! {
#[test]
fn [<$name _into_iter>]() {
let (min, max) = $typ::range($iter.into_iter()).unwrap();
assert_eq!(min, $min);
assert_eq!(max, $max)
}
}
};
($name:ident: $typ:ty as $iter:expr => ($min:expr, $max:expr)) => {
test_range!($name: $typ as $iter; iter => ($min, $max));
test_range!($name: $typ as $iter; into_iter => ($min, $max));
};
}
test_range!(empty: u32 as Vec::new() => None);
test_range!(f64: f64 as [0.1, -32.1, 23.2, 0., f64::NAN] => (-32.1, 23.2));
test_range!(f64_with_inf: f64 as [0.1, f64::NEG_INFINITY, -32.1, 23.2, f64::INFINITY, 0., f64::NAN] => (f64::NEG_INFINITY, f64::INFINITY));
test_range!(f32: f32 as [0.1, -32.1, 23.2, 0., f32::NAN] => (-32.1, 23.2));
test_range!(f32_with_inf: f32 as [0.1, f32::NEG_INFINITY, -32.1, 23.2, f32::INFINITY, 0., f32::NAN] => (f32::NEG_INFINITY, f32::INFINITY));
test_range!(u128: u128 as [1, 32, 23, 0] => (0, 32));
test_range!(u64: u64 as [1, 32, 23, 0] => (0, 32));
test_range!(u32: u32 as [1, 32, 23, 0] => (0, 32));
test_range!(u16: u16 as [1, 32, 23, 0] => (0, 32));
test_range!(u8: u8 as [1, 32, 23, 0] => (0, 32));
test_range!(usize: usize as [1, 32, 23, 0] => (0, 32));
test_range!(i128: i128 as [-4, -34, -1, -3] => (-34, -1));
test_range!(i64: i64 as [-4, -34, -1, -3] => (-34, -1));
test_range!(i32: i32 as [-4, -34, -1, -3] => (-34, -1));
test_range!(i16: i16 as [-4, -34, -1, -3] => (-34, -1));
test_range!(i8: i8 as [-4, -34, -1, -3] => (-34, -1));
test_range!(isize: isize as [-4, -34, -1, -3] => (-34, -1));
}