macro_rules! adjacent_int_impls {
( $( $t:ty ),+ $(,)? ) => {
$(
impl Adjacent for $t {
#[inline]
fn successor(&self) -> Option<Self> {
self.checked_add(1)
}
#[inline]
fn predecessor(&self) -> Option<Self> {
self.checked_sub(1)
}
}
)+
};
}
macro_rules! step_int_impls {
{
narrower than or same width as usize:
$( [ $u_narrower:ident $i_narrower:ident ] ),+;
wider than usize:
$( [ $u_wider:ident $i_wider:ident ] ),+;
} => {
$(
impl Step for $u_narrower {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
if *start <= *end {
#[allow(trivial_numeric_casts, reason = "macro is used for many integer types including usize")]
Some((*end - *start) as usize)
} else {
None
}
}
}
impl Step for $i_narrower {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
if *start <= *end {
#[allow(trivial_numeric_casts, reason = "macro is used for many integer types including isize")]
Some((*end as isize).wrapping_sub(*start as isize) as usize)
} else {
None
}
}
}
)+
$(
impl Step for $u_wider {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
if *start <= *end {
usize::try_from(*end - *start).ok()
} else {
None
}
}
}
impl Step for $i_wider {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
if *start <= *end {
usize::try_from(end.checked_sub(*start)?).ok()
} else {
None
}
}
}
)+
};
}
pub trait Adjacent: Sized {
fn predecessor(&self) -> Option<Self>;
fn successor(&self) -> Option<Self>;
}
pub trait Step: Sized {
fn steps_between(start: &Self, end: &Self) -> Option<usize>;
}
impl Adjacent for f32 {
#[inline]
fn predecessor(&self) -> Option<Self> {
debug_assert!(!self.is_nan(), "NaN has no predecessor");
let prev = self.next_down();
(prev != Self::NEG_INFINITY).then_some(prev)
}
#[inline]
fn successor(&self) -> Option<Self> {
debug_assert!(!self.is_nan(), "NaN has no successor");
let next = self.next_up();
(next != Self::INFINITY).then_some(next)
}
}
impl Adjacent for f64 {
#[inline]
fn predecessor(&self) -> Option<Self> {
debug_assert!(!self.is_nan(), "NaN has no predecessor");
let prev = self.next_down();
(prev != Self::NEG_INFINITY).then_some(prev)
}
#[inline]
fn successor(&self) -> Option<Self> {
debug_assert!(!self.is_nan(), "NaN has no successor");
let next = self.next_up();
(next != Self::INFINITY).then_some(next)
}
}
adjacent_int_impls!(
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize
);
#[cfg(target_pointer_width = "64")]
step_int_impls! {
narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize];
wider than usize: [u128 i128];
}
#[cfg(target_pointer_width = "32")]
step_int_impls! {
narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [usize isize];
wider than usize: [u64 i64], [u128 i128];
}
#[cfg(target_pointer_width = "16")]
step_int_impls! {
narrower than or same width as usize: [u8 i8], [u16 i16], [usize isize];
wider than usize: [u32 i32], [u64 i64], [u128 i128];
}