1use std::fmt;
2use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
3use std::str::FromStr;
4use serde::{Serialize, Serializer, Deserialize, Deserializer};
5use std::cmp::Ordering;
6
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub enum Suffix {
9 Giga, Mega, Kilo, None, Milli, Micro, Nano, Pico, }
18
19#[derive(Debug, Clone, Copy, PartialEq)]
20pub struct Number {
21 pub value: f64,
22 pub suffix: Suffix,
23}
24
25impl Suffix {
26 pub const fn factor(&self) -> f64 {
27 match self {
28 Suffix::Giga => 1e9,
29 Suffix::Mega => 1e6,
30 Suffix::Kilo => 1e3,
31 Suffix::None => 1.0,
32 Suffix::Milli => 1e-3,
33 Suffix::Micro => 1e-6,
34 Suffix::Nano => 1e-9,
35 Suffix::Pico => 1e-12,
36 }
37 }
38
39 pub const fn name(&self) -> &'static str {
40 match self {
41 Suffix::Giga => "G",
42 Suffix::Mega => "M",
43 Suffix::Kilo => "K",
44 Suffix::None => "",
45 Suffix::Milli => "m",
46 Suffix::Micro => "u",
47 Suffix::Nano => "n",
48 Suffix::Pico => "p",
49 }
50 }
51}
52
53impl FromStr for Suffix {
54 type Err = ();
55
56 fn from_str(s: &str) -> Result<Self, Self::Err> {
57 match s {
58 "G" => Ok(Suffix::Giga),
59 "M" => Ok(Suffix::Mega),
60 "K" => Ok(Suffix::Kilo),
61 "" => Ok(Suffix::None),
62 "m" => Ok(Suffix::Milli),
63 "u" => Ok(Suffix::Micro),
64 "n" => Ok(Suffix::Nano),
65 "p" => Ok(Suffix::Pico),
66 _ => Err(())
67 }
68 }
69}
70
71const PREFIX_VALUE_TABLE: [(Suffix, f64); 8] = [
72 (Suffix::Giga, 1e9),
73 (Suffix::Mega, 1e6),
74 (Suffix::Kilo, 1e3),
75 (Suffix::None, 1.0),
76 (Suffix::Milli, 1e-3),
77 (Suffix::Micro, 1e-6),
78 (Suffix::Nano, 1e-9),
79 (Suffix::Pico, 1e-12),
80];
81
82const PREFIX_TABLE: [(Suffix, &'static str); 8] = [
83 (Suffix::Giga, "G"),
84 (Suffix::Mega, "M"),
85 (Suffix::Kilo, "K"),
86 (Suffix::Kilo, "k"),
87 (Suffix::Milli, "m"),
88 (Suffix::Micro, "u"),
89 (Suffix::Nano, "n"),
90 (Suffix::Pico, "p"),
91];
92
93impl Number {
94 pub const fn new(value: f64, suffix: Suffix) -> Self {
95 Number { value, suffix }
96 }
97
98 pub const fn to_f64(&self) -> f64 {
99 self.value * self.suffix.factor()
100 }
101
102 pub fn from_f64<F: Into<f64>>(val: F) -> Self {
103 let val = val.into();
104 let abs = val.abs();
105 for (suffix, factor) in PREFIX_VALUE_TABLE.iter() {
106 if abs >= *factor {
107 return Number::new(val / factor, *suffix);
108 }
109 }
110
111 Number::new(val, Suffix::None)
112 }
113
114 pub fn zero() -> Self {
115 Self::new(0.0, Suffix::None)
116 }
117
118 pub fn is_zero(&self) -> bool {
119 self.value == 0.
120 }
121
122 pub fn is_nan(self) -> bool {
123 self.value.is_nan()
124 }
125
126 pub fn is_finite(self) -> bool {
127 self.value.is_finite()
128 }
129
130 pub fn powf(self, exp: f64) -> Self {
131 Self::new(self.value.powf(exp), self.suffix)
132 }
133
134 pub fn atan2(self, other: Number) -> Self {
135 Self::new(self.to_f64().atan2(other.to_f64()), self.suffix)
136 }
137}
138
139macro_rules! impl_f64_like_method {
140 ($f:ident) => {
141 #[inline]
142 pub fn $f(&self) -> Self {
143 Self::new(self.value.$f(), self.suffix)
144 }
145 };
146}
147
148impl Number {
149 impl_f64_like_method!(abs);
150 impl_f64_like_method!(ceil);
151 impl_f64_like_method!(floor);
152 impl_f64_like_method!(round);
153 impl_f64_like_method!(trunc);
154 impl_f64_like_method!(fract);
155
156 impl_f64_like_method!(sqrt);
157 impl_f64_like_method!(exp);
158 impl_f64_like_method!(ln);
159 impl_f64_like_method!(log10);
160 impl_f64_like_method!(log2);
161 impl_f64_like_method!(recip);
162
163 impl_f64_like_method!(sin);
164 impl_f64_like_method!(cos);
165 impl_f64_like_method!(tan);
166 impl_f64_like_method!(asin);
167 impl_f64_like_method!(acos);
168 impl_f64_like_method!(atan);
169
170 impl_f64_like_method!(sinh);
171 impl_f64_like_method!(cosh);
172 impl_f64_like_method!(tanh);
173
174 impl_f64_like_method!(to_degrees);
175 impl_f64_like_method!(to_radians);
176}
177
178impl fmt::Display for Number {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 if let Some(p) = f.precision() {
181 write!(f, "{:.*}{}", p, self.value, self.suffix.name())
182 } else {
183 write!(f, "{}{}", self.value, self.suffix.name())
184 }
185 }
186}
187
188impl FromStr for Number {
189 type Err = String;
190 fn from_str(s: &str) -> Result<Self, Self::Err> {
191 let s = s.trim();
192 for (suffix, suffix_str) in PREFIX_TABLE.iter() {
193 if s.ends_with(suffix_str) {
194 let num_str = &s[..s.len() - suffix_str.len()];
195 let val: f64 = num_str.trim().parse()
196 .map_err(|e| format!("Parse number '{}' error for '{}'", num_str, e))?;
197 return Ok(Number::new(val, *suffix));
198 }
199 }
200 let val: f64 = s.parse().map_err(|e| format!("Parse number '{}' error for '{}'", s, e))?;
202 return Ok(Number::new(val, Suffix::None));
203 }
204}
205
206
207macro_rules! impl_from {
208 ($t:ty) => {
209 impl From<$t> for Number {
210 fn from(value: $t) -> Self {
211 Self {
212 value: value as f64,
213 suffix: Suffix::None
214 }
215 }
216 }
217 };
218}
219
220impl_from!(f64);
221impl_from!(f32);
222impl_from!(u32);
223impl_from!(i32);
224
225impl Add for Number {
226 type Output = Number;
227 fn add(self, rhs: Number) -> Number {
228 Number::from_f64(self.to_f64() + rhs.to_f64())
229 }
230}
231
232impl Sub for Number {
233 type Output = Number;
234 fn sub(self, rhs: Number) -> Number {
235 Number::from_f64(self.to_f64() - rhs.to_f64())
236 }
237}
238
239impl Mul for Number {
240 type Output = Number;
241 fn mul(self, rhs: Number) -> Number {
242 Number::from_f64(self.to_f64() * rhs.to_f64())
243 }
244}
245
246impl Div for Number {
247 type Output = Number;
248 fn div(self, rhs: Number) -> Number {
249 Number::from_f64(self.to_f64() / rhs.to_f64())
250 }
251}
252
253impl Add<f64> for Number {
254 type Output = Number;
255 fn add(self, rhs: f64) -> Number {
256 Number::from_f64(self.to_f64() + rhs)
257 }
258}
259
260impl Sub<f64> for Number {
261 type Output = Number;
262 fn sub(self, rhs: f64) -> Number {
263 Number::from_f64(self.to_f64() - rhs)
264 }
265}
266
267impl Mul<f64> for Number {
268 type Output = Number;
269 fn mul(self, rhs: f64) -> Number {
270 Number::from_f64(self.to_f64() * rhs)
271 }
272}
273
274impl Div<f64> for Number {
275 type Output = Number;
276 fn div(self, rhs: f64) -> Number {
277 Number::from_f64(self.to_f64() / rhs)
278 }
279}
280
281impl Add<Number> for f64 {
282 type Output = Number;
283 fn add(self, rhs: Number) -> Number {
284 Number::from_f64(self + rhs.to_f64())
285 }
286}
287
288impl Sub<Number> for f64 {
289 type Output = Number;
290 fn sub(self, rhs: Number) -> Number {
291 Number::from_f64(self - rhs.to_f64())
292 }
293}
294
295impl Mul<Number> for f64 {
296 type Output = Number;
297 fn mul(self, rhs: Number) -> Number {
298 Number::from_f64(self * rhs.to_f64())
299 }
300}
301
302impl Div<Number> for f64 {
303 type Output = Number;
304 fn div(self, rhs: Number) -> Number {
305 Number::from_f64(self / rhs.to_f64())
306 }
307}
308
309impl Rem<Number> for Number {
310 type Output = Number;
311 fn rem(self, rhs: Number) -> Self::Output {
312 Number::from_f64(self.to_f64() % rhs.to_f64())
313 }
314}
315
316impl Rem<f64> for Number {
317 type Output = Number;
318 fn rem(self, rhs: f64) -> Self::Output {
319 Number::from_f64(self.to_f64() % rhs)
320 }
321}
322
323impl Rem<Number> for f64 {
324 type Output = Number;
325 fn rem(self, rhs: Number) -> Self::Output {
326 Number::from_f64(self % rhs.to_f64())
327 }
328}
329
330impl Neg for Number {
331 type Output = Self;
332 fn neg(self) -> Self::Output {
333 Self {
334 value: -self.value,
335 suffix: self.suffix
336 }
337 }
338}
339
340impl PartialEq<f64> for Number {
341 fn eq(&self, other: &f64) -> bool {
342 self.to_f64() == *other
343 }
344}
345
346impl PartialEq<Number> for f64 {
347 fn eq(&self, other: &Number) -> bool {
348 other == self
349 }
350}
351
352impl PartialOrd for Number {
353 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
354 self.to_f64().partial_cmp(&other.to_f64())
355 }
356}
357
358impl PartialOrd<f64> for Number {
359 fn partial_cmp(&self, other: &f64) -> Option<Ordering> {
360 self.to_f64().partial_cmp(other)
361 }
362}
363
364impl PartialOrd<Number> for f64 {
365 fn partial_cmp(&self, other: &Number) -> Option<Ordering> {
366 self.partial_cmp(&other.to_f64())
367 }
368}
369
370impl Eq for Number {}
371
372impl Ord for Number {
373 fn cmp(&self, other: &Self) -> Ordering {
374 self.partial_cmp(other).unwrap()
375 }
376}
377
378impl Serialize for Number {
379 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
380 where
381 S: Serializer,
382 {
383 let s = self.to_string();
384 serializer.serialize_str(&s)
385 }
386}
387
388impl<'de> Deserialize<'de> for Number {
389 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
390 where
391 D: Deserializer<'de>,
392 {
393 let s = String::deserialize(deserializer)?;
394 Number::from_str(&s).map_err(serde::de::Error::custom)
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use crate::num;
401
402 use super::*;
403 use std::str::FromStr;
404
405 #[test]
406 fn test_prefix_factor_and_suffix() {
407 assert_eq!(Suffix::Giga.factor(), 1e9);
408 assert_eq!(Suffix::Micro.name(), "u");
409 assert_eq!(Suffix::from_str("K"), Ok(Suffix::Kilo));
410 assert_eq!(Suffix::from_str("z"), Err(()));
411 }
412
413 #[test]
414 fn test_number_new_and_to_f64() {
415 let n = Number::new(3.3, Suffix::Kilo);
416 assert_eq!(n.to_f64(), 3300.0);
417 }
418
419 #[test]
420 fn test_number_from_f64() {
421 let n = Number::from_f64(1e-6);
422 assert_eq!(n.suffix, Suffix::Micro);
423 assert!((n.value - 1.0).abs() < 1e-6);
424
425 let n2 = Number::from_f64(1e3);
426 assert_eq!(n2.suffix, Suffix::Kilo);
427 }
428
429 #[test]
430 fn test_number_from_str() {
431 let a = Number::from_str("3.3K").unwrap();
432 assert_eq!(a.suffix, Suffix::Kilo);
433 assert!((a.value - 3.3).abs() < 1e-6);
434
435 let b = Number::from_str("2.2u").unwrap();
436 assert_eq!(b.suffix, Suffix::Micro);
437 assert!((b.value - 2.2).abs() < 1e-6);
438
439 let c = Number::from_str("100").unwrap();
440 assert_eq!(c.suffix, Suffix::None);
441 assert_eq!(c.value, 100.0);
442
443 assert!(Number::from_str("3.3X").is_err());
444 }
445
446 #[test]
447 fn test_display() {
448 let a = Number::new(1.23456, Suffix::Milli);
449 let s = format!("{}", a);
450 assert_eq!(s, "1.23456m");
451 }
452
453 #[test]
454 fn test_number_arithmetic() {
455 let a = Number::new(3.3, Suffix::Kilo); let b = Number::new(2.2, Suffix::Micro); let c = a + b;
459 assert!((c.to_f64() - 3300.0000022).abs() < 1e-6);
460
461 let d = a - b;
462 assert!((d.to_f64() - 3299.9999978).abs() < 1e-6);
463
464 let e = a * b;
465 assert!((e.to_f64() - 3300.0 * 2.2e-6).abs() < 1e-9);
466
467 let f = a / b;
468 assert!((f.to_f64() - (3300.0 / 2.2e-6)).abs() < 1e-3);
469
470 let g = num!(7.3) % num!(2.0);
471 assert_eq!(g, 7.3 % 2.0);
472 }
473
474 #[test]
475 fn test_number_f64_arithmetic() {
476 let a = Number::new(3.3, Suffix::Kilo); let b = a + 1.0;
478 assert!((b.to_f64() - 3301.0).abs() < 1e-6);
479 }
480
481 #[test]
482 fn test_num_macro() {
483 use crate::num;
484 let a = num!(3.3 k);
485 assert_eq!(a.suffix, Suffix::Kilo);
486 assert_eq!(a.value, 3.3);
487
488 let b = num!(1.0 u);
489 assert_eq!(b.suffix, Suffix::Micro);
490 assert_eq!(b.value, 1.0);
491
492 let c = num!(100);
493 assert_eq!(c.suffix, Suffix::None);
494 assert_eq!(c.value, 100.0);
495
496 let c = 100;
497 let c = num!(c);
498 assert_eq!(c.value, 100.0);
499 }
500
501 use serde_json;
502
503 #[test]
504 fn test_serialize_number() {
505 let n = Number::new(1.5, Suffix::Milli);
506 let json = serde_json::to_string(&n).unwrap();
507 assert_eq!(json, "\"1.5m\"");
508 }
509
510 #[test]
511 fn test_deserialize_number() {
512 let json = "\"2.2u\"";
513 let n: Number = serde_json::from_str(json).unwrap();
514 assert_eq!(n, Number::new(2.2, Suffix::Micro));
515 }
516
517 #[test]
518 fn test_serialize_deserialize_roundtrip() {
519 let original = Number::new(3.3, Suffix::Nano);
520 let json = serde_json::to_string(&original).unwrap();
521 let parsed: Number = serde_json::from_str(&json).unwrap();
522 assert_eq!(original, parsed);
523 }
524
525 #[test]
526 fn test_deserialize_invalid_number() {
527 let json = "\"bad_number\"";
528 let result: Result<Number, _> = serde_json::from_str(json);
529 assert!(result.is_err());
530 }
531
532 #[test]
533 fn test_deserialize_number_no_suffix() {
534 let json = "\"42.0\"";
535 let n: Number = serde_json::from_str(json).unwrap();
536 assert_eq!(n, Number::new(42.0, Suffix::None));
537 }
538}