|
9 | 9 | //! [`arrow::array::BinaryViewArray`] for the newer "view" encoding |
10 | 10 | //! ([`DataType::BinaryView`]), optimized for comparisons and out-of-order writes. |
11 | 11 | //! Reading is zero-copy: the element values are `&[u8]`. |
| 12 | +//! |
| 13 | +//! [`AnyBinary`] accepts *any* binary encoding — these three plus |
| 14 | +//! [`FixedSizeBinary`](crate::FixedSizeBinary) — all read as `&[u8]`, for when |
| 15 | +//! the encoding is decided at runtime. |
12 | 16 |
|
13 | 17 | use arrow::array::{Array, ArrayRef}; |
14 | 18 | use arrow::datatypes::DataType; |
@@ -116,3 +120,102 @@ impl_binary_datatype!( |
116 | 120 | arrow::array::BinaryViewArray, |
117 | 121 | DataType::BinaryView |
118 | 122 | ); |
| 123 | + |
| 124 | +/// Marker for a binary column in *any* of arrow's byte-string encodings. |
| 125 | +/// |
| 126 | +/// Accepts [`Binary`], [`LargeBinary`], [`BinaryView`], or |
| 127 | +/// [`FixedSizeBinary`](crate::FixedSizeBinary) (of any size). They all read as |
| 128 | +/// `&[u8]` — a `FixedSizeBinary<N>`'s fixed-width elements are seen here as |
| 129 | +/// plain `&[u8]` slices (length `N`), not `&[u8; N]`. |
| 130 | +/// |
| 131 | +/// Like [`AnyList`](crate::AnyList), this is a quiver-only logical type with no |
| 132 | +/// single arrow datatype: `Column<AnyBinary>` accepts whichever encoding it is |
| 133 | +/// handed and reads them all uniformly. It is *parse-only* — it implements |
| 134 | +/// [`LogicalType`] (so `try_from`/reading work) but not |
| 135 | +/// [`ConcreteType`](crate::ConcreteType), so there is no `from_values`/`Default`/ |
| 136 | +/// schema; to build, pick a concrete encoding such as `Column<Binary>`. |
| 137 | +/// |
| 138 | +/// ``` |
| 139 | +/// use quiver::{AnyBinary, Column}; |
| 140 | +/// use quiver::arrow::array::{ArrayRef, LargeBinaryArray}; |
| 141 | +/// # use std::sync::Arc; |
| 142 | +/// |
| 143 | +/// // `array` may be a Binary / LargeBinary / BinaryView: |
| 144 | +/// let array: ArrayRef = Arc::new(LargeBinaryArray::from_iter_values([b"abc"])); |
| 145 | +/// let column = Column::<AnyBinary>::try_from(array).unwrap(); |
| 146 | +/// assert_eq!(column.value(0), b"abc"); |
| 147 | +/// ``` |
| 148 | +/// |
| 149 | +/// This type is never instantiated — it only appears as a type parameter. |
| 150 | +pub struct AnyBinary; |
| 151 | + |
| 152 | +/// The validated representation of an [`AnyBinary`] column: one of the |
| 153 | +/// per-encoding binary arrays. |
| 154 | +#[derive(Clone)] |
| 155 | +pub enum AnyTypedBinary { |
| 156 | + Binary(arrow::array::BinaryArray), |
| 157 | + LargeBinary(arrow::array::LargeBinaryArray), |
| 158 | + BinaryView(arrow::array::BinaryViewArray), |
| 159 | + FixedSizeBinary(arrow::array::FixedSizeBinaryArray), |
| 160 | +} |
| 161 | + |
| 162 | +impl LogicalType for AnyBinary { |
| 163 | + type Typed = AnyTypedBinary; |
| 164 | + type Value<'a> = &'a [u8]; |
| 165 | + type Owned = Vec<u8>; |
| 166 | + |
| 167 | + fn downcast(array: &dyn Array) -> Result<Self::Typed, ColumnError> { |
| 168 | + match array.data_type() { |
| 169 | + DataType::Binary => Ok(AnyTypedBinary::Binary(downcast_array(array, || { |
| 170 | + "Binary".to_owned() |
| 171 | + })?)), |
| 172 | + DataType::LargeBinary => { |
| 173 | + Ok(AnyTypedBinary::LargeBinary(downcast_array(array, || { |
| 174 | + "LargeBinary".to_owned() |
| 175 | + })?)) |
| 176 | + } |
| 177 | + DataType::BinaryView => Ok(AnyTypedBinary::BinaryView(downcast_array(array, || { |
| 178 | + "BinaryView".to_owned() |
| 179 | + })?)), |
| 180 | + DataType::FixedSizeBinary(_) => Ok(AnyTypedBinary::FixedSizeBinary(downcast_array( |
| 181 | + array, |
| 182 | + || "FixedSizeBinary".to_owned(), |
| 183 | + )?)), |
| 184 | + actual => Err(ColumnError::WrongDatatype { |
| 185 | + expected: "a binary array (Binary/LargeBinary/BinaryView/FixedSizeBinary)" |
| 186 | + .to_owned(), |
| 187 | + actual: actual.clone(), |
| 188 | + }), |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + fn is_null(typed: &Self::Typed, index: usize) -> bool { |
| 193 | + match typed { |
| 194 | + AnyTypedBinary::Binary(array) => array.is_null(index), |
| 195 | + AnyTypedBinary::LargeBinary(array) => array.is_null(index), |
| 196 | + AnyTypedBinary::BinaryView(array) => array.is_null(index), |
| 197 | + AnyTypedBinary::FixedSizeBinary(array) => array.is_null(index), |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + fn value(typed: &Self::Typed, index: usize) -> Self::Value<'_> { |
| 202 | + match typed { |
| 203 | + AnyTypedBinary::Binary(array) => array.value(index), |
| 204 | + AnyTypedBinary::LargeBinary(array) => array.value(index), |
| 205 | + AnyTypedBinary::BinaryView(array) => array.value(index), |
| 206 | + AnyTypedBinary::FixedSizeBinary(array) => array.value(index), |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + fn to_owned_value(value: Self::Value<'_>) -> Self::Owned { |
| 211 | + value.to_vec() |
| 212 | + } |
| 213 | +} |
| 214 | + |
| 215 | +impl RefType for AnyBinary { |
| 216 | + type Ref = [u8]; |
| 217 | + |
| 218 | + fn value_ref(typed: &Self::Typed, index: usize) -> &[u8] { |
| 219 | + Self::value(typed, index) |
| 220 | + } |
| 221 | +} |
0 commit comments