Skip to main content

vortex_array/scalar/convert/
primitive.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! Conversions for [`PrimitiveScalar`]s.
5
6use vortex_error::VortexError;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_err;
10
11use crate::dtype::DType;
12use crate::dtype::NativePType;
13use crate::dtype::Nullability;
14use crate::dtype::PType;
15use crate::dtype::half::f16;
16use crate::scalar::PValue;
17use crate::scalar::PrimitiveScalar;
18use crate::scalar::Scalar;
19use crate::scalar::ScalarValue;
20
21// TODO(connor): Ideally we remove this.
22impl From<PrimitiveScalar<'_>> for Scalar {
23    fn from(ps: PrimitiveScalar<'_>) -> Self {
24        // SAFETY: `PrimitiveScalar` is already a valid `Scalar`.
25        unsafe {
26            Scalar::new_unchecked(ps.dtype().clone(), ps.pvalue().map(ScalarValue::Primitive))
27        }
28    }
29}
30
31impl From<PValue> for ScalarValue {
32    fn from(value: PValue) -> Self {
33        ScalarValue::Primitive(value)
34    }
35}
36
37/// Implements scalar conversions for a primitive type.
38macro_rules! primitive_scalar {
39    ($T:ty) => {
40        ////////////////////////////////////////////////////////////////////////////////////////////
41        // `Scalar` INTO $T conversions.
42        ////////////////////////////////////////////////////////////////////////////////////////////
43
44        /// Fallible conversion from a [`ScalarValue`] into an `T`.
45        ///
46        /// # Errors
47        ///
48        /// Returns an error if unable to convert the scalar value into the target type,
49        impl TryFrom<&ScalarValue> for $T {
50            type Error = VortexError;
51
52            fn try_from(value: &ScalarValue) -> VortexResult<Self> {
53                value.as_primitive().cast::<$T>()
54            }
55        }
56
57        /// Fallible conversion from a [`Scalar`] into an `T`.
58        ///
59        /// # Errors
60        ///
61        /// Returns an error if unable to convert the scalar into the target type, or if the
62        /// `Scalar` itself is null.
63        impl TryFrom<&Scalar> for $T {
64            type Error = VortexError;
65
66            fn try_from(value: &Scalar) -> VortexResult<Self> {
67                match value.value() {
68                    Some(ScalarValue::Primitive(pv)) => pv.cast::<$T>(),
69                    Some(_) => Err(vortex_err!(
70                        "Expected primitive scalar, found {}",
71                        value.dtype()
72                    )),
73                    None => Err(vortex_err!("Can't extract present value from null scalar")),
74                }
75            }
76        }
77
78        /// Fallible conversion from a [`Scalar`] into an `Option<T>`.
79        ///
80        /// # Errors
81        ///
82        /// Returns an error if the [`Scalar`] is not primitive, or if it is unable to convert the
83        /// [`Scalar`] into the target type.
84        impl TryFrom<&Scalar> for Option<$T> {
85            type Error = VortexError;
86
87            fn try_from(value: &Scalar) -> VortexResult<Self> {
88                let primitive_scalar = PrimitiveScalar::try_new(value.dtype(), value.value())?;
89                primitive_scalar.try_typed_value::<$T>()
90            }
91        }
92
93        ////////////////////////////////////////////////////////////////////////////////////////////
94        // `Scalar` FROM $T conversions.
95        ////////////////////////////////////////////////////////////////////////////////////////////
96
97        /// `Into<ScalarValue>` for T.
98        impl From<$T> for ScalarValue {
99            fn from(value: $T) -> Self {
100                ScalarValue::Primitive(value.into())
101            }
102        }
103
104        /// Non-nullable `Into<Scalar>` implementation for T.
105        impl From<$T> for Scalar {
106            fn from(value: $T) -> Self {
107                Scalar::try_new(
108                    DType::Primitive(<$T>::PTYPE, Nullability::NonNullable),
109                    Some(ScalarValue::Primitive(value.into())),
110                )
111                .vortex_expect(
112                    "somehow unable to construct a primitive `Scalar` from a native type",
113                )
114            }
115        }
116
117        /// Nullable `Into<Scalar>` implementation for T.
118        impl From<Option<$T>> for Scalar {
119            fn from(value: Option<$T>) -> Self {
120                Scalar::try_new(
121                    DType::Primitive(<$T>::PTYPE, Nullability::Nullable),
122                    value.map(|value| ScalarValue::Primitive(value.into())),
123                )
124                .vortex_expect(
125                    "somehow unable to construct a primitive `Scalar` from a native type",
126                )
127            }
128        }
129    };
130}
131
132primitive_scalar!(u8);
133primitive_scalar!(u16);
134primitive_scalar!(u32);
135primitive_scalar!(u64);
136
137primitive_scalar!(i8);
138primitive_scalar!(i16);
139primitive_scalar!(i32);
140primitive_scalar!(i64);
141
142primitive_scalar!(f16);
143primitive_scalar!(f32);
144primitive_scalar!(f64);
145
146////////////////////////////////////////////////////////////////////////////////////////////
147// `Scalar` <---> `usize` conversions.
148////////////////////////////////////////////////////////////////////////////////////////////
149
150// NB: We cast `usize` to `u64` (which should always succeed) for better ergonomics.
151
152/// Fallible conversion from a [`ScalarValue`] into an `T`.
153///
154/// # Errors
155///
156/// Returns an error if unable to convert the scalar value into the target type,
157impl TryFrom<&ScalarValue> for usize {
158    type Error = VortexError;
159
160    fn try_from(value: &ScalarValue) -> VortexResult<Self> {
161        let val = value.as_primitive().cast::<u64>()?;
162        Ok(usize::try_from(val)?)
163    }
164}
165
166impl TryFrom<&Scalar> for usize {
167    type Error = VortexError;
168
169    fn try_from(value: &Scalar) -> Result<Self, Self::Error> {
170        let prim_scalar = value
171            .as_primitive_opt()
172            .ok_or_else(|| vortex_err!("Expected primitive scalar, found {}", value.dtype()))?;
173
174        let prim = prim_scalar
175            .as_::<u64>()
176            .ok_or_else(|| vortex_err!("cannot convert Null to usize"))?;
177
178        Ok(usize::try_from(prim)?)
179    }
180}
181
182impl TryFrom<&Scalar> for Option<usize> {
183    type Error = VortexError;
184
185    fn try_from(value: &Scalar) -> Result<Self, Self::Error> {
186        let prim_scalar = value
187            .as_primitive_opt()
188            .ok_or_else(|| vortex_err!("Expected primitive scalar, found {}", value.dtype()))?;
189
190        Ok(prim_scalar.as_::<u64>().map(usize::try_from).transpose()?)
191    }
192}
193
194impl From<usize> for ScalarValue {
195    fn from(value: usize) -> Self {
196        ScalarValue::Primitive((value as u64).into())
197    }
198}
199
200impl From<usize> for Scalar {
201    fn from(value: usize) -> Self {
202        Scalar::try_new(
203            DType::Primitive(PType::U64, Nullability::NonNullable),
204            Some(ScalarValue::Primitive((value as u64).into())),
205        )
206        .vortex_expect("somehow unable to construct a primitive `Scalar` from a native type")
207    }
208}
209
210impl From<Option<usize>> for Scalar {
211    fn from(value: Option<usize>) -> Self {
212        Scalar::try_new(
213            DType::Primitive(PType::U64, Nullability::Nullable),
214            value.map(|value| ScalarValue::Primitive((value as u64).into())),
215        )
216        .vortex_expect("somehow unable to construct a primitive `Scalar` from a native type")
217    }
218}