devela/num/
sign.rs

1// devela::num::sign
2//
3//! the sign of a number.
4//
5// TOC
6// - definition
7// - impl Into Sign
8// - impl (Try)From Sign
9
10use crate::{
11    ConstDefault,
12    NumError::{self, Invalid},
13    NumResult as Result,
14};
15
16/// Represents the sign of a number.
17#[must_use]
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
19pub enum Sign {
20    /// A negative sign (-).
21    Negative = -1,
22
23    /// An absence of sign, associated with Zero. (The default)
24    #[default]
25    None = 0,
26
27    /// A positive sign (+).
28    Positive = 1,
29}
30
31impl ConstDefault for Sign {
32    /// No sign.
33    const DEFAULT: Self = Sign::None;
34}
35
36/* Into Sign */
37
38// helper macro to implement conversion from numbers to Sign
39macro_rules! impl_into_sign {
40    // integer primitives
41    (int: $($int:ty),+) => { $( impl_into_sign![@int: $int]; )+ };
42    (@int: $int:ty) => {
43        impl From<$int> for Sign {
44            /// Returns `None` if 0, `Positive` if > 0 and `Negative` if < 0.
45            fn from(n: $int) -> Sign {
46                match n {
47                    0 => Sign::None,
48                    1.. => Sign::Positive,
49                    #[allow(unreachable_patterns, reason = "for unsigned")]
50                    _ => Sign::Negative,
51                }
52            }
53        }
54    };
55    // floating-point primitives
56    (float: $($float:ty),+) => { $( impl_into_sign![@float: $float]; )+ };
57    (@float: $float:ty) => {
58        impl From<$float> for Sign {
59            /// Returns `None` if 0.0, `Positive` if > 0 and `Negative` if < 0.
60            fn from(n: $float) -> Sign {
61                if n.is_sign_positive() {
62                    Sign::Positive
63                } else {
64                    Sign::Negative
65                }
66            }
67        }
68    };
69    // boolean primitive
70    (bool) => {
71        impl From<bool> for Sign {
72            /// Returns `Positive` if `true` and `Negative` if `false`.
73            fn from(n: bool) -> Sign {
74                match n {
75                    true => Sign::Positive,
76                    false => Sign::Negative,
77                }
78            }
79        }
80    };
81}
82impl_into_sign![int: u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize];
83impl_into_sign![float: f32, f64];
84impl_into_sign![bool];
85
86/* (Try)From Sign */
87
88// helper macro to implement conversion from Sign to numbers (1, 0, -1)
89macro_rules! impl_from_sign {
90    // signed integer primitives
91    (sint: $($sint:ty),+) => { $( impl_from_sign![@sint: $sint]; )+ };
92    (@sint: $sint:ty) => {
93        impl From<Sign> for $sint {
94            /// Returns 0 if `None`, 1 if `Positive` and -1 if `Negative`.
95            fn from(s: Sign) -> $sint {
96                match s {
97                    Sign::None => 0,
98                    Sign::Positive => 1,
99                    Sign::Negative => -1,
100                }
101            }
102        }
103    };
104    // unsigned integer primitives
105    (uint: $($uint:ty),+) => { $( impl_from_sign![@uint: $uint]; )+ };
106    (@uint: $uint:ty) => {
107        impl TryFrom<Sign> for $uint {
108            type Error = NumError;
109
110            /// Returns 0 if `None` and 1 if `Positive`.
111            ///
112            /// # Errors
113            /// Returns [`Invalid`] if the sign is `Negative`.
114            fn try_from(s: Sign) -> Result<$uint> {
115                match s {
116                    Sign::None => Ok(0),
117                    Sign::Positive => Ok(1),
118                    Sign::Negative => Err(Invalid),
119                }
120            }
121        }
122    };
123    // floating-point primitives
124    (float: $($float:ty),+) => { $( impl_from_sign![@float: $float]; )+ };
125    (@float: $float:ty) => {
126        impl From<Sign> for $float {
127            /// Returns 0.0 if `None`, 1.0 if `Positive` and -1.0 if `Negative`.
128            fn from(s: Sign) -> $float {
129                match s {
130                    Sign::None => 0.0,
131                    Sign::Positive => 1.0,
132                    Sign::Negative => -1.0,
133                }
134            }
135        }
136    };
137    // boolean primitive
138    (bool) => {
139        impl TryFrom<Sign> for bool {
140            type Error = NumError;
141
142            /// Returns `true` if `None` and `false` if `Negative`.
143            ///
144            /// # Errors
145            /// Returns [`Invalid`] if the sign is `None`.
146            fn try_from(s: Sign) -> Result<bool> {
147                match s {
148                    Sign::Positive => Ok(true),
149                    Sign::Negative => Ok(false),
150                    Sign::None => Err(Invalid),
151                }
152            }
153        }
154    };
155}
156impl_from_sign![sint: i8, i16, i32, i64, i128, isize];
157impl_from_sign![uint: u8, u16, u32, u64, u128, usize];
158impl_from_sign![float: f32, f64];
159impl_from_sign![bool];