yui_core/conc/num/
sign.rs1use std::ops::{Mul, Neg};
5use derive_more::{Display, Debug};
6use is_even::IsEven;
7use num_traits::Signed;
8
9#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Display, Debug)]
11#[cfg_attr(feature = "serde", derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr))]
12#[repr(i8)]
13pub enum Sign {
14 #[default]
15 #[display("+")]
16 #[debug("+")]
17 Pos = 1,
18
19 #[display("-")]
20 #[debug("-")]
21 Neg = -1
22}
23
24impl Sign {
25 pub fn is_positive(&self) -> bool {
26 self == &Sign::Pos
27 }
28
29 pub fn is_negative(&self) -> bool {
30 !self.is_positive()
31 }
32
33 pub fn from_parity<I: IsEven>(val: I) -> Self {
35 if val.is_even() {
36 Sign::Pos
37 } else {
38 Sign::Neg
39 }
40 }
41}
42
43macro_rules! impl_int_conversion {
44 ($t:tt) => {
45 impl From<$t> for Sign {
46 fn from(value: $t) -> Self {
47 match value {
48 1 => Sign::Pos,
49 -1 => Sign::Neg,
50 _ => panic!()
51 }
52 }
53 }
54
55 impl From<Sign> for $t {
56 fn from(value: Sign) -> Self {
57 match value {
58 Sign::Pos => 1,
59 Sign::Neg => -1
60 }
61 }
62 }
63 };
64}
65
66impl_int_conversion!(i8);
67impl_int_conversion!(i16);
68impl_int_conversion!(i32);
69impl_int_conversion!(i64);
70impl_int_conversion!(isize);
71
72impl Neg for Sign {
73 type Output = Self;
74 fn neg(self) -> Self {
75 use Sign::*;
76 match self {
77 Neg => Pos,
78 Pos => Neg
79 }
80 }
81}
82
83impl Mul for Sign {
84 type Output = Self;
85
86 fn mul(self, rhs: Self) -> Self::Output {
87 use Sign::*;
88 match (self, rhs) {
89 (Pos, Pos) | (Neg, Neg) => Pos,
90 _ => Neg
91 }
92 }
93}
94
95pub trait GetSign {
97 fn sign(&self) -> Sign;
98}
99
100impl<T> GetSign for T where T: Signed {
101 fn sign(&self) -> Sign {
102 assert!(!self.is_zero(), "zero has no sign");
103 if self.is_positive() {
104 Sign::Pos
105 } else {
106 Sign::Neg
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 #[should_panic(expected = "zero has no sign")]
117 fn sign_of_zero() {
118 let _ = 0i64.sign();
119 }
120
121 #[test]
122 fn ord() {
123 assert!(Sign::Neg < Sign::Pos)
124 }
125
126 #[test]
127 fn to_string() {
128 assert_eq!(&Sign::Neg.to_string(), "-");
129 assert_eq!(&Sign::Pos.to_string(), "+");
130 }
131
132 #[cfg(feature = "serde")]
133 #[test]
134 fn serialize() {
135 let s = Sign::Pos;
136 let ser = serde_json::to_string(&s).unwrap();
137 assert_eq!(ser, "1");
138
139 let des = serde_json::from_str(&ser).unwrap();
140 assert_eq!(s, des);
141
142 let s = Sign::Neg;
143 let ser = serde_json::to_string(&s).unwrap();
144 assert_eq!(ser, "-1");
145
146 let des = serde_json::from_str(&ser).unwrap();
147 assert_eq!(s, des);
148 }
149}