vortex_scalar/
utf8.rs

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