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