1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
//! For mapping integers based on their parity
use num::Integer;
use std::convert::identity;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// Represents a number's parity (whether it is even or odd).
#[allow(missing_docs)]
pub enum Parity {
Even,
Odd,
}
impl Parity {
/// Returns `true` if the parity is [`Even`].
///
/// [`Even`]: Parity::Even
#[must_use]
pub const fn is_even(self) -> bool {
matches!(self, Self::Even)
}
/// Returns `true` if the parity is [`Odd`].
///
/// [`Odd`]: Parity::Odd
#[must_use]
pub const fn is_odd(self) -> bool {
matches!(self, Self::Odd)
}
}
/// Gives access to methods for mapping based on a number's parity.
pub trait ParityMap: Sized {
/// Returns the parity of `&self`
fn parity(&self) -> Parity;
/// Returns `odd(self)` if `self` is odd, else `even(self)`.
#[must_use]
fn parity_map(self, odd: impl FnOnce(Self) -> Self, even: impl FnOnce(Self) -> Self) -> Self {
match self.parity() {
Parity::Even => even(self),
Parity::Odd => odd(self),
}
}
/// Calls a function on the result of `self.parity_map(..)`, returning the result.
#[must_use]
fn parity_map_and_then<F>(
self,
odd: impl FnOnce(Self) -> Self,
even: impl FnOnce(Self) -> Self,
after: impl FnOnce(Self) -> Self,
) -> Self {
after(self.parity_map(odd, even))
}
/// Returns `f(self)` if `self` is even, else `self`.
#[must_use]
fn map_even(self, f: impl FnOnce(Self) -> Self) -> Self {
self.parity_map(identity, f)
}
/// Returns `f(self)` if `self` is odd, else `self`.
#[must_use]
fn map_odd(self, f: impl FnOnce(Self) -> Self) -> Self {
self.parity_map(f, identity)
}
}
impl<T: Integer> ParityMap for T {
fn parity(&self) -> Parity {
if self.is_even() {
Parity::Even
} else {
Parity::Odd
}
}
}