1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use crate::Error;
15 use core::fmt::{Display, Formatter};
16 use std::fmt::Debug;
17 
18 /// Numerical type
19 ///
20 /// # Examples
21 /// ```
22 /// use ylong_json::Number;
23 ///
24 /// let number: Number = 0.0.into();
25 /// assert_eq!(number.is_float(), true);
26 /// ```
27 #[derive(Clone)]
28 pub enum Number {
29     /// Unsigned integer
30     Unsigned(u64),
31     /// Signed integer
32     Signed(i64),
33     /// Floating point number
34     Float(f64),
35 }
36 
37 impl Number {
38     /// Determines whether the number is an unsigned integer.
39     ///
40     /// # Examples
41     /// ```
42     /// use ylong_json::Number;
43     ///
44     /// let number: Number = 1u8.into();
45     /// assert_eq!(number.is_unsigned(), true);
46     ///
47     /// let number: Number = 1i8.into();
48     /// assert_eq!(number.is_unsigned(), false);
49     /// ```
is_unsigned(&self) -> bool50     pub fn is_unsigned(&self) -> bool {
51         matches!(*self, Self::Unsigned(_))
52     }
53 
54     /// Determines whether the number is a signed integer.
55     ///
56     /// # Examples
57     /// ```
58     /// use ylong_json::Number;
59     ///
60     /// let number: Number = 1i8.into();
61     /// assert_eq!(number.is_signed(), true);
62     ///
63     /// let number: Number = 1u8.into();
64     /// assert_eq!(number.is_signed(), false);
65     /// ```
is_signed(&self) -> bool66     pub fn is_signed(&self) -> bool {
67         matches!(*self, Self::Signed(_))
68     }
69 
70     /// Determines whether the number is a floating point number.
71     ///
72     /// # Examples
73     /// ```
74     /// use ylong_json::Number;
75     ///
76     /// let number: Number = 0.0.into();
77     /// assert_eq!(number.is_float(), true);
78     ///
79     /// let number: Number = 1i8.into();
80     /// assert_eq!(number.is_float(), false);
81     /// ```
is_float(&self) -> bool82     pub fn is_float(&self) -> bool {
83         matches!(*self, Self::Float(_))
84     }
85 
86     /// Trys converting the number to u64. If conversion fails, returns Error.
87     ///
88     /// Only Unsigned case means success, other cases return Error.
89     ///
90     /// # Examples
91     /// ```
92     /// use ylong_json::Number;
93     ///
94     /// let number: Number = 1u8.into();
95     /// assert_eq!(number.try_as_u64().unwrap(), 1u64);
96     ///
97     /// let number: Number = 1i8.into();
98     /// assert_eq!(number.try_as_u64().is_err(), true);
99     /// ```
try_as_u64(&self) -> Result<u64, Error>100     pub fn try_as_u64(&self) -> Result<u64, Error> {
101         match self {
102             Self::Unsigned(u) => Ok(*u),
103             _ => Err(Error::TypeTransform),
104         }
105     }
106 
107     /// Trys converting the number to i64. If conversion fails, returns Error.
108     ///
109     /// Only in 164 range unsigned numbers can be converted. Signed numbers can be converted.
110     /// Otherwise, returns Error.
111     ///
112     /// # Examples
113     /// ```
114     /// use ylong_json::Number;
115     ///
116     /// let number: Number = 1i8.into();
117     /// assert_eq!(number.try_as_i64().unwrap(), 1i64);
118     ///
119     /// let number: Number = u64::MAX.into();
120     /// assert_eq!(number.try_as_i64().is_err(), true);
121     /// ```
try_as_i64(&self) -> Result<i64, Error>122     pub fn try_as_i64(&self) -> Result<i64, Error> {
123         match self {
124             Self::Unsigned(u) => {
125                 if *u <= i64::MAX as u64 {
126                     Ok(*u as i64)
127                 } else {
128                     Err(Error::TypeTransform)
129                 }
130             }
131             Self::Signed(i) => Ok(*i),
132             Self::Float(_) => Err(Error::TypeTransform),
133         }
134     }
135 
136     /// Trys converting the number to f64. If conversion fails, returns Error.
137     ///
138     /// All types can be converted to f64.
139     ///
140     /// # Examples
141     /// ```
142     /// use ylong_json::Number;
143     ///
144     /// let number: Number = 0.0.into();
145     /// assert_eq!(number.try_as_f64().unwrap(), 0.0f64);
146     /// ```
try_as_f64(&self) -> Result<f64, Error>147     pub fn try_as_f64(&self) -> Result<f64, Error> {
148         match self {
149             Self::Unsigned(u) => Ok(*u as f64),
150             Self::Signed(i) => Ok(*i as f64),
151             Self::Float(f) => Ok(*f),
152         }
153     }
154 }
155 
156 impl PartialEq for Number {
eq(&self, other: &Self) -> bool157     fn eq(&self, other: &Self) -> bool {
158         let a = self.try_as_f64().unwrap();
159         let b = other.try_as_f64().unwrap();
160         a == b
161     }
162 }
163 
164 impl Display for Number {
fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result165     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
166         match self {
167             Number::Unsigned(x) => write!(f, "{x}"),
168             Number::Signed(x) => write!(f, "{x}"),
169             Number::Float(x) => write!(f, "{x:?}"),
170         }
171     }
172 }
173 
174 impl Debug for Number {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result175     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
176         Display::fmt(self, f)
177     }
178 }
179 
180 macro_rules! number_from_unsigned {
181     ($($u: tt),* $(,)?) => {
182         $(
183             impl From<$u> for Number {
184                 fn from(u: $u) -> Self {
185                     Self::Unsigned(u as u64)
186                 }
187             }
188         )*
189     }
190 }
191 
192 macro_rules! number_from_signed {
193     ($($i: tt),* $(,)?) => {
194         $(
195             impl From<$i> for Number {
196                 fn from(i: $i) -> Self {
197                     Self::Signed(i as i64)
198                 }
199             }
200         )*
201     }
202 }
203 
204 macro_rules! number_from_float {
205     ($($f: tt),* $(,)?) => {
206         $(
207             impl From<$f> for Number {
208                 fn from(f: $f) -> Self {
209                     Self::Float(f as f64)
210                 }
211             }
212         )*
213     }
214 }
215 
216 number_from_unsigned!(u8, u16, u32, u64, usize);
217 number_from_signed!(i8, i16, i32, i64, isize);
218 number_from_float!(f32, f64);
219 
220 #[cfg(test)]
221 mod ut_number {
222     use crate::Number;
223 
224     /// UT test for `Number::fmt`.
225     ///
226     /// # Title
227     /// ut_number_fmt
228     ///
229     /// # Brief
230     /// 1. Creates some `Number`s.
231     /// 2. Calls `Number::fmt`.
232     /// 3. Checks if the test results are correct.
233     #[test]
ut_number_fmt()234     fn ut_number_fmt() {
235         assert_eq!(format!("{}", Number::Unsigned(1)), "1");
236         assert_eq!(format!("{:?}", Number::Unsigned(1)), "1");
237 
238         assert_eq!(format!("{}", Number::Signed(1)), "1");
239         assert_eq!(format!("{:?}", Number::Signed(1)), "1");
240 
241         assert_eq!(format!("{}", Number::Float(1.0)), "1.0");
242         assert_eq!(format!("{:?}", Number::Float(1.0)), "1.0");
243     }
244 
245     /// UT test for `Number::clone`.
246     ///
247     /// # Title
248     /// ut_number_clone
249     ///
250     /// # Brief
251     /// 1. Creates some `Number`s.
252     /// 2. Calls `Number::clone`.
253     /// 3. Checks if the test results are correct.
254     #[test]
ut_number_clone()255     fn ut_number_clone() {
256         let number1 = Number::Unsigned(1);
257         assert_eq!(number1, number1.clone());
258 
259         let number1 = Number::Signed(1);
260         assert_eq!(number1, number1.clone());
261 
262         let number1 = Number::Float(1.0);
263         assert_eq!(number1, number1.clone());
264     }
265 
266     /// UT test for `Number::is_unsigned`.
267     ///
268     /// # Title
269     /// ut_number_is_unsigned
270     ///
271     /// # Brief
272     /// 1. Creates some `Number`s.
273     /// 2. Calls `Number::is_unsigned`.
274     /// 3. Checks if the test results are correct.
275     #[test]
ut_number_is_unsigned()276     fn ut_number_is_unsigned() {
277         assert!(Number::Unsigned(1).is_unsigned());
278         assert!(!Number::Signed(1).is_unsigned());
279         assert!(!Number::Float(1.0).is_unsigned());
280     }
281 
282     /// UT test for `Number::is_signed`.
283     ///
284     /// # Title
285     /// ut_number_is_signed
286     ///
287     /// # Brief
288     /// 1. Creates some `Number`s.
289     /// 2. Calls `Number::is_signed`.
290     /// 3. Checks if the test results are correct.
291     #[test]
ut_number_is_signed()292     fn ut_number_is_signed() {
293         assert!(!Number::Unsigned(1).is_signed());
294         assert!(Number::Signed(1).is_signed());
295         assert!(!Number::Float(1.0).is_signed());
296     }
297 
298     /// UT test for `Number::is_float`.
299     ///
300     /// # Title
301     /// ut_number_is_float
302     ///
303     /// # Brief
304     /// 1. Creates some `Number`s.
305     /// 2. Calls `Number::is_float`.
306     /// 3. Checks if the test results are correct.
307     #[test]
ut_number_is_float()308     fn ut_number_is_float() {
309         assert!(!Number::Unsigned(1).is_float());
310         assert!(!Number::Signed(1).is_float());
311         assert!(Number::Float(1.0).is_float());
312     }
313 
314     /// UT test for `Number::try_as_u64`.
315     ///
316     /// # Title
317     /// ut_number_try_as_u64
318     ///
319     /// # Brief
320     /// 1. Creates some `Number`s.
321     /// 2. Calls `Number::try_as_u64`.
322     /// 3. Checks if the test results are correct.
323     #[test]
ut_number_try_as_u64()324     fn ut_number_try_as_u64() {
325         assert!(Number::Unsigned(1).try_as_u64().is_ok());
326         assert!(Number::Signed(1).try_as_u64().is_err());
327         assert!(Number::Float(1.0).try_as_u64().is_err());
328     }
329 
330     /// UT test for `Number::try_as_i64`.
331     ///
332     /// # Title
333     /// ut_number_try_as_i64
334     ///
335     /// # Brief
336     /// 1. Creates some `Number`s.
337     /// 2. Calls `Number::try_as_i64`.
338     /// 3. Checks if the test results are correct.
339     #[test]
ut_number_try_as_i64()340     fn ut_number_try_as_i64() {
341         assert!(Number::Unsigned(1).try_as_i64().is_ok());
342         assert!(Number::Unsigned(u64::MAX).try_as_i64().is_err());
343         assert!(Number::Signed(1).try_as_i64().is_ok());
344         assert!(Number::Float(1.0).try_as_i64().is_err());
345     }
346 }
347