Skip to main content

rimu_value/
number.rs

1use rust_decimal::{
2    prelude::{FromPrimitive, ToPrimitive},
3    serde::float::{deserialize, serialize},
4    Decimal,
5};
6use serde::{
7    de::{Unexpected, Visitor},
8    forward_to_deserialize_any, Deserialize, Deserializer, Serialize,
9};
10use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Sub};
11use std::{
12    fmt::{Debug, Display},
13    hash::{Hash, Hasher},
14};
15
16use crate::SerdeValueError;
17
18#[derive(Clone, Copy)]
19pub struct Number(Decimal);
20
21impl Debug for Number {
22    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        Debug::fmt(&self.0, formatter)
24    }
25}
26
27impl Display for Number {
28    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        Display::fmt(&self.0, formatter)
30    }
31}
32
33impl From<Decimal> for Number {
34    fn from(value: Decimal) -> Self {
35        Self(value)
36    }
37}
38
39impl Deref for Number {
40    type Target = Decimal;
41
42    fn deref(&self) -> &Self::Target {
43        &self.0
44    }
45}
46
47impl Serialize for Number {
48    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
49    where
50        S: serde::Serializer,
51    {
52        serialize(&self.0, serializer)
53    }
54}
55
56impl<'de> Deserialize<'de> for Number {
57    #[inline]
58    fn deserialize<D>(deserializer: D) -> Result<Number, D::Error>
59    where
60        D: Deserializer<'de>,
61    {
62        deserialize(deserializer).map(Number)
63    }
64}
65
66impl<'de> Deserializer<'de> for Number {
67    type Error = SerdeValueError;
68
69    #[inline]
70    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
71    where
72        V: Visitor<'de>,
73    {
74        let Some(f) = self.0.to_f64() else {
75            return Err(SerdeValueError::NumberOutOfRange);
76        };
77        visitor.visit_f64(f)
78    }
79
80    forward_to_deserialize_any! {
81        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
82        bytes byte_buf option unit unit_struct newtype_struct seq tuple
83        tuple_struct map struct enum identifier ignored_any
84    }
85}
86
87impl<'de, 'a> Deserializer<'de> for &'a Number {
88    type Error = SerdeValueError;
89
90    #[inline]
91    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
92    where
93        V: Visitor<'de>,
94    {
95        let Some(f) = self.0.to_f64() else {
96            return Err(SerdeValueError::NumberOutOfRange);
97        };
98        visitor.visit_f64(f)
99    }
100
101    forward_to_deserialize_any! {
102        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
103        bytes byte_buf option unit unit_struct newtype_struct seq tuple
104        tuple_struct map struct enum identifier ignored_any
105    }
106}
107
108macro_rules! from_integer {
109    ($($ty:ident)*) => {
110        $(
111            impl From<$ty> for Number {
112                #[inline]
113                #[allow(clippy::cast_sign_loss)]
114                fn from(n: $ty) -> Self {
115                    Number(n.into())
116                }
117            }
118        )*
119    };
120}
121
122macro_rules! from_float {
123    ($($ty:ident)*) => {
124        $(
125            impl From<$ty> for Number {
126                #[inline]
127                #[allow(clippy::cast_sign_loss)]
128                fn from(n: $ty) -> Self {
129                    // TODO what to do
130                    Number(Decimal::from_f64(n as f64).unwrap())
131                }
132            }
133        )*
134    };
135}
136
137from_integer!(i8 i16 i32 i64 isize);
138from_integer!(u8 u16 u32 u64 usize);
139from_float!(f32 f64);
140
141pub(crate) fn unexpected(_number: &Number) -> Unexpected {
142    Unexpected::Other("number")
143}
144
145impl PartialEq for Number {
146    fn eq(&self, other: &Self) -> bool {
147        self.0.eq(&other.0)
148    }
149}
150
151impl Eq for Number {
152    fn assert_receiver_is_total_eq(&self) {
153        self.0.assert_receiver_is_total_eq()
154    }
155}
156
157impl PartialOrd for Number {
158    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
159        self.0.partial_cmp(&other.0)
160    }
161}
162
163impl Ord for Number {
164    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
165        self.0.cmp(&other.0)
166    }
167}
168
169impl Hash for Number {
170    fn hash<H: Hasher>(&self, state: &mut H) {
171        Decimal::hash(&self.0, state)
172    }
173}
174
175impl Neg for Number {
176    type Output = Number;
177
178    fn neg(self) -> Self::Output {
179        self.0.neg().into()
180    }
181}
182
183impl Add for Number {
184    type Output = Number;
185
186    fn add(self, rhs: Self) -> Self::Output {
187        self.0.add(rhs.0).into()
188    }
189}
190
191impl Sub for Number {
192    type Output = Number;
193
194    fn sub(self, rhs: Self) -> Self::Output {
195        self.0.sub(rhs.0).into()
196    }
197}
198
199impl Mul for Number {
200    type Output = Number;
201
202    fn mul(self, rhs: Self) -> Self::Output {
203        self.0.mul(rhs.0).into()
204    }
205}
206
207impl Div for Number {
208    type Output = Number;
209
210    fn div(self, rhs: Self) -> Self::Output {
211        self.0.div(rhs.0).into()
212    }
213}
214
215impl Rem for Number {
216    type Output = Number;
217
218    fn rem(self, rhs: Self) -> Self::Output {
219        self.0.rem(rhs.0).into()
220    }
221}