Skip to main content

vortex_array/scalar/convert/
decimal.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! Conversions for [`DecimalScalar`]s.
5
6use vortex_dtype::i256;
7use vortex_error::VortexError;
8use vortex_error::vortex_err;
9
10use crate::scalar::DecimalScalar;
11use crate::scalar::DecimalValue;
12use crate::scalar::Scalar;
13use crate::scalar::ScalarValue;
14
15// TODO(connor): Ideally we remove this.
16impl From<DecimalScalar<'_>> for Scalar {
17    fn from(ds: DecimalScalar<'_>) -> Self {
18        // SAFETY: `DecimalScalar` is already a valid `Scalar`.
19        unsafe {
20            Scalar::new_unchecked(
21                ds.dtype().clone(),
22                ds.decimal_value().map(ScalarValue::Decimal),
23            )
24        }
25    }
26}
27
28/// Implements `TryFrom<DecimalScalar>` for the given type.
29macro_rules! decimal_scalar_unpack {
30    ($T:ident, $arm:ident) => {
31        impl TryFrom<DecimalScalar<'_>> for Option<$T> {
32            type Error = VortexError;
33
34            fn try_from(value: DecimalScalar) -> Result<Self, Self::Error> {
35                Ok(match value.decimal_value() {
36                    None => None,
37                    Some(DecimalValue::$arm(v)) => Some(v),
38                    v => vortex_error::vortex_bail!(
39                        "Cannot extract decimal {:?} as {}",
40                        v,
41                        stringify!($T)
42                    ),
43                })
44            }
45        }
46
47        impl TryFrom<DecimalScalar<'_>> for $T {
48            type Error = VortexError;
49
50            fn try_from(value: DecimalScalar) -> Result<Self, Self::Error> {
51                match value.decimal_value() {
52                    None => vortex_error::vortex_bail!("Cannot extract value from null decimal"),
53                    Some(DecimalValue::$arm(v)) => Ok(v),
54                    v => vortex_error::vortex_bail!(
55                        "Cannot extract decimal {:?} as {}",
56                        v,
57                        stringify!($T)
58                    ),
59                }
60            }
61        }
62    };
63}
64
65/// Implements `Into<DecimalValue>` for the given type.
66macro_rules! decimal_scalar_pack {
67    ($from:ident, $to:ident, $arm:ident) => {
68        impl From<$from> for DecimalValue {
69            fn from(value: $from) -> Self {
70                DecimalValue::$arm(value as $to)
71            }
72        }
73    };
74}
75
76decimal_scalar_unpack!(i8, I8);
77decimal_scalar_unpack!(i16, I16);
78decimal_scalar_unpack!(i32, I32);
79decimal_scalar_unpack!(i64, I64);
80decimal_scalar_unpack!(i128, I128);
81decimal_scalar_unpack!(i256, I256);
82
83decimal_scalar_pack!(i8, i8, I8);
84decimal_scalar_pack!(i16, i16, I16);
85decimal_scalar_pack!(i32, i32, I32);
86decimal_scalar_pack!(i64, i64, I64);
87decimal_scalar_pack!(i128, i128, I128);
88decimal_scalar_pack!(i256, i256, I256);
89
90decimal_scalar_pack!(u8, i16, I16);
91decimal_scalar_pack!(u16, i32, I32);
92decimal_scalar_pack!(u32, i64, I64);
93decimal_scalar_pack!(u64, i128, I128);
94
95impl TryFrom<&Scalar> for DecimalValue {
96    type Error = VortexError;
97
98    fn try_from(scalar: &Scalar) -> Result<Self, Self::Error> {
99        let decimal_scalar = scalar
100            .as_decimal_opt()
101            .ok_or_else(|| vortex_err!("Expected decimal scalar, found {}", scalar.dtype()))?;
102
103        decimal_scalar
104            .decimal_value()
105            .as_ref()
106            .cloned()
107            .ok_or_else(|| vortex_err!("Cannot extract DecimalValue from null decimal"))
108    }
109}
110
111impl TryFrom<Scalar> for DecimalValue {
112    type Error = VortexError;
113
114    fn try_from(scalar: Scalar) -> Result<Self, Self::Error> {
115        DecimalValue::try_from(&scalar)
116    }
117}
118
119impl TryFrom<&Scalar> for Option<DecimalValue> {
120    type Error = VortexError;
121
122    fn try_from(scalar: &Scalar) -> Result<Self, Self::Error> {
123        Ok(scalar
124            .as_decimal_opt()
125            .ok_or_else(|| vortex_err!("Expected decimal scalar, found {}", scalar.dtype()))?
126            .decimal_value())
127    }
128}
129
130impl TryFrom<Scalar> for Option<DecimalValue> {
131    type Error = VortexError;
132
133    fn try_from(scalar: Scalar) -> Result<Self, Self::Error> {
134        Option::<DecimalValue>::try_from(&scalar)
135    }
136}