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 {} exceeds MAX_PRECISION",
43            precision
44        );
45
46        assert!(
47            scale <= MAX_SCALE,
48            "decimal scale {} exceeds MAX_SCALE",
49            scale
50        );
51
52        Self { precision, scale }
53    }
54
55    /// The precision is the number of significant figures that the decimal tracks.
56    pub fn precision(&self) -> u8 {
57        self.precision
58    }
59
60    /// The scale is the maximum number of digits relative to the decimal point.
61    ///
62    /// Positive scale means digits after decimal point, negative scale means number of
63    /// zeros before the decimal point.
64    pub fn scale(&self) -> i8 {
65        self.scale
66    }
67
68    /// Return the max number of bits required to fit a decimal with `precision` in.
69    pub fn required_bit_width(&self) -> usize {
70        (self.precision as f32 * 10.0f32.log(2.0))
71            .ceil()
72            .to_usize()
73            .vortex_expect("too many bits required")
74    }
75}
76
77impl Display for DecimalDType {
78    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
79        write!(f, "decimal({},{})", self.precision, self.scale)
80    }
81}
82
83impl TryFrom<&DType> for DecimalDType {
84    type Error = VortexError;
85
86    fn try_from(value: &DType) -> Result<Self, Self::Error> {
87        match value {
88            DType::Decimal(dt, _) => Ok(*dt),
89            _ => vortex_bail!("Cannot convert DType {value} into DecimalType"),
90        }
91    }
92}
93
94impl TryFrom<DType> for DecimalDType {
95    type Error = VortexError;
96
97    fn try_from(value: DType) -> Result<Self, Self::Error> {
98        Self::try_from(&value)
99    }
100}