fluent_static_value/
number.rs1use std::str::FromStr;
2
3pub mod format;
4use crate::Value;
5
6#[derive(Debug, Clone, Copy)]
7pub enum Number {
8 I64(i64),
9 U64(u64),
10 I128(i128),
11 U128(u128),
12 F64(f64),
13}
14
15impl PartialEq for Number {
16 fn eq(&self, other: &Self) -> bool {
17 match self.ordered_tuple(other) {
18 (Number::I64(i1), Number::I64(i2)) => i1 == i2,
19 (Number::U64(u1), Number::I64(i2)) if *i2 >= 0 => *u1 == *i2 as u64,
20 (Number::U64(u1), Number::U64(u2)) => u1 == u2,
21 (Number::I128(i1), Number::I64(i2)) => *i1 == *i2 as i128,
22 (Number::I128(i1), Number::U64(u2)) => *i1 == *u2 as i128,
23 (Number::I128(i1), Number::I128(i2)) => i1 == i2,
24 (Number::U128(u1), Number::I64(i2)) if *i2 >= 0 => *u1 == *i2 as u128,
25 (Number::U128(u1), Number::U64(u2)) => *u1 == *u2 as u128,
26 (Number::U128(u1), Number::I128(i2)) if *i2 >= 0 => *u1 == *i2 as u128,
27 (Number::U128(u1), Number::U128(u2)) => u1 == u2,
28 (Number::F64(f1), n2) => f64::abs(f1 - n2.as_f64()) < f64::EPSILON,
29
30 _ => false,
31 }
32 }
33}
34
35impl Number {
36 fn ord(&self) -> usize {
37 match self {
38 Number::I64(_) => 0,
39 Number::U64(_) => 1,
40 Number::I128(_) => 2,
41 Number::U128(_) => 3,
42 Number::F64(_) => 4,
43 }
44 }
45
46 fn ordered_tuple<'a>(&'a self, other: &'a Self) -> (&'a Self, &'a Self) {
47 if self.ord() > other.ord() {
48 (self, other)
49 } else {
50 (other, self)
51 }
52 }
53
54 pub fn as_f64(&self) -> f64 {
55 match self {
56 Number::I64(v) => *v as f64,
57 Number::U64(v) => *v as f64,
58 Number::I128(v) => *v as f64,
59 Number::U128(v) => *v as f64,
60 Number::F64(v) => *v,
61 }
62 }
63
64 pub fn as_string(&self) -> String {
65 match self {
66 Number::I64(n) => n.to_string(),
67 Number::U64(n) => n.to_string(),
68 Number::I128(n) => n.to_string(),
69 Number::U128(n) => n.to_string(),
70 Number::F64(n) => n.to_string(),
71 }
72 }
73}
74
75impl FromStr for Number {
76 type Err = std::num::ParseFloatError;
77
78 fn from_str(s: &str) -> Result<Self, Self::Err> {
79 if s.contains('.') {
80 match s.parse::<f64>() {
82 Ok(f) => Ok(Number::F64(f)),
83 Err(e) => Err(e),
84 }
85 } else {
86 if let Ok(i) = s.parse::<i64>() {
88 Ok(Number::I64(i))
89 } else if let Ok(u) = s.parse::<u64>() {
90 Ok(Number::U64(u))
91 } else if let Ok(i) = s.parse::<i128>() {
92 Ok(Number::I128(i))
93 } else if let Ok(u) = s.parse::<u128>() {
94 Ok(Number::U128(u))
95 } else {
96 match s.parse::<f64>() {
98 Ok(f) => Ok(Number::F64(f)),
99 Err(e) => Err(e),
100 }
101 }
102 }
103 }
104}
105
106impl<'a> From<Number> for Value<'a> {
107 fn from(value: Number) -> Self {
108 Self::Number {
109 value,
110 format: None,
111 }
112 }
113}
114
115macro_rules! impl_from_for_number {
116 ($($t:ty => $variant:ident),*) => {
117 $(
118 impl From<$t> for Number {
119 fn from(value: $t) -> Self {
120 Number::$variant(value as _)
121 }
122 }
123 impl From<&$t> for Number {
124 fn from(value: &$t) -> Self {
125 Number::$variant(*value as _)
126 }
127 }
128 impl From<$t> for Value<'_> {
129 fn from(value: $t) -> Self {
130 Value::Number {
131 value: Number::$variant(value as _),
132 format: None
133 }
134 }
135 }
136 impl From<&$t> for Value<'_> {
137 fn from(value: &$t) -> Self {
138 Value::Number{
139 value: Number::$variant(*value as _),
140 format: None
141 }
142 }
143 }
144 )*
145 };
146}
147
148impl_from_for_number! {
149 i8 => I64,
150 i16 => I64,
151 i32 => I64,
152 i64 => I64,
153 i128 => I128,
154 isize => I64,
155 u8 => U64,
156 u16 => U64,
157 u32 => U64,
158 u64 => U64,
159 u128 => U128,
160 usize => U64,
161 f32 => F64,
162 f64 => F64
163}
164
165#[cfg(test)]
166mod test {
167 use super::Number;
168
169 #[test]
170 fn test_number_equality() {
171 let n1 = Number::I64(0);
172 let n2 = Number::F64(0f64);
173 assert_eq!(n1, n2);
174 }
175}