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// }