1use std::{convert::TryInto, fmt, num::ParseIntError};
4
5use bitvec::prelude::*;
6
7use crate::error::{Decimal128ErrorKind, Error, Result};
8
9#[derive(Copy, Clone, Hash, PartialEq, Eq)]
27pub struct Decimal128 {
28 pub(crate) bytes: [u8; 16],
30}
31
32impl Decimal128 {
33 pub fn from_bytes(bytes: [u8; 128 / 8]) -> Self {
35 Self { bytes }
36 }
37
38 pub fn bytes(&self) -> [u8; 128 / 8] {
40 self.bytes
41 }
42
43 #[cfg(feature = "serde")]
44 pub(crate) fn deserialize_from_slice<E: serde::de::Error>(
45 bytes: &[u8],
46 ) -> std::result::Result<Self, E> {
47 let arr: [u8; 128 / 8] = bytes.try_into().map_err(E::custom)?;
48 Ok(Decimal128 { bytes: arr })
49 }
50}
51
52impl fmt::Debug for Decimal128 {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 write!(f, "Decimal128({})", hex::encode(self.bytes))
55 }
56}
57
58impl fmt::Display for Decimal128 {
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 write!(f, "{}", ParsedDecimal128::new(self))
61 }
62}
63
64impl std::str::FromStr for Decimal128 {
65 type Err = Error;
66
67 fn from_str(s: &str) -> Result<Self> {
68 Ok(s.parse::<ParsedDecimal128>()?.pack())
69 }
70}
71
72#[derive(Debug, Clone, PartialEq)]
73struct ParsedDecimal128 {
74 sign: bool,
75 kind: Decimal128Kind,
76}
77
78#[derive(Debug, Clone, PartialEq)]
79enum Decimal128Kind {
80 NaN {
81 signalling: bool,
82 },
83 Infinity,
84 Finite {
85 exponent: Exponent,
86 coefficient: Coefficient,
87 },
88}
89
90#[derive(Debug, Clone, PartialEq)]
91struct Exponent([u8; 2]);
92
93impl Exponent {
94 const BIAS: i16 = 6176;
96 const TINY: i16 = -6176;
99 const MAX: i16 = 6111;
101
102 const UNUSED_BITS: usize = 2;
104 const PACKED_WIDTH: usize = 14;
106
107 fn from_bits(src_bits: &BitSlice<u8, Msb0>) -> Self {
108 let mut bytes = [0u8; 2];
109 bytes.view_bits_mut::<Msb0>()[Self::UNUSED_BITS..].copy_from_bitslice(src_bits);
110 Self(bytes)
111 }
112
113 fn from_native(value: i16) -> Self {
114 let mut bytes = [0u8; 2];
115 bytes.view_bits_mut::<Msb0>().store_be(value + Self::BIAS);
116 Self(bytes)
117 }
118
119 fn bits(&self) -> &BitSlice<u8, Msb0> {
120 &self.0.view_bits::<Msb0>()[Self::UNUSED_BITS..]
121 }
122
123 fn raw(&self) -> u16 {
124 self.0.view_bits::<Msb0>().load_be::<u16>()
125 }
126
127 fn value(&self) -> i16 {
128 (self.raw() as i16) - Self::BIAS
129 }
130}
131
132#[derive(Debug, Clone, PartialEq)]
133struct Coefficient([u8; 16]);
134
135impl Coefficient {
136 const UNUSED_BITS: usize = 14;
138 const MAX_DIGITS: usize = 34;
140 const MAX_VALUE: u128 = 9_999_999_999_999_999_999_999_999_999_999_999;
142
143 fn from_bits(src_prefix: &BitSlice<u8, Msb0>, src_suffix: &BitSlice<u8, Msb0>) -> Result<Self> {
144 let mut bytes = [0u8; 16];
145 let bits = &mut bytes.view_bits_mut::<Msb0>()[Self::UNUSED_BITS..];
146 let prefix_len = src_prefix.len();
147 bits[0..prefix_len].copy_from_bitslice(src_prefix);
148 bits[prefix_len..].copy_from_bitslice(src_suffix);
149 let out = Self(bytes);
150 if out.value() > Self::MAX_VALUE {
151 Err(Error::decimal128(Decimal128ErrorKind::Overflow {}))
152 } else {
153 Ok(out)
154 }
155 }
156
157 fn from_native(value: u128) -> Self {
158 let mut bytes = [0u8; 16];
159 bytes.view_bits_mut::<Msb0>().store_be(value);
160 Self(bytes)
161 }
162
163 fn bits(&self) -> &BitSlice<u8, Msb0> {
164 &self.0.view_bits::<Msb0>()[Self::UNUSED_BITS..]
165 }
166
167 fn value(&self) -> u128 {
168 self.0.view_bits::<Msb0>().load_be::<u128>()
169 }
170}
171
172impl ParsedDecimal128 {
173 fn new(source: &Decimal128) -> Self {
174 let tmp: [u8; 16] = {
178 let mut tmp = [0u8; 16];
179 tmp.view_bits_mut::<Msb0>()
180 .store_be(source.bytes.view_bits::<Msb0>().load_le::<u128>());
181 tmp
182 };
183 let src_bits = tmp.view_bits::<Msb0>();
184
185 let sign = src_bits[0];
186 let kind = if src_bits[1..5].all() {
187 if src_bits[5] {
189 Decimal128Kind::NaN {
190 signalling: src_bits[6],
191 }
192 } else {
193 Decimal128Kind::Infinity
194 }
195 } else {
196 let exponent_offset;
198 let coeff_prefix;
199 if src_bits[1..3].all() {
200 exponent_offset = 3;
201 coeff_prefix = bits![static u8, Msb0; 1, 0, 0];
202 } else {
203 exponent_offset = 1;
204 coeff_prefix = bits![static u8, Msb0; 0];
205 }
206 let coeff_offset = exponent_offset + Exponent::PACKED_WIDTH;
207
208 let exponent = Exponent::from_bits(&src_bits[exponent_offset..coeff_offset]);
209 let coefficient = match Coefficient::from_bits(coeff_prefix, &src_bits[coeff_offset..])
210 {
211 Ok(c) => c,
212 Err(_) => Coefficient([0u8; 16]),
214 };
215 Decimal128Kind::Finite {
216 exponent,
217 coefficient,
218 }
219 };
220 ParsedDecimal128 { sign, kind }
221 }
222
223 fn pack(&self) -> Decimal128 {
224 let mut tmp = [0u8; 16];
225 let dest_bits = tmp.view_bits_mut::<Msb0>();
226
227 dest_bits.set(0, self.sign);
228
229 match &self.kind {
230 Decimal128Kind::NaN { signalling } => {
231 dest_bits[1..6].copy_from_bitslice(bits![u8, Msb0; 1, 1, 1, 1, 1]);
232 dest_bits.set(6, *signalling);
233 }
234 Decimal128Kind::Infinity => {
235 dest_bits[1..6].copy_from_bitslice(bits![u8, Msb0; 1, 1, 1, 1, 0]);
236 }
237 Decimal128Kind::Finite {
238 exponent,
239 coefficient,
240 } => {
241 let mut coeff_bits = coefficient.bits();
242 let exponent_offset;
243 if coeff_bits[0] {
244 dest_bits.set(1, true);
245 dest_bits.set(2, true);
246 coeff_bits = &coeff_bits[3..];
247 exponent_offset = 3;
248 } else {
249 coeff_bits = &coeff_bits[1..];
250 exponent_offset = 1;
251 };
252 let coeff_offset = exponent_offset + Exponent::PACKED_WIDTH;
253 dest_bits[exponent_offset..coeff_offset].copy_from_bitslice(exponent.bits());
254 dest_bits[coeff_offset..].copy_from_bitslice(coeff_bits);
255 }
256 }
257
258 let mut bytes = [0u8; 16];
259 bytes
260 .view_bits_mut::<Msb0>()
261 .store_le(tmp.view_bits::<Msb0>().load_be::<u128>());
262 Decimal128 { bytes }
263 }
264}
265
266impl fmt::Display for ParsedDecimal128 {
267 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268 if self.sign && !matches!(&self.kind, Decimal128Kind::NaN { .. }) {
270 write!(f, "-")?;
271 }
272 match &self.kind {
273 Decimal128Kind::NaN {
274 signalling: _signalling,
275 } => {
276 write!(f, "NaN")?;
282 }
283 Decimal128Kind::Infinity => write!(f, "Infinity")?,
284 Decimal128Kind::Finite {
285 exponent,
286 coefficient,
287 } => {
288 let coeff_str = format!("{}", coefficient.value());
289 let exp_val = exponent.value();
290 let adj_exp = exp_val + (coeff_str.len() as i16) - 1;
291 if exp_val <= 0 && adj_exp >= -6 {
292 if exp_val == 0 {
294 write!(f, "{}", coeff_str)?;
295 } else {
296 let dec_charlen = exp_val.unsigned_abs() as usize;
297 if dec_charlen >= coeff_str.len() {
298 write!(f, "0.")?;
299 write!(f, "{}", "0".repeat(dec_charlen - coeff_str.len()))?;
300 write!(f, "{}", coeff_str)?;
301 } else {
302 let (pre, post) = coeff_str.split_at(coeff_str.len() - dec_charlen);
303 write!(f, "{}", pre)?;
304 write!(f, ".")?;
305 write!(f, "{}", post)?;
306 }
307 }
308 } else {
309 let (pre, post) = coeff_str.split_at(1);
311 write!(f, "{}", pre)?;
312 if !post.is_empty() {
313 write!(f, ".{}", post)?;
314 }
315 write!(f, "E")?;
316 if adj_exp > 0 {
317 write!(f, "+")?;
318 }
319 write!(f, "{}", adj_exp)?;
320 }
321 }
322 }
323 Ok(())
324 }
325}
326
327impl std::str::FromStr for ParsedDecimal128 {
328 type Err = Error;
329
330 fn from_str(mut s: &str) -> Result<Self> {
331 let sign;
332 if let Some(rest) = s.strip_prefix(&['-', '+'][..]) {
333 sign = s.starts_with('-');
334 s = rest;
335 } else {
336 sign = false;
337 }
338 let kind = match s.to_ascii_lowercase().as_str() {
339 "nan" => Decimal128Kind::NaN { signalling: false },
340 "snan" => Decimal128Kind::NaN { signalling: true },
341 "infinity" | "inf" => Decimal128Kind::Infinity,
342 finite_str => {
343 let mut decimal_str;
345 let exp_str;
346 match finite_str.split_once('e') {
347 None => {
348 decimal_str = finite_str;
349 exp_str = "0";
350 }
351 Some((_, "")) => {
352 return Err(Error::decimal128(Decimal128ErrorKind::EmptyExponent {}))
353 }
354 Some((pre, post)) => {
355 decimal_str = pre;
356 exp_str = post;
357 }
358 }
359 let mut wide_exp = exp_str.parse::<i128>().map_err(|e| {
362 Error::decimal128(Decimal128ErrorKind::InvalidExponent {}).with_message(e)
363 })?;
364
365 let joined_str;
367 if let Some((pre, post)) = decimal_str.split_once('.') {
368 let exp_adj = post
369 .len()
370 .try_into()
371 .map_err(|_| Error::decimal128(Decimal128ErrorKind::Underflow {}))?;
372 wide_exp = wide_exp
373 .checked_sub(exp_adj)
374 .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Underflow {}))?;
375 joined_str = format!("{}{}", pre, post);
376 decimal_str = &joined_str;
377 }
378
379 let rest = decimal_str.trim_start_matches('0');
381 decimal_str = if rest.is_empty() { "0" } else { rest };
382
383 {
385 let len = decimal_str.len();
386 if len > Coefficient::MAX_DIGITS {
387 decimal_str = round_decimal_str(decimal_str, Coefficient::MAX_DIGITS)?;
388 let exp_adj = (len - decimal_str.len())
389 .try_into()
390 .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
391 wide_exp = wide_exp
392 .checked_add(exp_adj)
393 .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
394 }
395 }
396
397 const TINY: i128 = Exponent::TINY as i128;
399 if wide_exp < TINY {
400 if decimal_str != "0" {
401 let delta = (TINY - wide_exp)
402 .try_into()
403 .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
404 let new_precision = decimal_str
405 .len()
406 .checked_sub(delta)
407 .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
408 decimal_str = round_decimal_str(decimal_str, new_precision)?;
409 }
410 wide_exp = Exponent::TINY.into();
411 }
412 let padded_str;
413 const MAX: i128 = Exponent::MAX as i128;
414 if wide_exp > MAX {
415 if decimal_str != "0" {
416 let delta = (wide_exp - MAX)
417 .try_into()
418 .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
419 if decimal_str
420 .len()
421 .checked_add(delta)
422 .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Overflow {}))?
423 > Coefficient::MAX_DIGITS
424 {
425 return Err(Error::decimal128(Decimal128ErrorKind::Overflow {}));
426 }
427 padded_str = format!("{}{}", decimal_str, "0".repeat(delta));
428 decimal_str = &padded_str;
429 }
430 wide_exp = Exponent::MAX.into();
431 }
432
433 let exp: i16 = wide_exp
435 .try_into()
436 .map_err(|_| Error::decimal128(Decimal128ErrorKind::Overflow {}))?;
437 let exponent = Exponent::from_native(exp);
438 let coeff: u128 = decimal_str.parse().map_err(|e: ParseIntError| {
439 Error::decimal128(Decimal128ErrorKind::InvalidCoefficient {}).with_message(e)
440 })?;
441 let coefficient = Coefficient::from_native(coeff);
442 Decimal128Kind::Finite {
443 exponent,
444 coefficient,
445 }
446 }
447 };
448
449 Ok(Self { sign, kind })
450 }
451}
452
453fn round_decimal_str(s: &str, precision: usize) -> Result<&str> {
454 let (pre, post) = s
455 .split_at_checked(precision)
456 .ok_or_else(|| Error::decimal128(Decimal128ErrorKind::Unparseable {}))?;
457 if post.chars().any(|c| c != '0') {
459 return Err(Error::decimal128(Decimal128ErrorKind::InexactRounding {}));
460 }
461 Ok(pre)
462}