|
11 | 11 | //! |
12 | 12 | //! All three are markers: the owned values are `String`s, and reading is |
13 | 13 | //! zero-copy — the element values are `&str` borrows into the array. |
| 14 | +//! |
| 15 | +//! [`AnyUtf8`] accepts *any* of those three encodings (they all read as `&str`), |
| 16 | +//! for when the encoding is decided at runtime. |
14 | 17 |
|
15 | 18 | use arrow::array::{Array, ArrayRef}; |
16 | 19 | use arrow::datatypes::DataType; |
17 | 20 |
|
18 | | -use crate::datatype::{ColumnError, LogicalType, RefType, impl_marker_datatype}; |
| 21 | +use crate::datatype::{ColumnError, LogicalType, RefType, downcast_array, impl_marker_datatype}; |
19 | 22 |
|
20 | 23 | /// UTF-8 text: an arrow [`DataType::Utf8`] column with `String` values. |
21 | 24 | /// |
@@ -103,3 +106,89 @@ impl RefType for Utf8View { |
103 | 106 | typed.value(index) |
104 | 107 | } |
105 | 108 | } |
| 109 | + |
| 110 | +/// Marker for a UTF-8 column in *any* of arrow's string encodings. |
| 111 | +/// |
| 112 | +/// Accepts [`Utf8`], [`LargeUtf8`], or [`Utf8View`] — they all read as `&str`. |
| 113 | +/// |
| 114 | +/// Like [`AnyList`](crate::AnyList), this is a quiver-only logical type with no |
| 115 | +/// single arrow datatype: `Column<AnyUtf8>` accepts whichever encoding it is |
| 116 | +/// handed and reads them all uniformly. It is *parse-only* — it implements |
| 117 | +/// [`LogicalType`] (so `try_from`/reading work) but not |
| 118 | +/// [`ConcreteType`](crate::ConcreteType), so there is no `from_values`/`Default`/ |
| 119 | +/// schema; to build, pick a concrete encoding such as `Column<Utf8>`. |
| 120 | +/// |
| 121 | +/// ``` |
| 122 | +/// use quiver::{AnyUtf8, Column}; |
| 123 | +/// use quiver::arrow::array::{ArrayRef, LargeStringArray}; |
| 124 | +/// # use std::sync::Arc; |
| 125 | +/// |
| 126 | +/// // `array` may be a Utf8 / LargeUtf8 / Utf8View: |
| 127 | +/// let array: ArrayRef = Arc::new(LargeStringArray::from(vec!["alice", "bob"])); |
| 128 | +/// let column = Column::<AnyUtf8>::try_from(array).unwrap(); |
| 129 | +/// assert_eq!(column.value(0), "alice"); |
| 130 | +/// ``` |
| 131 | +/// |
| 132 | +/// This type is never instantiated — it only appears as a type parameter. |
| 133 | +pub struct AnyUtf8; |
| 134 | + |
| 135 | +/// The validated representation of an [`AnyUtf8`] column: one of the |
| 136 | +/// per-encoding string arrays. |
| 137 | +#[derive(Clone)] |
| 138 | +pub enum AnyTypedUtf8 { |
| 139 | + Utf8(arrow::array::StringArray), |
| 140 | + LargeUtf8(arrow::array::LargeStringArray), |
| 141 | + Utf8View(arrow::array::StringViewArray), |
| 142 | +} |
| 143 | + |
| 144 | +impl LogicalType for AnyUtf8 { |
| 145 | + type Typed = AnyTypedUtf8; |
| 146 | + type Value<'a> = &'a str; |
| 147 | + type Owned = String; |
| 148 | + |
| 149 | + fn downcast(array: &dyn Array) -> Result<Self::Typed, ColumnError> { |
| 150 | + match array.data_type() { |
| 151 | + DataType::Utf8 => Ok(AnyTypedUtf8::Utf8(downcast_array(array, || { |
| 152 | + "Utf8".to_owned() |
| 153 | + })?)), |
| 154 | + DataType::LargeUtf8 => Ok(AnyTypedUtf8::LargeUtf8(downcast_array(array, || { |
| 155 | + "LargeUtf8".to_owned() |
| 156 | + })?)), |
| 157 | + DataType::Utf8View => Ok(AnyTypedUtf8::Utf8View(downcast_array(array, || { |
| 158 | + "Utf8View".to_owned() |
| 159 | + })?)), |
| 160 | + actual => Err(ColumnError::WrongDatatype { |
| 161 | + expected: "a string array (Utf8/LargeUtf8/Utf8View)".to_owned(), |
| 162 | + actual: actual.clone(), |
| 163 | + }), |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + fn is_null(typed: &Self::Typed, index: usize) -> bool { |
| 168 | + match typed { |
| 169 | + AnyTypedUtf8::Utf8(array) => array.is_null(index), |
| 170 | + AnyTypedUtf8::LargeUtf8(array) => array.is_null(index), |
| 171 | + AnyTypedUtf8::Utf8View(array) => array.is_null(index), |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + fn value(typed: &Self::Typed, index: usize) -> Self::Value<'_> { |
| 176 | + match typed { |
| 177 | + AnyTypedUtf8::Utf8(array) => array.value(index), |
| 178 | + AnyTypedUtf8::LargeUtf8(array) => array.value(index), |
| 179 | + AnyTypedUtf8::Utf8View(array) => array.value(index), |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + fn to_owned_value(value: Self::Value<'_>) -> Self::Owned { |
| 184 | + value.to_owned() |
| 185 | + } |
| 186 | +} |
| 187 | + |
| 188 | +impl RefType for AnyUtf8 { |
| 189 | + type Ref = str; |
| 190 | + |
| 191 | + fn value_ref(typed: &Self::Typed, index: usize) -> &str { |
| 192 | + Self::value(typed, index) |
| 193 | + } |
| 194 | +} |
0 commit comments