use crate::data::types::{PhysicalType, PrimitiveType};
use crate::data::ArrayDataLayout;
use crate::{ArrayDataBuilder, Buffers};
use arrow_buffer::buffer::{NullBuffer, ScalarBuffer};
use arrow_buffer::{i256, ArrowNativeType};
use arrow_schema::DataType;
use half::f16;
mod private {
use super::*;
pub trait PrimitiveSealed {
fn downcast_ref(data: &ArrayDataPrimitive) -> Option<&PrimitiveArrayData<Self>>
where
Self: Primitive;
fn downcast(data: ArrayDataPrimitive) -> Option<PrimitiveArrayData<Self>>
where
Self: Primitive;
fn upcast(v: PrimitiveArrayData<Self>) -> ArrayDataPrimitive
where
Self: Primitive;
}
}
pub trait Primitive: private::PrimitiveSealed + ArrowNativeType {
const TYPE: PrimitiveType;
}
macro_rules! primitive_op {
($array:ident, $op:block) => {
match $array {
ArrayDataPrimitive::Int8($array) => $op
ArrayDataPrimitive::Int16($array) => $op
ArrayDataPrimitive::Int32($array) => $op
ArrayDataPrimitive::Int64($array) => $op
ArrayDataPrimitive::Int128($array) => $op
ArrayDataPrimitive::Int256($array) => $op
ArrayDataPrimitive::UInt8($array) => $op
ArrayDataPrimitive::UInt16($array) => $op
ArrayDataPrimitive::UInt32($array) => $op
ArrayDataPrimitive::UInt64($array) => $op
ArrayDataPrimitive::Float16($array) => $op
ArrayDataPrimitive::Float32($array) => $op
ArrayDataPrimitive::Float64($array) => $op
}
};
}
macro_rules! primitive {
($t:ty,$v:ident) => {
impl Primitive for $t {
const TYPE: PrimitiveType = PrimitiveType::$v;
}
impl private::PrimitiveSealed for $t {
fn downcast_ref(
data: &ArrayDataPrimitive,
) -> Option<&PrimitiveArrayData<Self>> {
match data {
ArrayDataPrimitive::$v(v) => Some(v),
_ => None,
}
}
fn downcast(data: ArrayDataPrimitive) -> Option<PrimitiveArrayData<Self>> {
match data {
ArrayDataPrimitive::$v(v) => Some(v),
_ => None,
}
}
fn upcast(v: PrimitiveArrayData<Self>) -> ArrayDataPrimitive {
ArrayDataPrimitive::$v(v)
}
}
};
}
primitive!(i8, Int8);
primitive!(i16, Int16);
primitive!(i32, Int32);
primitive!(i64, Int64);
primitive!(i128, Int128);
primitive!(i256, Int256);
primitive!(u8, UInt8);
primitive!(u16, UInt16);
primitive!(u32, UInt32);
primitive!(u64, UInt64);
primitive!(f16, Float16);
primitive!(f32, Float32);
primitive!(f64, Float64);
#[derive(Debug, Clone)]
pub enum ArrayDataPrimitive {
Int8(PrimitiveArrayData<i8>),
Int16(PrimitiveArrayData<i16>),
Int32(PrimitiveArrayData<i32>),
Int64(PrimitiveArrayData<i64>),
Int128(PrimitiveArrayData<i128>),
Int256(PrimitiveArrayData<i256>),
UInt8(PrimitiveArrayData<u8>),
UInt16(PrimitiveArrayData<u16>),
UInt32(PrimitiveArrayData<u32>),
UInt64(PrimitiveArrayData<u64>),
Float16(PrimitiveArrayData<f16>),
Float32(PrimitiveArrayData<f32>),
Float64(PrimitiveArrayData<f64>),
}
impl ArrayDataPrimitive {
pub fn downcast_ref<P: Primitive>(&self) -> Option<&PrimitiveArrayData<P>> {
P::downcast_ref(self)
}
pub fn downcast<P: Primitive>(self) -> Option<PrimitiveArrayData<P>> {
P::downcast(self)
}
pub fn slice(&self, offset: usize, len: usize) -> Self {
let s = self;
primitive_op!(s, { s.slice(offset, len).into() })
}
pub(crate) fn layout(&self) -> ArrayDataLayout<'_> {
let s = self;
primitive_op!(s, { s.layout() })
}
pub(crate) unsafe fn from_raw(
builder: ArrayDataBuilder,
primitive: PrimitiveType,
) -> Self {
use PrimitiveType::*;
match primitive {
Int8 => Self::Int8(PrimitiveArrayData::from_raw(builder)),
Int16 => Self::Int16(PrimitiveArrayData::from_raw(builder)),
Int32 => Self::Int32(PrimitiveArrayData::from_raw(builder)),
Int64 => Self::Int64(PrimitiveArrayData::from_raw(builder)),
Int128 => Self::Int128(PrimitiveArrayData::from_raw(builder)),
Int256 => Self::Int256(PrimitiveArrayData::from_raw(builder)),
UInt8 => Self::UInt8(PrimitiveArrayData::from_raw(builder)),
UInt16 => Self::UInt16(PrimitiveArrayData::from_raw(builder)),
UInt32 => Self::UInt32(PrimitiveArrayData::from_raw(builder)),
UInt64 => Self::UInt64(PrimitiveArrayData::from_raw(builder)),
Float16 => Self::Float16(PrimitiveArrayData::from_raw(builder)),
Float32 => Self::Float32(PrimitiveArrayData::from_raw(builder)),
Float64 => Self::Float64(PrimitiveArrayData::from_raw(builder)),
}
}
}
impl<P: Primitive> From<PrimitiveArrayData<P>> for ArrayDataPrimitive {
fn from(value: PrimitiveArrayData<P>) -> Self {
P::upcast(value)
}
}
#[derive(Debug, Clone)]
pub struct PrimitiveArrayData<T: Primitive> {
data_type: DataType,
values: ScalarBuffer<T>,
nulls: Option<NullBuffer>,
}
impl<T: Primitive> PrimitiveArrayData<T> {
pub fn new(
data_type: DataType,
values: ScalarBuffer<T>,
nulls: Option<NullBuffer>,
) -> Self {
assert_eq!(
PhysicalType::from(&data_type),
PhysicalType::Primitive(T::TYPE),
"Illegal physical type for PrimitiveArrayData of datatype {data_type:?}",
);
if let Some(n) = nulls.as_ref() {
assert_eq!(values.len(), n.len())
}
Self {
data_type,
values,
nulls,
}
}
pub unsafe fn new_unchecked(
data_type: DataType,
values: ScalarBuffer<T>,
nulls: Option<NullBuffer>,
) -> Self {
Self {
data_type,
values,
nulls,
}
}
pub(crate) unsafe fn from_raw(builder: ArrayDataBuilder) -> Self {
let values = builder.buffers.into_iter().next().unwrap();
let values = ScalarBuffer::new(values, builder.offset, builder.len);
Self {
values,
data_type: builder.data_type,
nulls: builder.nulls,
}
}
#[inline]
pub fn nulls(&self) -> Option<&NullBuffer> {
self.nulls.as_ref()
}
#[inline]
pub fn values(&self) -> &ScalarBuffer<T> {
&self.values
}
#[inline]
pub fn data_type(&self) -> &DataType {
&self.data_type
}
pub fn into_parts(self) -> (DataType, ScalarBuffer<T>, Option<NullBuffer>) {
(self.data_type, self.values, self.nulls)
}
pub fn slice(&self, offset: usize, len: usize) -> Self {
Self {
data_type: self.data_type.clone(),
values: self.values.slice(offset, len),
nulls: self.nulls.as_ref().map(|x| x.slice(offset, len)),
}
}
pub(crate) fn layout(&self) -> ArrayDataLayout<'_> {
ArrayDataLayout {
data_type: &self.data_type,
len: self.values.len(),
offset: 0,
nulls: self.nulls.as_ref(),
buffers: Buffers::one(self.values.inner()),
child_data: &[],
}
}
}