amadeus_types/decimal.rs
1//! Implement [`Record`] for [`Decimal`].
2
3// use num_bigint::{BigInt, Sign};
4use serde::{Deserialize, Serialize};
5use std::{
6 cmp::Ordering, error::Error, fmt::{self, Display}, str::FromStr
7};
8
9use super::AmadeusOrd;
10
11// use internal::{
12// basic::Repetition,
13// column::reader::ColumnReader,
14// // data_type::{Vec<u8>, Decimal},
15// errors::Result,
16// record::{
17// reader::MapReader,
18// schemas::{DecimalSchema, I32Schema, I64Schema},
19// types::{downcast, Value},
20// Reader, Record,
21// },
22// schema::types::{ColumnPath, Type},
23// };
24
25// [`Decimal`] corresponds to the [Decimal logical type](https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#decimal).
26/// Rust representation for Decimal values.
27///
28/// This is not a representation of Parquet physical type, but rather a wrapper for
29/// DECIMAL logical type, and serves as container for raw parts of decimal values:
30/// unscaled value in bytes, precision and scale.
31#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)]
32pub enum Decimal {
33 /// Decimal backed by `i32`.
34 Int32 {
35 value: [u8; 4],
36 precision: i32,
37 scale: i32,
38 },
39 /// Decimal backed by `i64`.
40 Int64 {
41 value: [u8; 8],
42 precision: i32,
43 scale: i32,
44 },
45 /// Decimal backed by byte array.
46 Bytes {
47 value: Vec<u8>,
48 precision: i32,
49 scale: i32,
50 },
51}
52
53impl Decimal {
54 // /// Creates new decimal value from `i32`.
55 // pub fn from_i32(value: i32, precision: i32, scale: i32) -> Self {
56 // let mut bytes = [0; 4];
57 // BigEndian::write_i32(&mut bytes, value);
58 // Self::Int32 {
59 // value: bytes,
60 // precision,
61 // scale,
62 // }
63 // }
64
65 // /// Creates new decimal value from `i64`.
66 // pub fn from_i64(value: i64, precision: i32, scale: i32) -> Self {
67 // let mut bytes = [0; 8];
68 // BigEndian::write_i64(&mut bytes, value);
69 // Self::Int64 {
70 // value: bytes,
71 // precision,
72 // scale,
73 // }
74 // }
75
76 /// Creates new decimal value from `Vec<u8>`.
77 pub fn from_bytes(value: Vec<u8>, precision: i32, scale: i32) -> Self {
78 Self::Bytes {
79 value,
80 precision,
81 scale,
82 }
83 }
84
85 /// Returns bytes of unscaled value.
86 pub fn data(&self) -> &[u8] {
87 match *self {
88 Self::Int32 { ref value, .. } => value,
89 Self::Int64 { ref value, .. } => value,
90 Self::Bytes { ref value, .. } => value,
91 }
92 }
93
94 /// Returns decimal precision.
95 pub fn precision(&self) -> i32 {
96 match *self {
97 Self::Int32 { precision, .. }
98 | Self::Int64 { precision, .. }
99 | Self::Bytes { precision, .. } => precision,
100 }
101 }
102
103 /// Returns decimal scale.
104 pub fn scale(&self) -> i32 {
105 match *self {
106 Self::Int32 { scale, .. } | Self::Int64 { scale, .. } | Self::Bytes { scale, .. } => {
107 scale
108 }
109 }
110 }
111}
112
113impl AmadeusOrd for Decimal {
114 fn amadeus_cmp(&self, other: &Self) -> Ordering {
115 Ord::cmp(self, other)
116 }
117}
118impl Display for Decimal {
119 fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
120 unimplemented!()
121 }
122}
123impl FromStr for Decimal {
124 type Err = ParseDecimalError;
125
126 fn from_str(_s: &str) -> Result<Self, Self::Err> {
127 unimplemented!()
128 }
129}
130
131#[derive(Clone, PartialEq, Eq, Debug)]
132pub struct ParseDecimalError;
133impl Display for ParseDecimalError {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 write!(f, "error parsing decimal")
136 }
137}
138impl Error for ParseDecimalError {}
139
140// impl From<Decimal> for internal::data_type::Decimal {
141// fn from(_decimal: Decimal) -> Self {
142// unimplemented!()
143// }
144// }
145
146// impl Display for Decimal {
147// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148// // We assert that `scale >= 0` and `precision > scale`, but this will be enforced
149// // when constructing Parquet schema.
150// assert!(self.scale() >= 0 && self.precision() > self.scale());
151
152// // Specify as signed bytes to resolve sign as part of conversion.
153// let num = BigInt::from_signed_bytes_be(self.data());
154
155// // Offset of the first digit in a string.
156// let negative = if num.sign() == Sign::Minus { 1 } else { 0 };
157// let mut num_str = num.to_string();
158// let mut point = num_str.len() as i32 - self.scale() - negative;
159
160// // Convert to string form without scientific notation.
161// if point <= 0 {
162// // Zeros need to be prepended to the unscaled value.
163// while point < 0 {
164// num_str.insert(negative as usize, '0');
165// point += 1;
166// }
167// num_str.insert_str(negative as usize, "0.");
168// } else {
169// // No zeroes need to be prepended to the unscaled value, simply insert decimal
170// // point.
171// num_str.insert((point + negative) as usize, '.');
172// }
173
174// num_str.fmt(f)
175// }
176// }
177
178// impl Default for Decimal {
179// fn default() -> Self {
180// Self::from_i32(0, 0, 0)
181// }
182// }
183
184// impl PartialEq for Decimal {
185// fn eq(&self, other: &Decimal) -> bool {
186// self.precision() == other.precision()
187// && self.scale() == other.scale()
188// && self.data() == other.data()
189// }
190// }