1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
38pub enum Sign {
39 Positive = 1,
40 Negative = -1,
41}
42
43pub use Sign::*;
44
45impl Sign {
46 pub fn to_isize(self) -> isize {
47 self.into()
48 }
49 pub fn to_i64(self) -> i64 {
50 self.into()
51 }
52 pub fn to_i32(self) -> i32 {
53 self.into()
54 }
55 pub fn to_i16(self) -> i16 {
56 self.into()
57 }
58 pub fn to_i8(self) -> i16 {
59 self.into()
60 }
61
62 pub fn parity(n: impl Into<i32>) -> Self {
72 if n.into() % 2 == 0 {
73 Positive
74 } else {
75 Negative
76 }
77 }
78}
79
80impl std::ops::Neg for Sign {
81 type Output = Self;
82 fn neg(self) -> Self {
83 match self {
84 Positive => Negative,
85 Negative => Positive,
86 }
87 }
88}
89
90impl<T: std::ops::Neg<Output = T>> std::ops::Mul<T> for Sign {
91 type Output = T;
92 fn mul(self, rhs: T) -> T {
93 match self {
94 Positive => rhs,
95 Negative => -rhs,
96 }
97 }
98}
99
100impl std::str::FromStr for Sign {
101 type Err = ();
102 fn from_str(s: &str) -> Result<Self, Self::Err> {
103 match s {
104 "+" => Ok(Positive),
105 "-" => Ok(Negative),
106 _ => Err(()),
107 }
108 }
109}
110
111impl std::fmt::Display for Sign {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 f.write_str(match self {
114 Positive => "+",
115 Negative => "-",
116 })
117 }
118}
119
120pub trait Signed {
121 fn sign(&self) -> Option<Sign>;
122}
123
124macro_rules! impl_traits_for_int {
125 ($($int_type: ty),*) => {
126 $(
127 impl From<Sign> for $int_type {
128 fn from(sign: Sign) -> $int_type {
129 match sign {
130 Positive => 1,
131 Negative => -1,
132 }
133 }
134 }
135 impl Signed for $int_type {
136 fn sign(&self) -> Option<Sign> {
137 match self.cmp(&0) {
138 std::cmp::Ordering::Equal => None,
139 std::cmp::Ordering::Greater => Some(Positive),
140 std::cmp::Ordering::Less => Some(Negative),
141 }
142 }
143 }
144 )*
145 };
146}
147
148impl_traits_for_int!(isize, i64, i32, i16, i8);
149
150impl From<Sign> for f64 {
151 fn from(sign: Sign) -> f64 {
152 match sign {
153 Positive => 1.0,
154 Negative => -1.0,
155 }
156 }
157}
158impl From<Sign> for f32 {
159 fn from(sign: Sign) -> f32 {
160 match sign {
161 Positive => 1.0,
162 Negative => -1.0,
163 }
164 }
165}
166
167impl Signed for f64 {
168 fn sign(&self) -> Option<Sign> {
169 match self.signum().partial_cmp(&0.0) {
170 Some(std::cmp::Ordering::Greater) => Some(Positive),
171 Some(std::cmp::Ordering::Less) => Some(Negative),
172 _ => None,
173 }
174 }
175}
176impl Signed for f32 {
177 fn sign(&self) -> Option<Sign> {
178 match self.signum().partial_cmp(&0.0) {
179 Some(std::cmp::Ordering::Greater) => Some(Positive),
180 Some(std::cmp::Ordering::Less) => Some(Negative),
181 _ => None,
182 }
183 }
184}
185
186#[cfg(feature = "serde")]
187mod impl_serde {
188 use super::*;
189 impl serde::Serialize for Sign {
190 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
191 serializer.serialize_str(match self {
192 Positive => "+",
193 Negative => "-",
194 })
195 }
196 }
197 struct SignVisitor;
198 impl<'de> serde::de::Visitor<'de> for SignVisitor {
199 type Value = Sign;
200 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
201 f.write_str("\"+\" or \"-\"")
202 }
203 fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
204 match value {
205 "+" => Ok(Positive),
206 "-" => Ok(Negative),
207 _ => Err(E::custom("Sign must be + or -")),
208 }
209 }
210 }
211 impl<'de> serde::Deserialize<'de> for Sign {
212 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
213 deserializer.deserialize_str(SignVisitor)
214 }
215 }
216 #[test]
217 fn test_serde() {
218 assert_eq!(serde_json::to_string(&Positive).unwrap(), "\"+\"");
219 assert_eq!(serde_json::to_string(&Negative).unwrap(), "\"-\"");
220 assert_eq!(Positive, serde_json::from_str("\"+\"").unwrap());
221 assert_eq!(Negative, serde_json::from_str("\"-\"").unwrap());
222 }
223}