vortex_scalar/
binary.rs

1use std::fmt::{Display, Formatter};
2use std::sync::Arc;
3
4use itertools::Itertools;
5use vortex_buffer::ByteBuffer;
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 BinaryScalar<'a> {
13    dtype: &'a DType,
14    value: Option<ByteBuffer>,
15}
16
17impl Display for BinaryScalar<'_> {
18    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
19        match &self.value {
20            None => write!(f, "null"),
21            Some(v) => write!(
22                f,
23                "\"{}\"",
24                v.as_slice().iter().map(|b| format!("{b:x}")).format(" ")
25            ),
26        }
27    }
28}
29
30impl PartialEq for BinaryScalar<'_> {
31    fn eq(&self, other: &Self) -> bool {
32        self.dtype.eq_ignore_nullability(other.dtype) && self.value == other.value
33    }
34}
35
36impl Eq for BinaryScalar<'_> {}
37
38impl PartialOrd for BinaryScalar<'_> {
39    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
40        Some(self.value.cmp(&other.value))
41    }
42}
43
44impl Ord for BinaryScalar<'_> {
45    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
46        self.value.cmp(&other.value)
47    }
48}
49
50impl<'a> BinaryScalar<'a> {
51    #[inline]
52    pub fn dtype(&self) -> &'a DType {
53        self.dtype
54    }
55
56    pub fn value(&self) -> Option<ByteBuffer> {
57        self.value.as_ref().cloned()
58    }
59
60    pub(crate) fn cast(&self, dtype: &DType) -> VortexResult<Scalar> {
61        if !matches!(dtype, DType::Binary(..)) {
62            vortex_bail!("Can't cast binary to {}", dtype)
63        }
64        Ok(Scalar::new(
65            dtype.clone(),
66            ScalarValue(InnerScalarValue::Buffer(Arc::new(
67                self.value
68                    .as_ref()
69                    .vortex_expect("nullness handled in Scalar::cast")
70                    .clone(),
71            ))),
72        ))
73    }
74
75    /// Returns whether its value is non-null and empty, otherwise `None`.
76    pub fn is_empty(&self) -> Option<bool> {
77        self.value.as_ref().map(|v| v.is_empty())
78    }
79}
80
81impl Scalar {
82    pub fn binary(buffer: impl Into<Arc<ByteBuffer>>, nullability: Nullability) -> Self {
83        Self {
84            dtype: DType::Binary(nullability),
85            value: ScalarValue(InnerScalarValue::Buffer(buffer.into())),
86        }
87    }
88}
89
90impl<'a> TryFrom<&'a Scalar> for BinaryScalar<'a> {
91    type Error = VortexError;
92
93    fn try_from(value: &'a Scalar) -> Result<Self, Self::Error> {
94        if !matches!(value.dtype(), DType::Binary(_)) {
95            vortex_bail!("Expected binary scalar, found {}", value.dtype())
96        }
97        Ok(Self {
98            dtype: value.dtype(),
99            value: value.value.as_buffer()?,
100        })
101    }
102}
103
104impl<'a> TryFrom<&'a Scalar> for ByteBuffer {
105    type Error = VortexError;
106
107    fn try_from(scalar: &'a Scalar) -> VortexResult<Self> {
108        let binary = scalar
109            .as_binary_opt()
110            .ok_or_else(|| vortex_err!("Cannot extract buffer from non-buffer scalar"))?;
111
112        binary
113            .value()
114            .ok_or_else(|| vortex_err!("Cannot extract present value from null scalar"))
115    }
116}
117
118impl<'a> TryFrom<&'a Scalar> for Option<ByteBuffer> {
119    type Error = VortexError;
120
121    fn try_from(scalar: &'a Scalar) -> VortexResult<Self> {
122        Ok(scalar
123            .as_binary_opt()
124            .ok_or_else(|| vortex_err!("Cannot extract buffer from non-buffer scalar"))?
125            .value())
126    }
127}
128
129impl TryFrom<Scalar> for ByteBuffer {
130    type Error = VortexError;
131
132    fn try_from(scalar: Scalar) -> VortexResult<Self> {
133        Self::try_from(&scalar)
134    }
135}
136
137impl TryFrom<Scalar> for Option<ByteBuffer> {
138    type Error = VortexError;
139
140    fn try_from(scalar: Scalar) -> VortexResult<Self> {
141        Self::try_from(&scalar)
142    }
143}
144
145impl From<&[u8]> for Scalar {
146    fn from(value: &[u8]) -> Self {
147        Scalar::from(ByteBuffer::from(value.to_vec()))
148    }
149}
150
151impl From<ByteBuffer> for Scalar {
152    fn from(value: ByteBuffer) -> Self {
153        Self {
154            dtype: DType::Binary(Nullability::NonNullable),
155            value: ScalarValue(InnerScalarValue::Buffer(Arc::new(value))),
156        }
157    }
158}
159
160impl From<Arc<ByteBuffer>> for Scalar {
161    fn from(value: Arc<ByteBuffer>) -> Self {
162        Self {
163            dtype: DType::Binary(Nullability::NonNullable),
164            value: ScalarValue(InnerScalarValue::Buffer(value)),
165        }
166    }
167}