1use fastnum::D128;
24use fastnum::decimal::Context;
25
26use crate::{Error, ErrorKind, Result};
27
28pub type Decimal = D128;
30
31pub fn decimal_from_i128_with_scale(mantissa: i128, scale: u32) -> Decimal {
40 if scale == 0 {
41 return D128::from_i128(mantissa).expect("i128 always fits in D128");
42 }
43
44 let is_negative = mantissa < 0;
46 let abs_str = mantissa.unsigned_abs().to_string();
47 let scale_usize = scale as usize;
48
49 let decimal_str = if abs_str.len() <= scale_usize {
50 let zeros_needed = scale_usize - abs_str.len();
53 format!(
54 "{}0.{}{}",
55 if is_negative { "-" } else { "" },
56 "0".repeat(zeros_needed),
57 abs_str
58 )
59 } else {
60 let decimal_pos = abs_str.len() - scale_usize;
62 format!(
63 "{}{}.{}",
64 if is_negative { "-" } else { "" },
65 &abs_str[..decimal_pos],
66 &abs_str[decimal_pos..]
67 )
68 };
69
70 D128::from_str(&decimal_str, Context::default())
71 .expect("constructed decimal string is always valid")
72}
73
74pub fn try_decimal_from_i128_with_scale(mantissa: i128, scale: u32) -> Result<Decimal> {
79 Ok(decimal_from_i128_with_scale(mantissa, scale))
81}
82
83#[allow(dead_code)]
87pub fn decimal_new(mantissa: i64, scale: u32) -> Decimal {
88 decimal_from_i128_with_scale(mantissa as i128, scale)
89}
90
91pub fn decimal_from_str_exact(s: &str) -> Result<Decimal> {
95 D128::from_str(s, Context::default())
96 .map_err(|e| Error::new(ErrorKind::DataInvalid, format!("Can't parse decimal: {e}")))
97}
98
99pub fn decimal_mantissa(d: &Decimal) -> i128 {
105 let digits = d.digits();
108
109 let unsigned: u128 = digits
112 .to_u128()
113 .expect("Iceberg decimals (max 38 digits) always fit in u128");
114
115 let signed = unsigned as i128;
116 if d.is_sign_negative() {
117 -signed
118 } else {
119 signed
120 }
121}
122
123pub fn decimal_precision(mantissa: i128) -> u32 {
127 mantissa
128 .unsigned_abs()
129 .checked_ilog10()
130 .map_or(1, |x| x + 1)
131}
132
133pub fn decimal_scale(d: &Decimal) -> u32 {
137 let frac = d.fractional_digits_count();
138 if frac < 0 { 0 } else { frac as u32 }
139}
140
141pub fn decimal_rescale(d: Decimal, scale: u32) -> Decimal {
145 d.rescale(scale as i16)
146}
147
148pub fn i128_from_be_bytes(bytes: &[u8]) -> Option<i128> {
153 if bytes.is_empty() {
154 return Some(0);
155 }
156 if bytes.len() > 16 {
157 return None; }
159
160 let is_negative = bytes[0] & 0x80 != 0;
162
163 let mut padded = if is_negative { [0xFF; 16] } else { [0; 16] };
165 let start = 16 - bytes.len();
166 padded[start..].copy_from_slice(bytes);
167
168 Some(i128::from_be_bytes(padded))
169}
170
171pub fn i128_to_be_bytes_min(value: i128) -> Vec<u8> {
176 let bytes = value.to_be_bytes();
177
178 let is_negative = value < 0;
182 let skip_byte = if is_negative { 0xFF } else { 0x00 };
183
184 let mut start = 0;
185 while start < 15 && bytes[start] == skip_byte {
186 let next_byte = bytes[start + 1];
188 let next_is_negative = (next_byte & 0x80) != 0;
189 if next_is_negative == is_negative {
190 start += 1;
191 } else {
192 break;
193 }
194 }
195
196 bytes[start..].to_vec()
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn test_decimal_from_i128_with_scale() {
205 let d = decimal_from_i128_with_scale(12345, 2);
206 assert_eq!(d.to_string(), "123.45");
207
208 let d = decimal_from_i128_with_scale(-12345, 2);
209 assert_eq!(d.to_string(), "-123.45");
210
211 let d = decimal_from_i128_with_scale(0, 5);
212 assert_eq!(d.to_string(), "0.00000");
213 }
214
215 #[test]
216 fn test_decimal_new() {
217 let d = decimal_new(123, 2);
218 assert_eq!(d.to_string(), "1.23");
219
220 let d = decimal_new(-456, 3);
221 assert_eq!(d.to_string(), "-0.456");
222 }
223
224 #[test]
225 fn test_decimal_from_str_exact() {
226 let d = decimal_from_str_exact("123.45").unwrap();
227 assert_eq!(d.to_string(), "123.45");
228
229 let d = decimal_from_str_exact("-0.001").unwrap();
230 assert_eq!(d.to_string(), "-0.001");
231
232 let d = decimal_from_str_exact("99999999999999999999999999999999999999").unwrap();
233 assert_eq!(d.to_string(), "99999999999999999999999999999999999999");
234 }
235
236 #[test]
237 fn test_decimal_mantissa() {
238 let d = decimal_from_i128_with_scale(12345, 2);
239 assert_eq!(decimal_mantissa(&d), 12345);
240
241 let d = decimal_from_i128_with_scale(-12345, 2);
242 assert_eq!(decimal_mantissa(&d), -12345);
243 }
244
245 #[test]
246 fn test_decimal_precision() {
247 assert_eq!(decimal_precision(0), 1);
248 assert_eq!(decimal_precision(5), 1);
249 assert_eq!(decimal_precision(42), 2);
250 assert_eq!(decimal_precision(-42), 2);
251 assert_eq!(decimal_precision(9), 1);
253 assert_eq!(decimal_precision(10), 2);
254 assert_eq!(decimal_precision(99), 2);
255 assert_eq!(decimal_precision(100), 3);
256
257 assert_eq!(
259 decimal_precision(99999999999999999999999999999999999999),
260 38
261 );
262 assert_eq!(
263 decimal_precision(-99999999999999999999999999999999999999),
264 38
265 );
266
267 assert_eq!(decimal_precision(i128::MAX), 39);
269 assert_eq!(decimal_precision(i128::MIN), 39);
270 }
271
272 #[test]
273 fn test_decimal_scale() {
274 let d = decimal_from_i128_with_scale(12345, 2);
275 assert_eq!(decimal_scale(&d), 2);
276
277 let d = decimal_from_i128_with_scale(12345, 0);
278 assert_eq!(decimal_scale(&d), 0);
279 }
280
281 #[test]
282 fn test_decimal_rescale() {
283 let d = decimal_from_str_exact("123.45").unwrap();
284 let rescaled = decimal_rescale(d, 4);
285 assert_eq!(decimal_scale(&rescaled), 4);
286 assert_eq!(decimal_mantissa(&rescaled), 1234500);
287 }
288
289 #[test]
290 fn test_38_digit_precision() {
291 let max_38_digits = "99999999999999999999999999999999999999";
293 let d = decimal_from_str_exact(max_38_digits).unwrap();
294 assert_eq!(d.to_string(), max_38_digits);
295
296 let min_38_digits = "-99999999999999999999999999999999999999";
297 let d = decimal_from_str_exact(min_38_digits).unwrap();
298 assert_eq!(d.to_string(), min_38_digits);
299 }
300
301 #[test]
302 fn test_i128_from_be_bytes() {
303 assert_eq!(i128_from_be_bytes(&[]), Some(0));
305
306 assert_eq!(i128_from_be_bytes(&[0x01]), Some(1));
308 assert_eq!(i128_from_be_bytes(&[0x7F]), Some(127));
309 assert_eq!(i128_from_be_bytes(&[0x00, 0xFF]), Some(255));
310 assert_eq!(i128_from_be_bytes(&[0x04, 0xD2]), Some(1234));
311
312 assert_eq!(i128_from_be_bytes(&[0xFF]), Some(-1));
314 assert_eq!(i128_from_be_bytes(&[0x80]), Some(-128));
315 assert_eq!(i128_from_be_bytes(&[0xFB, 0x2E]), Some(-1234));
316
317 assert_eq!(i128_from_be_bytes(&[0; 17]), None);
319 }
320
321 #[test]
322 fn test_i128_to_be_bytes_min() {
323 assert_eq!(i128_to_be_bytes_min(0), vec![0x00]);
325 assert_eq!(i128_to_be_bytes_min(1), vec![0x01]);
326 assert_eq!(i128_to_be_bytes_min(127), vec![0x7F]);
327 assert_eq!(i128_to_be_bytes_min(128), vec![0x00, 0x80]);
328 assert_eq!(i128_to_be_bytes_min(255), vec![0x00, 0xFF]);
329 assert_eq!(i128_to_be_bytes_min(1234), vec![0x04, 0xD2]);
330
331 assert_eq!(i128_to_be_bytes_min(-1), vec![0xFF]);
333 assert_eq!(i128_to_be_bytes_min(-128), vec![0x80]);
334 assert_eq!(i128_to_be_bytes_min(-129), vec![0xFF, 0x7F]);
335 assert_eq!(i128_to_be_bytes_min(-1234), vec![0xFB, 0x2E]);
336
337 for val in [
339 0i128,
340 1,
341 -1,
342 127,
343 -128,
344 255,
345 -256,
346 12345,
347 -12345,
348 i128::MAX,
349 i128::MIN,
350 ] {
351 let bytes = i128_to_be_bytes_min(val);
352 assert_eq!(
353 i128_from_be_bytes(&bytes),
354 Some(val),
355 "Round trip failed for {val}"
356 );
357 }
358 }
359}