clickhouse_rs_async/types/
decimal.rs1use std::{
2 cmp::Ordering,
3 fmt,
4 hash::{Hash, Hasher},
5};
6
7static FACTORS10: &[i64] = &[
8 1,
9 10,
10 100,
11 1000,
12 10000,
13 100_000,
14 1_000_000,
15 10_000_000,
16 100_000_000,
17 1_000_000_000,
18 10_000_000_000,
19 100_000_000_000,
20 1_000_000_000_000,
21 10_000_000_000_000,
22 100_000_000_000_000,
23 1_000_000_000_000_000,
24 10_000_000_000_000_000,
25 100_000_000_000_000_000,
26 1_000_000_000_000_000_000,
27];
28
29pub trait Base {
30 fn scale(self, scale: i64) -> i64;
31}
32
33pub trait InternalResult {
34 fn get(underlying: i64) -> Self;
35}
36
37#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
38pub(crate) enum NoBits {
39 N32,
40 N64,
41}
42
43#[derive(Clone)]
45pub struct Decimal {
46 pub(crate) underlying: i64,
47 pub(crate) nobits: NoBits, pub(crate) precision: u8,
49 pub(crate) scale: u8,
50}
51
52impl Default for Decimal {
53 fn default() -> Self {
54 Decimal {
55 underlying: 0,
56 precision: 9,
57 scale: 4,
58 nobits: NoBits::N32,
59 }
60 }
61}
62
63impl Hash for Decimal {
64 fn hash<H: Hasher>(&self, state: &mut H) {
65 self.underlying.hash(state);
66 self.nobits.hash(state);
67 self.precision.hash(state);
68 self.scale.hash(state);
69 }
70}
71
72macro_rules! base_for {
73 ( $( $t:ty: $cast:expr ),* ) => {
74 $(
75 impl Base for $t {
76 fn scale(self, scale: i64) -> i64 {
77 $cast(self * (scale as $t)) as i64
78 }
79 }
80 )*
81 };
82}
83
84base_for! {
85 f32: std::convert::identity,
86 f64: std::convert::identity,
87 i8: i64::from,
88 i16: i64::from,
89 i32: i64::from,
90 i64: std::convert::identity,
91 u8: i64::from,
92 u16: i64::from,
93 u32: i64::from,
94 u64 : std::convert::identity
95}
96
97impl InternalResult for i32 {
98 #[inline(always)]
99 fn get(underlying: i64) -> Self {
100 underlying as Self
101 }
102}
103
104impl InternalResult for i64 {
105 #[inline(always)]
106 fn get(underlying: i64) -> Self {
107 underlying
108 }
109}
110
111impl NoBits {
112 pub(crate) fn from_precision(precision: u8) -> Option<NoBits> {
113 if precision <= 9 {
114 Some(NoBits::N32)
115 } else if precision <= 18 {
116 Some(NoBits::N64)
117 } else {
118 None
119 }
120 }
121}
122
123impl PartialEq for Decimal {
124 fn eq(&self, other: &Self) -> bool {
125 match self.scale.cmp(&other.scale) {
126 Ordering::Less => {
127 let delta = other.scale() - self.scale();
128 let underlying = self.underlying * FACTORS10[delta];
129 other.underlying == underlying
130 }
131 Ordering::Equal => self.underlying == other.underlying,
132 Ordering::Greater => {
133 let delta = self.scale() - other.scale();
134 let underlying = other.underlying * FACTORS10[delta];
135 self.underlying == underlying
136 }
137 }
138 }
139}
140
141fn decimal2str(decimal: &Decimal) -> String {
142 let mut r = format!("{}", decimal.underlying);
143 while r.len() < decimal.scale() {
144 r.insert(0, '0');
145 }
146 let pos = r.len() - decimal.scale();
147 r.insert(pos, '.');
148 if r.starts_with('.') {
149 r.insert(0, '0');
150 }
151 r
152}
153
154impl fmt::Display for Decimal {
155 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
156 write!(f, "{}", decimal2str(self))
157 }
158}
159
160impl fmt::Debug for Decimal {
161 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
162 write!(f, "{}", decimal2str(self))
163 }
164}
165
166impl From<Decimal> for f32 {
167 fn from(value: Decimal) -> Self {
168 value.underlying as f32 / FACTORS10[value.scale()] as f32
169 }
170}
171
172impl From<Decimal> for f64 {
173 fn from(value: Decimal) -> Self {
174 value.underlying as f64 / FACTORS10[value.scale()] as f64
175 }
176}
177
178impl Decimal {
179 pub fn new(underlying: i64, scale: u8) -> Decimal {
181 let precision = 18;
182 if scale > precision {
183 panic!("scale can't be greater than 18");
184 }
185
186 Decimal {
187 underlying,
188 precision,
189 scale,
190 nobits: NoBits::N64,
191 }
192 }
193
194 pub fn of<B: Base>(source: B, scale: u8) -> Decimal {
195 let precision = 18;
196 if scale > precision {
197 panic!("scale can't be greater than 18");
198 }
199
200 let underlying = source.scale(FACTORS10[scale as usize]);
201 if underlying > FACTORS10[precision as usize] {
202 panic!("{} > {}", underlying, FACTORS10[precision as usize]);
203 }
204
205 Decimal {
206 underlying,
207 precision,
208 scale,
209 nobits: NoBits::N64,
210 }
211 }
212
213 #[inline(always)]
235 pub fn internal<I: InternalResult>(&self) -> I {
236 InternalResult::get(self.underlying)
237 }
238
239 pub fn scale(&self) -> usize {
241 self.scale as usize
242 }
243
244 pub(crate) fn set_scale(self, scale: u8) -> Self {
245 let underlying = match scale.cmp(&self.scale) {
246 Ordering::Less => {
247 let delta = self.scale() - scale as usize;
248 self.underlying / FACTORS10[delta]
249 }
250 Ordering::Equal => return self,
251 Ordering::Greater => {
252 let delta = scale as usize - self.scale();
253 self.underlying * FACTORS10[delta]
254 }
255 };
256
257 Decimal {
258 underlying,
259 precision: self.precision,
260 scale,
261 nobits: self.nobits,
262 }
263 }
264}
265
266#[cfg(test)]
267mod test {
268 use super::*;
269
270 #[test]
271 fn test_new() {
272 assert_eq!(Decimal::new(2, 1), Decimal::of(0.2_f64, 1));
273 assert_eq!(Decimal::new(2, 5), Decimal::of(0.00002_f64, 5));
274 }
275
276 #[test]
277 fn test_display() {
278 assert_eq!(format!("{}", Decimal::of(2.1_f32, 4)), "2.1000");
279 assert_eq!(format!("{}", Decimal::of(0.2_f64, 4)), "0.2000");
280 assert_eq!(format!("{}", Decimal::of(2, 4)), "2.0000");
281 assert_eq!(format!("{:?}", Decimal::of(2, 4)), "2.0000");
282 }
283
284 #[test]
285 fn test_eq() {
286 assert_eq!(Decimal::of(2.0_f64, 4), Decimal::of(2.0_f64, 4));
287 assert_ne!(Decimal::of(3.0_f64, 4), Decimal::of(2.0_f64, 4));
288
289 assert_eq!(Decimal::of(2.0_f64, 4), Decimal::of(2.0_f64, 2));
290 assert_ne!(Decimal::of(2.0_f64, 4), Decimal::of(3.0_f64, 2));
291
292 assert_eq!(Decimal::of(2.0_f64, 2), Decimal::of(2.0_f64, 4));
293 assert_ne!(Decimal::of(3.0_f64, 2), Decimal::of(2.0_f64, 4));
294 }
295
296 #[test]
297 fn test_internal32() {
298 let internal: i32 = Decimal::of(2, 4).internal();
299 assert_eq!(internal, 20000_i32);
300 }
301
302 #[test]
303 fn test_internal64() {
304 let internal: i64 = Decimal::of(2, 4).internal();
305 assert_eq!(internal, 20000_i64);
306 }
307
308 #[test]
309 fn test_scale() {
310 assert_eq!(Decimal::of(2, 4).scale(), 4);
311 }
312
313 #[test]
314 fn test_from_f32() {
315 let value: f32 = Decimal::of(2, 4).into();
316 assert!((value - 2.0_f32).abs() <= std::f32::EPSILON);
317 }
318
319 #[test]
320 fn test_from_f64() {
321 let value: f64 = Decimal::of(2, 4).into();
322 assert!((value - 2.0_f64).abs() < std::f64::EPSILON);
323 }
324
325 #[test]
326 fn set_scale1() {
327 let a = Decimal::of(12, 3);
328 let b = a.set_scale(2);
329
330 assert_eq!(2, b.scale);
331 assert_eq!(1200, b.underlying);
332 }
333
334 #[test]
335 fn set_scale2() {
336 let a = Decimal::of(12, 3);
337 let b = a.set_scale(4);
338
339 assert_eq!(4, b.scale);
340 assert_eq!(120_000, b.underlying);
341 }
342
343 #[test]
344 fn test_decimal2str() {
345 let d = Decimal::of(0.00001, 5);
346 let actual = decimal2str(&d);
347 assert_eq!(actual, "0.00001".to_string());
348 }
349}