vortex_vector/decimal/
scalar.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use vortex_dtype::DecimalTypeUpcast;
5use vortex_dtype::NativeDecimalType;
6use vortex_dtype::PrecisionScale;
7use vortex_dtype::i256;
8use vortex_error::VortexExpect;
9
10use crate::Scalar;
11use crate::ScalarOps;
12use crate::VectorMut;
13use crate::VectorMutOps;
14use crate::decimal::DVectorMut;
15
16/// Represents a decimal scalar value.
17#[derive(Clone, Debug)]
18pub enum DecimalScalar {
19    /// 8-bit decimal scalar.
20    D8(DScalar<i8>),
21    /// 16-bit decimal scalar.
22    D16(DScalar<i16>),
23    /// 32-bit decimal scalar.
24    D32(DScalar<i32>),
25    /// 64-bit decimal scalar.
26    D64(DScalar<i64>),
27    /// 128-bit decimal scalar.
28    D128(DScalar<i128>),
29    /// 256-bit decimal scalar.
30    D256(DScalar<i256>),
31}
32
33impl DecimalScalar {
34    /// Returns the precision of the decimal scalar.
35    pub fn precision(&self) -> u8 {
36        match self {
37            DecimalScalar::D8(v) => v.ps.precision(),
38            DecimalScalar::D16(v) => v.ps.precision(),
39            DecimalScalar::D32(v) => v.ps.precision(),
40            DecimalScalar::D64(v) => v.ps.precision(),
41            DecimalScalar::D128(v) => v.ps.precision(),
42            DecimalScalar::D256(v) => v.ps.precision(),
43        }
44    }
45
46    /// Returns the scale of the decimal scalar.
47    pub fn scale(&self) -> i8 {
48        match self {
49            DecimalScalar::D8(v) => v.ps.scale(),
50            DecimalScalar::D16(v) => v.ps.scale(),
51            DecimalScalar::D32(v) => v.ps.scale(),
52            DecimalScalar::D64(v) => v.ps.scale(),
53            DecimalScalar::D128(v) => v.ps.scale(),
54            DecimalScalar::D256(v) => v.ps.scale(),
55        }
56    }
57}
58
59impl ScalarOps for DecimalScalar {
60    fn is_valid(&self) -> bool {
61        match self {
62            DecimalScalar::D8(v) => v.is_valid(),
63            DecimalScalar::D16(v) => v.is_valid(),
64            DecimalScalar::D32(v) => v.is_valid(),
65            DecimalScalar::D64(v) => v.is_valid(),
66            DecimalScalar::D128(v) => v.is_valid(),
67            DecimalScalar::D256(v) => v.is_valid(),
68        }
69    }
70
71    fn mask_validity(&mut self, mask: bool) {
72        match self {
73            DecimalScalar::D8(v) => v.mask_validity(mask),
74            DecimalScalar::D16(v) => v.mask_validity(mask),
75            DecimalScalar::D32(v) => v.mask_validity(mask),
76            DecimalScalar::D64(v) => v.mask_validity(mask),
77            DecimalScalar::D128(v) => v.mask_validity(mask),
78            DecimalScalar::D256(v) => v.mask_validity(mask),
79        }
80    }
81
82    fn repeat(&self, n: usize) -> VectorMut {
83        match self {
84            DecimalScalar::D8(v) => v.repeat(n),
85            DecimalScalar::D16(v) => v.repeat(n),
86            DecimalScalar::D32(v) => v.repeat(n),
87            DecimalScalar::D64(v) => v.repeat(n),
88            DecimalScalar::D128(v) => v.repeat(n),
89            DecimalScalar::D256(v) => v.repeat(n),
90        }
91    }
92}
93
94impl From<DecimalScalar> for Scalar {
95    fn from(val: DecimalScalar) -> Self {
96        Scalar::Decimal(val)
97    }
98}
99
100/// Represents a decimal scalar value with a specific native decimal type.
101#[derive(Clone, Debug, PartialEq, Eq, Hash)]
102pub struct DScalar<D> {
103    ps: PrecisionScale<D>,
104    value: Option<D>,
105}
106
107impl<D: NativeDecimalType> DScalar<D> {
108    /// Creates a new decimal scalar with the given precision/scale and value.
109    ///
110    /// Returns `None` if the value is not valid for the given precision/scale.
111    pub fn maybe_new(ps: PrecisionScale<D>, value: Option<D>) -> Option<Self> {
112        Some(match value {
113            None => Self { ps, value: None },
114            Some(v) => {
115                if !ps.is_valid(v) {
116                    return None;
117                }
118                Self { ps, value: Some(v) }
119            }
120        })
121    }
122
123    /// Creates a new decimal scalar with the given precision/scale and value without validation.
124    ///
125    /// # Safety
126    ///
127    /// The caller must ensure that the value is valid for the given precision/scale.
128    pub unsafe fn new_unchecked(ps: PrecisionScale<D>, value: Option<D>) -> Self {
129        Self { ps, value }
130    }
131
132    /// Returns the value of the decimal scalar, or `None` if the scalar is null.
133    pub fn value(&self) -> Option<D> {
134        self.value
135    }
136}
137
138impl<D: NativeDecimalType> ScalarOps for DScalar<D> {
139    fn is_valid(&self) -> bool {
140        self.value.is_some()
141    }
142
143    fn mask_validity(&mut self, mask: bool) {
144        if !mask {
145            self.value = None;
146        }
147    }
148
149    fn repeat(&self, n: usize) -> VectorMut {
150        let mut vec = DVectorMut::with_capacity(self.ps, n);
151        match &self.value {
152            None => vec.append_nulls(n),
153            Some(v) => vec.try_append_n(*v, n).vortex_expect("known to fit"),
154        }
155        vec.into()
156    }
157}
158
159impl<D: NativeDecimalType> From<DScalar<D>> for Scalar {
160    fn from(value: DScalar<D>) -> Self {
161        Scalar::Decimal(D::upcast(value))
162    }
163}
164
165impl<D: NativeDecimalType> From<DScalar<D>> for DecimalScalar {
166    fn from(value: DScalar<D>) -> Self {
167        D::upcast(value)
168    }
169}
170
171impl DecimalTypeUpcast for DecimalScalar {
172    type Input<T: NativeDecimalType> = DScalar<T>;
173
174    fn from_i8(input: Self::Input<i8>) -> Self {
175        DecimalScalar::D8(input)
176    }
177
178    fn from_i16(input: Self::Input<i16>) -> Self {
179        DecimalScalar::D16(input)
180    }
181
182    fn from_i32(input: Self::Input<i32>) -> Self {
183        DecimalScalar::D32(input)
184    }
185
186    fn from_i64(input: Self::Input<i64>) -> Self {
187        DecimalScalar::D64(input)
188    }
189
190    fn from_i128(input: Self::Input<i128>) -> Self {
191        DecimalScalar::D128(input)
192    }
193
194    fn from_i256(input: Self::Input<i256>) -> Self {
195        DecimalScalar::D256(input)
196    }
197}