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 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}