blob: 63a40c668071a28144c7cb854ed88f9ddba303ce [file] [edit]
//! Identity elements for numbers.
use core::num::{Saturating, Wrapping};
use crate::macros::all_the_numbers;
/// Additive identity.
///
/// # Laws
///
/// ```text
/// ∀ a ∈ Self: a + 0 = a
/// ∀ a ∈ Self: 0 + a = a
/// ```
///
/// # Note
///
/// This trait is different from [`num_traits::Zero`], as it doesn't have any supertraits and does
/// not require [`Sized`].
pub trait Zero {
/// Returns the additive identity of `Self`, `0`.
///
/// # Purity
///
/// This function is pure.
fn zero() -> Self;
/// Returns `true` if `self` is equal to the additive identity.
///
/// # Purity
///
/// This function is pure.
fn is_zero(&self) -> bool;
}
macro_rules! impl_zero {
(@int $ty:ty) => {
impl Zero for $ty {
#[inline]
fn zero() -> Self {
0
}
#[inline]
fn is_zero(&self) -> bool {
*self == 0
}
}
};
(@float $ty:ty) => {
impl Zero for $ty {
#[inline]
fn zero() -> Self {
0.0
}
#[inline]
fn is_zero(&self) -> bool {
*self == 0.0
}
}
};
}
all_the_numbers!(@typed impl_zero);
impl<T> Zero for Wrapping<T>
where
T: Zero,
{
#[inline]
fn zero() -> Self {
Self(T::zero())
}
#[inline]
fn is_zero(&self) -> bool {
self.0.is_zero()
}
}
impl<T> Zero for Saturating<T>
where
T: Zero,
{
#[inline]
fn zero() -> Self {
Self(T::zero())
}
#[inline]
fn is_zero(&self) -> bool {
self.0.is_zero()
}
}
#[cfg(feature = "ordered-float-impl")]
impl<T> Zero for ordered_float::OrderedFloat<T>
where
T: Zero,
{
#[inline]
fn zero() -> Self {
Self(T::zero())
}
#[inline]
fn is_zero(&self) -> bool {
self.0.is_zero()
}
}
#[cfg(feature = "ordered-float-impl")]
impl<T> Zero for ordered_float::NotNan<T>
where
T: Copy + Zero,
{
#[inline]
fn zero() -> Self {
// SAFETY: `T::zero()` is always a valid `NotNan<T>`.
unsafe { Self::new_unchecked(T::zero()) }
}
#[inline]
fn is_zero(&self) -> bool {
self.into_inner().is_zero()
}
}
/// Multiplicative identity.
///
/// # Laws
///
/// ```text
/// ∀ a ∈ Self: a * 1 = a
/// ∀ a ∈ Self: 1 * a = a
/// ```
///
/// # Note
///
/// This trait is different from [`num_traits::One`], as it doesn't have any supertraits and does
/// not require [`Sized`].
pub trait One {
/// Returns the multiplicative identity of `Self`, `1`.
///
/// # Purity
///
/// This function is pure.
fn one() -> Self;
/// Returns `true` if `self` is equal to the multiplicative identity.
///
/// # Purity
///
/// This function is pure.
fn is_one(&self) -> bool;
}
macro_rules! impl_one {
(@int $ty:ty) => {
impl One for $ty {
#[inline]
fn one() -> Self {
1
}
#[inline]
fn is_one(&self) -> bool {
*self == 1
}
}
};
(@float $ty:ty) => {
impl One for $ty {
#[inline]
fn one() -> Self {
1.0
}
#[inline]
fn is_one(&self) -> bool {
let difference = *self - 1.0;
// abs isn't available in no_std
difference < Self::EPSILON && difference > -Self::EPSILON
}
}
};
}
all_the_numbers!(@typed impl_one);
impl<T> One for Wrapping<T>
where
T: One,
{
#[inline]
fn one() -> Self {
Self(T::one())
}
#[inline]
fn is_one(&self) -> bool {
self.0.is_one()
}
}
impl<T> One for Saturating<T>
where
T: One,
{
#[inline]
fn one() -> Self {
Self(T::one())
}
#[inline]
fn is_one(&self) -> bool {
self.0.is_one()
}
}
#[cfg(feature = "ordered-float-impl")]
impl<T> One for ordered_float::OrderedFloat<T>
where
T: One,
{
#[inline]
fn one() -> Self {
Self(T::one())
}
#[inline]
fn is_one(&self) -> bool {
self.0.is_one()
}
}
#[cfg(feature = "ordered-float-impl")]
impl<T> One for ordered_float::NotNan<T>
where
T: Copy + One,
{
#[inline]
fn one() -> Self {
// SAFETY: `T::one()` is always a valid `NotNan<T>`.
unsafe { Self::new_unchecked(T::one()) }
}
#[inline]
fn is_one(&self) -> bool {
self.into_inner().is_one()
}
}