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