vortex_dtype/
decimal.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::fmt::{Display, Formatter};
5
6use num_traits::ToPrimitive;
7use vortex_error::{VortexError, VortexExpect, vortex_bail};
8
9use crate::DType;
10
11const MAX_PRECISION: u8 = 76;
12const MAX_SCALE: i8 = 76;
13
14/// Maximum precision for a Decimal128 type from Arrow
15pub const DECIMAL128_MAX_PRECISION: u8 = 38;
16
17/// Maximum precision for a Decimal256 type from Arrow
18pub const DECIMAL256_MAX_PRECISION: u8 = 76;
19
20/// Maximum sacle for a Decimal128 type from Arrow
21pub const DECIMAL128_MAX_SCALE: i8 = 38;
22
23/// Maximum sacle for a Decimal256 type from Arrow
24pub const DECIMAL256_MAX_SCALE: i8 = 76;
25
26/// Parameters that define the precision and scale of a decimal type.
27///
28/// Decimal types allow real numbers with a similar precision and scale to be represented exactly.
29#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct DecimalDType {
32    precision: u8,
33    scale: i8,
34}
35
36impl DecimalDType {
37    /// Checked constructor for a `DecimalDType`.
38    ///
39    /// # Panics
40    ///
41    /// Attempting to build a new instance with invalid precision or scale values will panic.
42    pub fn new(precision: u8, scale: i8) -> Self {
43        assert!(
44            precision <= MAX_PRECISION,
45            "decimal precision {precision} exceeds MAX_PRECISION"
46        );
47
48        assert!(
49            scale <= MAX_SCALE,
50            "decimal scale {scale} exceeds MAX_SCALE"
51        );
52
53        Self { precision, scale }
54    }
55
56    /// The precision is the number of significant figures that the decimal tracks.
57    pub fn precision(&self) -> u8 {
58        self.precision
59    }
60
61    /// The scale is the maximum number of digits relative to the decimal point.
62    ///
63    /// Positive scale means digits after decimal point, negative scale means number of
64    /// zeros before the decimal point.
65    pub fn scale(&self) -> i8 {
66        self.scale
67    }
68
69    /// Return the max number of bits required to fit a decimal with `precision` in.
70    pub fn required_bit_width(&self) -> usize {
71        (self.precision as f32 * 10.0f32.log(2.0))
72            .ceil()
73            .to_usize()
74            .vortex_expect("too many bits required")
75    }
76}
77
78impl Display for DecimalDType {
79    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
80        write!(f, "decimal({},{})", self.precision, self.scale)
81    }
82}
83
84impl TryFrom<&DType> for DecimalDType {
85    type Error = VortexError;
86
87    fn try_from(value: &DType) -> Result<Self, Self::Error> {
88        match value {
89            DType::Decimal(dt, _) => Ok(*dt),
90            _ => vortex_bail!("Cannot convert DType {value} into DecimalType"),
91        }
92    }
93}
94
95impl TryFrom<DType> for DecimalDType {
96    type Error = VortexError;
97
98    fn try_from(value: DType) -> Result<Self, Self::Error> {
99        Self::try_from(&value)
100    }
101}