use std::marker::PhantomData;
use arrow::array::{Array, ArrayRef, RunArray};
use arrow::datatypes::{DataType, Field};
use crate::datatype::{ColumnError, LogicalType, RefType, downcast_array};
pub struct Run<R, V> {
_marker: PhantomData<fn() -> (R, V)>,
}
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be used as a run-end index type",
label = "run-end indices must be one of `i16`, `i32`, `i64`"
)]
pub trait RunEndType: crate::ConcreteType {
type ArrowRunType: arrow::datatypes::RunEndIndexType;
}
macro_rules! impl_run_end_type {
($rust:ty, $arrow:ty) => {
impl RunEndType for $rust {
type ArrowRunType = $arrow;
}
};
}
impl_run_end_type!(i16, arrow::datatypes::Int16Type);
impl_run_end_type!(i32, arrow::datatypes::Int32Type);
impl_run_end_type!(i64, arrow::datatypes::Int64Type);
pub struct TypedRun<R: RunEndType, V: LogicalType> {
run: RunArray<R::ArrowRunType>,
values: V::Typed,
}
impl<R: RunEndType, V: LogicalType> Clone for TypedRun<R, V> {
fn clone(&self) -> Self {
Self {
run: self.run.clone(),
values: self.values.clone(),
}
}
}
impl<R: RunEndType + 'static, V: LogicalType + 'static> LogicalType for Run<R, V> {
type Typed = TypedRun<R, V>;
type Value<'a> = V::Value<'a>;
type Owned = V::Owned;
fn downcast(array: &dyn Array) -> Result<Self::Typed, ColumnError> {
let run = downcast_array::<RunArray<R::ArrowRunType>>(array, || {
format!("RunEndEncoded({:?}, …)", R::datatype())
})?;
if !V::NULLABLE {
let null_count = run.logical_nulls().map_or(0, |nulls| nulls.null_count());
if 0 < null_count {
return Err(ColumnError::UnexpectedNulls { null_count });
}
}
let values = V::downcast(&**run.values())?;
Ok(TypedRun { run, values })
}
#[inline]
fn is_null(typed: &Self::Typed, index: usize) -> bool {
let physical = typed.run.get_physical_index(index);
V::is_null(&typed.values, physical)
}
#[inline]
unsafe fn is_null_unchecked(typed: &Self::Typed, index: usize) -> bool {
let physical = typed.run.get_physical_index(index);
unsafe { V::is_null_unchecked(&typed.values, physical) }
}
#[inline]
fn value(typed: &Self::Typed, index: usize) -> Self::Value<'_> {
let physical = typed.run.get_physical_index(index);
V::value(&typed.values, physical)
}
#[inline]
unsafe fn value_unchecked(typed: &Self::Typed, index: usize) -> Self::Value<'_> {
let physical = typed.run.get_physical_index(index);
unsafe { V::value_unchecked(&typed.values, physical) }
}
fn to_owned_value(value: Self::Value<'_>) -> Self::Owned {
V::to_owned_value(value)
}
}
impl<R: RunEndType + 'static, V: crate::ConcreteType + 'static> crate::ConcreteType for Run<R, V> {
fn datatype() -> DataType {
DataType::RunEndEncoded(
std::sync::Arc::new(Field::new("run_ends", R::datatype(), false)),
std::sync::Arc::new(Field::new("values", V::datatype(), V::NULLABLE)),
)
}
fn build(values: impl Iterator<Item = Option<Self::Owned>>) -> Result<ArrayRef, ColumnError> {
let plain = V::build(values)?;
arrow::compute::cast(&plain, &Self::datatype()).map_err(ColumnError::Build)
}
}
impl<R: RunEndType + 'static, V: RefType + 'static> RefType for Run<R, V> {
type Ref = V::Ref;
fn value_ref(typed: &Self::Typed, index: usize) -> &Self::Ref {
let physical = typed.run.get_physical_index(index);
V::value_ref(&typed.values, physical)
}
}
impl<R, V, T> TryFrom<Vec<T>> for crate::Column<Run<R, V>>
where
R: RunEndType + 'static,
V: crate::ConcreteType + 'static,
T: Into<V::Owned>,
{
type Error = ColumnError;
fn try_from(values: Vec<T>) -> Result<Self, Self::Error> {
Self::try_from_values(values)
}
}