use crate::Enumerable;
macro_rules! impl_enumerable_for_numeric_type {
($ty:ty) => {
#[automatically_derived]
impl Enumerable for $ty {
type Enumerator = core::ops::RangeInclusive<$ty>;
fn enumerator() -> Self::Enumerator {
<$ty>::MIN..=<$ty>::MAX
}
const ENUMERABLE_SIZE_OPTION: Option<usize> = {
if core::mem::size_of::<$ty>() < core::mem::size_of::<usize>() {
match (<$ty>::MAX.abs_diff(<$ty>::MIN) as usize).checked_add(1) {
Some(size) => Some(size),
None => {
unreachable!()
}
}
} else {
None
}
};
}
};
}
macro_rules! impl_enumerable_for_numeric_types {
($ty:ty) => { impl_enumerable_for_numeric_type!($ty); };
($ty:ty, $($tys:ty),+) => {
impl_enumerable_for_numeric_type!($ty);
impl_enumerable_for_numeric_types!($($tys),+);
};
}
impl_enumerable_for_numeric_types!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl Enumerable for bool {
type Enumerator = core::iter::Copied<core::slice::Iter<'static, bool>>;
fn enumerator() -> Self::Enumerator {
const ALL_VARIANTS: &[bool; 2] = &[false, true];
ALL_VARIANTS.iter().copied()
}
const ENUMERABLE_SIZE_OPTION: Option<usize> = Some(2);
}
impl Enumerable for char {
type Enumerator =
core::iter::Chain<core::ops::RangeInclusive<char>, core::ops::RangeInclusive<char>>;
fn enumerator() -> Self::Enumerator {
('\u{0}'..='\u{D7FF}').chain('\u{E000}'..='\u{10FFFF}')
}
const ENUMERABLE_SIZE_OPTION: Option<usize> = Some((0xD7FF + 1) + (0x10FFFF - 0xE000 + 1));
}
pub struct OptionEnumerator<T: Enumerable> {
first: bool,
inner: <T as Enumerable>::Enumerator,
}
impl<T> OptionEnumerator<T>
where
T: Enumerable,
{
pub(crate) fn new() -> Self {
Self {
first: true,
inner: T::enumerator(),
}
}
}
impl<T> Iterator for OptionEnumerator<T>
where
T: Enumerable,
{
type Item = Option<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.first {
self.first = false;
Some(None)
} else {
self.inner.next().map(Some)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.inner.size_hint();
if self.first {
(
lower.saturating_add(1),
upper.and_then(|u| u.checked_add(1)),
)
} else {
(lower, upper)
}
}
}
impl<T> Enumerable for Option<T>
where
T: Enumerable,
{
type Enumerator = OptionEnumerator<T>;
fn enumerator() -> Self::Enumerator {
OptionEnumerator::new()
}
const ENUMERABLE_SIZE_OPTION: Option<usize> = {
match <T as Enumerable>::ENUMERABLE_SIZE_OPTION {
Some(size) => size.checked_add(1),
None => None,
}
};
}
impl<T, E> Enumerable for Result<T, E>
where
T: Enumerable,
E: Enumerable,
{
type Enumerator = core::iter::Chain<
core::iter::Map<<T as Enumerable>::Enumerator, fn(T) -> Result<T, E>>,
core::iter::Map<<E as Enumerable>::Enumerator, fn(E) -> Result<T, E>>,
>;
fn enumerator() -> Self::Enumerator {
let t: fn(T) -> Result<T, E> = Ok;
let e: fn(E) -> Result<T, E> = Err;
<T as Enumerable>::enumerator()
.map(t)
.chain(<E as Enumerable>::enumerator().map(e))
}
const ENUMERABLE_SIZE_OPTION: Option<usize> = {
match (
<T as Enumerable>::ENUMERABLE_SIZE_OPTION,
<E as Enumerable>::ENUMERABLE_SIZE_OPTION,
) {
(Some(t), Some(e)) => t.checked_add(e),
_ => None,
}
};
}