use arrow::array::{Array as _, ArrayRef};
use crate::datatype::{PrimitiveDatatype, RefDatatype};
use crate::{ColumnError, Datatype};
pub(crate) struct TypedArray<L: Datatype> {
array: ArrayRef,
typed: L::Typed,
}
impl<L: Datatype> TypedArray<L> {
pub fn try_new(array: ArrayRef) -> Result<Self, ColumnError> {
let expected = L::datatype();
let actual = array.data_type();
if !crate::datatype::datatypes_compatible(actual, &expected) {
return Err(ColumnError::WrongDatatype {
expected,
actual: actual.clone(),
});
}
if !L::NULLABLE && 0 < array.null_count() {
return Err(ColumnError::UnexpectedNulls {
null_count: array.null_count(),
});
}
let typed = L::downcast(&*array)?;
Ok(Self { array, typed })
}
pub fn len(&self) -> usize {
self.array.len()
}
pub fn is_empty(&self) -> bool {
self.array.is_empty()
}
pub fn get(&self, index: usize) -> Option<L::Value<'_>> {
(index < self.len()).then(|| L::value(&self.typed, index))
}
pub fn value(&self, index: usize) -> L::Value<'_> {
assert!(index < self.len(), "Index {index} out of bounds");
L::value(&self.typed, index)
}
pub fn as_arrow(&self) -> &ArrayRef {
&self.array
}
pub fn into_arrow(self) -> ArrayRef {
self.array
}
}
impl<L: RefDatatype> TypedArray<L> {
pub fn value_ref(&self, index: usize) -> &L::Ref {
assert!(index < self.len(), "Index {index} out of bounds");
L::value_ref(&self.typed, index)
}
}
impl<L: PrimitiveDatatype> TypedArray<L> {
pub fn values(&self) -> &[L::Native] {
L::values(&self.typed)
}
}
impl<L: Datatype> PartialEq for TypedArray<L> {
fn eq(&self, other: &Self) -> bool {
self.array.as_ref() == other.array.as_ref()
}
}
impl<L: Datatype> Clone for TypedArray<L> {
fn clone(&self) -> Self {
Self {
array: ArrayRef::clone(&self.array),
typed: self.typed.clone(),
}
}
}
impl<L: Datatype> std::fmt::Debug for TypedArray<L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TypedArray")
.field("array", &self.array)
.finish_non_exhaustive()
}
}