#![allow(deprecated)]
#[allow(unused_imports)]
use crate::internal_prelude::*;
use core::ops::{Div, DivAssign, Mul, MulAssign, Neg, Not};
use Sign::{Negative, Positive, Zero};
#[repr(i8)]
#[cfg_attr(serde, derive(serde::Serialize))]
#[cfg_attr(serde, serde(into = "crate::serde::Sign"))]
#[deprecated(
since = "0.2.7",
note = "The only use for this (obtaining the sign of a `Duration`) can be replaced with \
`Duration::is_{positive|negative|zero}`"
)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Sign {
Positive = 1,
Negative = -1,
Zero = 0,
}
#[cfg(serde)]
impl<'a> serde::Deserialize<'a> for Sign {
#[inline(always)]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
crate::serde::Sign::deserialize(deserializer)?
.try_into()
.map_err(serde::de::Error::custom)
}
}
impl Default for Sign {
#[inline(always)]
fn default() -> Self {
Zero
}
}
macro_rules! sign_mul {
($($type:ty),+ $(,)?) => {
$(
impl Mul<$type> for Sign {
type Output = $type;
#[allow(trivial_numeric_casts)]
#[inline(always)]
fn mul(self, rhs: $type) -> Self::Output {
(self as i8) as $type * rhs
}
}
impl Mul<Sign> for $type {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: Sign) -> Self::Output {
rhs * self
}
}
impl MulAssign<Sign> for $type {
#[inline(always)]
fn mul_assign(&mut self, rhs: Sign) {
if rhs.is_negative() {
*self = -*self;
}
}
}
impl Div<Sign> for $type {
type Output = Self;
#[inline(always)]
fn div(self, rhs: Sign) -> Self::Output {
self * rhs
}
}
impl DivAssign<Sign> for $type {
#[inline(always)]
fn div_assign(&mut self, rhs: Sign) {
*self *= rhs
}
}
)*
};
}
sign_mul![i8, i16, i32, i64, i128, f32, f64];
impl Mul<Sign> for Sign {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Zero, _) | (_, Zero) => Zero,
(Positive, Positive) | (Negative, Negative) => Positive,
(Positive, Negative) | (Negative, Positive) => Negative,
}
}
}
impl MulAssign<Sign> for Sign {
#[inline(always)]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl Div<Sign> for Sign {
type Output = Self;
#[inline(always)]
fn div(self, rhs: Self) -> Self::Output {
self * rhs
}
}
impl DivAssign<Sign> for Sign {
#[inline(always)]
fn div_assign(&mut self, rhs: Self) {
*self *= rhs
}
}
impl Neg for Sign {
type Output = Self;
#[inline(always)]
fn neg(self) -> Self::Output {
self.negate()
}
}
impl Not for Sign {
type Output = Self;
#[inline(always)]
fn not(self) -> Self::Output {
self.negate()
}
}
impl Sign {
#[inline(always)]
pub fn negate(self) -> Self {
match self {
Positive => Negative,
Negative => Positive,
Zero => Zero,
}
}
#[inline(always)]
pub const fn is_positive(self) -> bool {
self as u8 == Positive as u8
}
#[inline(always)]
pub const fn is_negative(self) -> bool {
self as u8 == Negative as u8
}
#[inline(always)]
pub const fn is_zero(self) -> bool {
self as u8 == Zero as u8
}
}
#[cfg(test)]
mod test {
use super::*;
macro_rules! op_assign {
($a:ident $op:tt $b:ident) => {{
let mut v = $a;
v $op $b;
v
}};
}
#[test]
fn default() {
assert_eq!(Sign::default(), Zero);
}
#[test]
fn sign_mul_int() {
assert_eq!(Positive * 2, 2);
assert_eq!(Negative * 2, -2);
assert_eq!(Zero * 2, 0);
}
#[test]
#[allow(clippy::float_cmp)]
fn sign_mul_float() {
assert_eq!(Positive * 2., 2.);
assert_eq!(Negative * 2., -2.);
assert_eq!(Zero * 2., 0.);
}
#[test]
fn sign_mul_sign() {
assert_eq!(Zero * Positive, Zero);
assert_eq!(Zero * Negative, Zero);
assert_eq!(Zero * Zero, Zero);
assert_eq!(Positive * Zero, Zero);
assert_eq!(Negative * Zero, Zero);
assert_eq!(Positive * Positive, Positive);
assert_eq!(Positive * Negative, Negative);
assert_eq!(Negative * Positive, Negative);
assert_eq!(Negative * Negative, Positive);
}
#[test]
fn sign_mul_assign_sign() {
assert_eq!(op_assign!(Zero *= Positive), Zero);
assert_eq!(op_assign!(Zero *= Negative), Zero);
assert_eq!(op_assign!(Zero *= Zero), Zero);
assert_eq!(op_assign!(Positive *= Zero), Zero);
assert_eq!(op_assign!(Negative *= Zero), Zero);
assert_eq!(op_assign!(Positive *= Positive), Positive);
assert_eq!(op_assign!(Positive *= Negative), Negative);
assert_eq!(op_assign!(Negative *= Positive), Negative);
assert_eq!(op_assign!(Negative *= Negative), Positive);
}
#[test]
#[allow(clippy::eq_op)]
fn sign_div_sign() {
assert_eq!(Zero / Positive, Zero);
assert_eq!(Zero / Negative, Zero);
assert_eq!(Zero / Zero, Zero);
assert_eq!(Positive / Zero, Zero);
assert_eq!(Negative / Zero, Zero);
assert_eq!(Positive / Positive, Positive);
assert_eq!(Positive / Negative, Negative);
assert_eq!(Negative / Positive, Negative);
assert_eq!(Negative / Negative, Positive);
}
#[test]
fn sign_div_assign_sign() {
assert_eq!(op_assign!(Zero /= Positive), Zero);
assert_eq!(op_assign!(Zero /= Negative), Zero);
assert_eq!(op_assign!(Zero /= Zero), Zero);
assert_eq!(op_assign!(Positive /= Zero), Zero);
assert_eq!(op_assign!(Negative /= Zero), Zero);
assert_eq!(op_assign!(Positive /= Positive), Positive);
assert_eq!(op_assign!(Positive /= Negative), Negative);
assert_eq!(op_assign!(Negative /= Positive), Negative);
assert_eq!(op_assign!(Negative /= Negative), Positive);
}
#[test]
fn neg() {
assert_eq!(-Positive, Negative);
assert_eq!(-Negative, Positive);
assert_eq!(-Zero, Zero);
}
#[test]
fn not() {
assert_eq!(!Positive, Negative);
assert_eq!(!Negative, Positive);
assert_eq!(!Zero, Zero);
}
#[test]
fn negate() {
assert_eq!(Positive.negate(), Negative);
assert_eq!(Negative.negate(), Positive);
assert_eq!(Zero.negate(), Zero);
}
#[test]
fn is_positive() {
assert!(Positive.is_positive());
assert!(!Negative.is_positive());
assert!(!Zero.is_positive());
}
#[test]
fn is_negative() {
assert!(!Positive.is_negative());
assert!(Negative.is_negative());
assert!(!Zero.is_negative());
}
#[test]
fn is_zero() {
assert!(!Positive.is_zero());
assert!(!Negative.is_zero());
assert!(Zero.is_zero());
}
}