vortex_dtype/
decimal.rs

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