vortex_scalar/
utf8.rs

1use std::sync::Arc;
2
3use vortex_buffer::BufferString;
4use vortex_dtype::Nullability::NonNullable;
5use vortex_dtype::{DType, Nullability};
6use vortex_error::{VortexError, VortexExpect as _, VortexResult, vortex_bail, vortex_err};
7
8use crate::{InnerScalarValue, Scalar, ScalarValue};
9
10#[derive(Debug, Hash)]
11pub struct Utf8Scalar<'a> {
12    dtype: &'a DType,
13    value: Option<BufferString>,
14}
15
16impl PartialEq for Utf8Scalar<'_> {
17    fn eq(&self, other: &Self) -> bool {
18        self.dtype.eq_ignore_nullability(other.dtype) && self.value == other.value
19    }
20}
21
22impl Eq for Utf8Scalar<'_> {}
23
24impl PartialOrd for Utf8Scalar<'_> {
25    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
26        Some(self.value.cmp(&other.value))
27    }
28}
29
30impl Ord for Utf8Scalar<'_> {
31    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
32        self.value.cmp(&other.value)
33    }
34}
35
36impl<'a> Utf8Scalar<'a> {
37    #[inline]
38    pub fn dtype(&self) -> &'a DType {
39        self.dtype
40    }
41
42    pub fn value(&self) -> Option<BufferString> {
43        self.value.as_ref().cloned()
44    }
45
46    pub(crate) fn cast(&self, dtype: &DType) -> VortexResult<Scalar> {
47        if !matches!(dtype, DType::Utf8(..)) {
48            vortex_bail!("Can't cast utf8 to {}", dtype)
49        }
50        Ok(Scalar::new(
51            dtype.clone(),
52            ScalarValue(InnerScalarValue::BufferString(Arc::new(
53                self.value
54                    .as_ref()
55                    .vortex_expect("nullness handled in Scalar::cast")
56                    .clone(),
57            ))),
58        ))
59    }
60
61    /// Returns whether its value is non-null and empty, otherwise `None`.
62    pub fn is_empty(&self) -> Option<bool> {
63        self.value.as_ref().map(|v| v.is_empty())
64    }
65}
66
67impl Scalar {
68    pub fn utf8<B>(str: B, nullability: Nullability) -> Self
69    where
70        B: Into<BufferString>,
71    {
72        Self::try_utf8(str, nullability).unwrap()
73    }
74
75    pub fn try_utf8<B>(
76        str: B,
77        nullability: Nullability,
78    ) -> Result<Self, <B as TryInto<BufferString>>::Error>
79    where
80        B: TryInto<BufferString>,
81    {
82        Ok(Self {
83            dtype: DType::Utf8(nullability),
84            value: ScalarValue(InnerScalarValue::BufferString(Arc::new(str.try_into()?))),
85        })
86    }
87}
88
89impl<'a> TryFrom<&'a Scalar> for Utf8Scalar<'a> {
90    type Error = VortexError;
91
92    fn try_from(value: &'a Scalar) -> Result<Self, Self::Error> {
93        if !matches!(value.dtype(), DType::Utf8(_)) {
94            vortex_bail!("Expected utf8 scalar, found {}", value.dtype())
95        }
96        Ok(Self {
97            dtype: value.dtype(),
98            value: value.value.as_buffer_string()?,
99        })
100    }
101}
102
103impl<'a> TryFrom<&'a Scalar> for String {
104    type Error = VortexError;
105
106    fn try_from(value: &'a Scalar) -> Result<Self, Self::Error> {
107        Ok(BufferString::try_from(value)?.to_string())
108    }
109}
110
111impl From<&str> for Scalar {
112    fn from(value: &str) -> Self {
113        Self {
114            dtype: DType::Utf8(NonNullable),
115            value: ScalarValue(InnerScalarValue::BufferString(Arc::new(
116                value.to_string().into(),
117            ))),
118        }
119    }
120}
121
122impl From<String> for Scalar {
123    fn from(value: String) -> Self {
124        Self {
125            dtype: DType::Utf8(NonNullable),
126            value: ScalarValue(InnerScalarValue::BufferString(Arc::new(value.into()))),
127        }
128    }
129}
130
131impl From<BufferString> for Scalar {
132    fn from(value: BufferString) -> Self {
133        Self {
134            dtype: DType::Utf8(NonNullable),
135            value: ScalarValue(InnerScalarValue::BufferString(Arc::new(value))),
136        }
137    }
138}
139
140impl From<Arc<BufferString>> for Scalar {
141    fn from(value: Arc<BufferString>) -> Self {
142        Self {
143            dtype: DType::Utf8(NonNullable),
144            value: ScalarValue(InnerScalarValue::BufferString(value)),
145        }
146    }
147}
148
149impl<'a> TryFrom<&'a Scalar> for BufferString {
150    type Error = VortexError;
151
152    fn try_from(scalar: &'a Scalar) -> VortexResult<Self> {
153        <Option<BufferString>>::try_from(scalar)?
154            .ok_or_else(|| vortex_err!("Can't extract present value from null scalar"))
155    }
156}
157
158impl TryFrom<Scalar> for BufferString {
159    type Error = VortexError;
160
161    fn try_from(scalar: Scalar) -> Result<Self, Self::Error> {
162        Self::try_from(&scalar)
163    }
164}
165
166impl<'a> TryFrom<&'a Scalar> for Option<BufferString> {
167    type Error = VortexError;
168
169    fn try_from(scalar: &'a Scalar) -> Result<Self, Self::Error> {
170        Ok(Utf8Scalar::try_from(scalar)?.value())
171    }
172}
173
174impl TryFrom<Scalar> for Option<BufferString> {
175    type Error = VortexError;
176
177    fn try_from(scalar: Scalar) -> Result<Self, Self::Error> {
178        Self::try_from(&scalar)
179    }
180}