diff --git a/vortex-array2/src/array/bool/compute/as_contiguous.rs b/vortex-array2/src/array/bool/compute/as_contiguous.rs index c6f1c85715..bc2ecae0a6 100644 --- a/vortex-array2/src/array/bool/compute/as_contiguous.rs +++ b/vortex-array2/src/array/bool/compute/as_contiguous.rs @@ -4,7 +4,7 @@ use vortex_error::VortexResult; use crate::array::bool::BoolArray; use crate::compute::as_contiguous::AsContiguousFn; use crate::validity::Validity; -use crate::{Array, ArrayTrait, IntoArray}; +use crate::{Array, IntoArray}; impl AsContiguousFn for BoolArray<'_> { fn as_contiguous(&self, arrays: &[Array]) -> VortexResult> { diff --git a/vortex-array2/src/array/bool/compute/fill.rs b/vortex-array2/src/array/bool/compute/fill.rs index bfb85ba344..c4245ad64a 100644 --- a/vortex-array2/src/array/bool/compute/fill.rs +++ b/vortex-array2/src/array/bool/compute/fill.rs @@ -4,7 +4,7 @@ use vortex_schema::Nullability; use crate::array::bool::BoolArray; use crate::compute::fill::FillForwardFn; use crate::validity::ArrayValidity; -use crate::{Array, ArrayTrait, IntoArray, ToArrayData}; +use crate::{Array, IntoArray, ToArrayData}; impl FillForwardFn for BoolArray<'_> { fn fill_forward(&self) -> VortexResult> { diff --git a/vortex-array2/src/array/bool/compute/scalar_at.rs b/vortex-array2/src/array/bool/compute/scalar_at.rs index 09b4ac5679..1897bdfc94 100644 --- a/vortex-array2/src/array/bool/compute/scalar_at.rs +++ b/vortex-array2/src/array/bool/compute/scalar_at.rs @@ -4,7 +4,6 @@ use vortex_error::VortexResult; use crate::array::bool::BoolArray; use crate::compute::scalar_at::ScalarAtFn; use crate::validity::ArrayValidity; -use crate::ArrayTrait; impl ScalarAtFn for BoolArray<'_> { fn scalar_at(&self, index: usize) -> VortexResult { diff --git a/vortex-array2/src/array/bool/mod.rs b/vortex-array2/src/array/bool/mod.rs index 640832babd..45d1d5165d 100644 --- a/vortex-array2/src/array/bool/mod.rs +++ b/vortex-array2/src/array/bool/mod.rs @@ -13,7 +13,6 @@ use crate::buffer::Buffer; use crate::validity::{ArrayValidity, ValidityMetadata}; use crate::validity::{LogicalValidity, Validity}; use crate::visitor::{AcceptArrayVisitor, ArrayVisitor}; -use crate::ArrayMetadata; use crate::{impl_encoding, ArrayFlatten}; impl_encoding!("vortex.bool", Bool); @@ -90,19 +89,9 @@ impl FromIterator> for OwnedBoolArray { } impl ArrayTrait for BoolArray<'_> { - fn dtype(&self) -> &DType { - // FIXME(ngates): move this - self.array().dtype() - } - fn len(&self) -> usize { self.metadata().length } - - fn metadata(&self) -> Arc { - // FIXME(ngates): move this - Arc::new(self.metadata().clone()) - } } impl ArrayFlatten for BoolArray<'_> { diff --git a/vortex-array2/src/array/bool/stats.rs b/vortex-array2/src/array/bool/stats.rs index 67439408f4..608fa7e504 100644 --- a/vortex-array2/src/array/bool/stats.rs +++ b/vortex-array2/src/array/bool/stats.rs @@ -5,11 +5,10 @@ use vortex_error::VortexResult; use crate::array::bool::BoolArray; use crate::stats::{ArrayStatisticsCompute, Stat}; -use crate::ArrayTrait; impl ArrayStatisticsCompute for BoolArray<'_> { fn compute_statistics(&self, _stat: Stat) -> VortexResult> { - if self.len() == 0 { + if self.is_empty() { return Ok(HashMap::from([ (Stat::TrueCount, 0.into()), (Stat::RunCount, 0.into()), diff --git a/vortex-array2/src/array/chunked/compute/mod.rs b/vortex-array2/src/array/chunked/compute/mod.rs new file mode 100644 index 0000000000..4a9585361d --- /dev/null +++ b/vortex-array2/src/array/chunked/compute/mod.rs @@ -0,0 +1,45 @@ +use vortex::scalar::Scalar; +use vortex_error::VortexResult; + +use crate::array::chunked::ChunkedArray; +use crate::compute::as_contiguous::{as_contiguous, AsContiguousFn}; +use crate::compute::scalar_at::{scalar_at, ScalarAtFn}; +use crate::compute::take::TakeFn; +use crate::compute::ArrayCompute; +use crate::{Array, OwnedArray, ToStatic}; + +mod take; + +impl ArrayCompute for ChunkedArray<'_> { + fn as_contiguous(&self) -> Option<&dyn AsContiguousFn> { + Some(self) + } + + fn scalar_at(&self) -> Option<&dyn ScalarAtFn> { + Some(self) + } + + fn take(&self) -> Option<&dyn TakeFn> { + Some(self) + } +} + +impl AsContiguousFn for ChunkedArray<'_> { + fn as_contiguous(&self, arrays: &[Array]) -> VortexResult { + // Combine all the chunks into one, then call as_contiguous again. + let mut chunks = Vec::with_capacity(self.nchunks()); + for array in arrays { + for chunk in ChunkedArray::try_from(array).unwrap().chunks() { + chunks.push(chunk.to_static()); + } + } + as_contiguous(&chunks) + } +} + +impl ScalarAtFn for ChunkedArray<'_> { + fn scalar_at(&self, index: usize) -> VortexResult { + let (chunk_index, chunk_offset) = self.find_chunk_idx(index); + scalar_at(&self.chunk(chunk_index).unwrap(), chunk_offset) + } +} diff --git a/vortex-array2/src/array/chunked/compute/take.rs b/vortex-array2/src/array/chunked/compute/take.rs new file mode 100644 index 0000000000..800318ad45 --- /dev/null +++ b/vortex-array2/src/array/chunked/compute/take.rs @@ -0,0 +1,82 @@ +use vortex::ptype::PType; +use vortex_error::VortexResult; + +use crate::array::chunked::ChunkedArray; +use crate::compute::cast::cast; +use crate::compute::take::{take, TakeFn}; +use crate::{Array, IntoArray, OwnedArray, ToArray, ToStatic}; + +impl TakeFn for ChunkedArray<'_> { + fn take(&self, indices: &Array) -> VortexResult { + if self.len() == indices.len() { + return Ok(self.to_array().to_static()); + } + + let indices = cast(indices, PType::U64.into())?.flatten_primitive()?; + + // While the chunk idx remains the same, accumulate a list of chunk indices. + let mut chunks = Vec::new(); + let mut indices_in_chunk = Vec::new(); + let mut prev_chunk_idx = self + .find_chunk_idx(indices.typed_data::()[0] as usize) + .0; + for idx in indices.typed_data::() { + let (chunk_idx, idx_in_chunk) = self.find_chunk_idx(*idx as usize); + + if chunk_idx != prev_chunk_idx { + // Start a new chunk + let indices_in_chunk_array = indices_in_chunk.clone().into_array(); + chunks.push(take( + &self.chunk(prev_chunk_idx).unwrap(), + &indices_in_chunk_array, + )?); + indices_in_chunk = Vec::new(); + } + + indices_in_chunk.push(idx_in_chunk as u64); + prev_chunk_idx = chunk_idx; + } + + if !indices_in_chunk.is_empty() { + let indices_in_chunk_array = indices_in_chunk.into_array(); + chunks.push(take( + &self.chunk(prev_chunk_idx).unwrap(), + &indices_in_chunk_array, + )?); + } + + Ok(ChunkedArray::new(chunks, self.dtype().clone()).into_array()) + } +} + +#[cfg(test)] +mod test { + use itertools::Itertools; + + use crate::array::chunked::ChunkedArray; + use crate::array::primitive::PrimitiveArray; + use crate::compute::as_contiguous::as_contiguous; + use crate::compute::take::take; + use crate::IntoArray; + + #[test] + fn test_take() { + let a = vec![1i32, 2, 3].into_array(); + let arr = ChunkedArray::new(vec![a.clone(), a.clone(), a.clone()], a.dtype().clone()); + assert_eq!(arr.nchunks(), 3); + assert_eq!(arr.len(), 9); + let indices = vec![0, 0, 6, 4].into_array(); + + let result = PrimitiveArray::try_from( + as_contiguous( + &ChunkedArray::try_from(take(arr.as_ref(), &indices).unwrap()) + .unwrap() + .chunks() + .collect_vec(), + ) + .unwrap(), + ) + .unwrap(); + assert_eq!(result.typed_data::(), &[1, 1, 1, 2]); + } +} diff --git a/vortex-array2/src/array/chunked/mod.rs b/vortex-array2/src/array/chunked/mod.rs new file mode 100644 index 0000000000..3a2eccbd59 --- /dev/null +++ b/vortex-array2/src/array/chunked/mod.rs @@ -0,0 +1,213 @@ +use std::collections::HashMap; + +use itertools::Itertools; +use serde::{Deserialize, Serialize}; +use vortex_error::{vortex_bail, VortexResult}; +use vortex_schema::{DType, IntWidth, Nullability, Signedness}; + +use crate::array::primitive::PrimitiveArray; +use crate::compute::scalar_at::scalar_at; +use crate::compute::search_sorted::{search_sorted, SearchSortedSide}; +use crate::validity::Validity::NonNullable; +use crate::validity::{ArrayValidity, LogicalValidity}; +use crate::visitor::{AcceptArrayVisitor, ArrayVisitor}; +use crate::{impl_encoding, ArrayFlatten, IntoArrayData, OwnedArray, ToArrayData}; + +mod compute; +mod stats; + +impl_encoding!("vortex.chunked", Chunked); + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ChunkedMetadata; + +impl ChunkedArray<'_> { + const ENDS_DTYPE: DType = DType::Int( + IntWidth::_64, + Signedness::Unsigned, + Nullability::NonNullable, + ); + + pub fn new(chunks: Vec, dtype: DType) -> Self { + Self::try_new(chunks, dtype).unwrap() + } + + pub fn try_new(chunks: Vec, dtype: DType) -> VortexResult { + for chunk in &chunks { + if chunk.dtype() != &dtype { + vortex_bail!(MismatchedTypes: dtype, chunk.dtype()); + } + } + + let chunk_ends = PrimitiveArray::from_vec( + [0u64] + .into_iter() + .chain(chunks.iter().map(|c| c.len() as u64)) + .scan(0, |acc, c| { + *acc += c; + Some(*acc) + }) + .collect_vec(), + NonNullable, + ); + + let mut children = vec![chunk_ends.into_array_data()]; + children.extend(chunks.iter().map(|a| a.to_array_data())); + + Self::try_from_parts( + dtype, + ChunkedMetadata, + vec![].into(), + children.into(), + HashMap::default(), + ) + } + + #[inline] + pub fn chunk(&self, idx: usize) -> Option { + // Offset the index since chunk_ends is child 0. + self.array().child(idx + 1, self.array().dtype()) + } + + pub fn chunks(&self) -> impl Iterator { + (0..self.nchunks()).map(|c| self.chunk(c).unwrap()) + } + + pub fn nchunks(&self) -> usize { + self.chunk_ends().len() - 1 + } + + #[inline] + pub fn chunk_ends(&self) -> Array { + self.array() + .child(0, &Self::ENDS_DTYPE) + .expect("missing chunk ends") + } + + pub fn find_chunk_idx(&self, index: usize) -> (usize, usize) { + assert!(index <= self.len(), "Index out of bounds of the array"); + + // TODO(ngates): migrate to the new search_sorted API to subtract 1 if not exact match. + let mut index_chunk = + search_sorted(&self.chunk_ends(), index, SearchSortedSide::Left).unwrap(); + let mut chunk_start = + usize::try_from(scalar_at(&self.chunk_ends(), index_chunk).unwrap()).unwrap(); + + if chunk_start != index { + index_chunk -= 1; + chunk_start = + usize::try_from(scalar_at(&self.chunk_ends(), index_chunk).unwrap()).unwrap(); + } + + let index_in_chunk = index - chunk_start; + (index_chunk, index_in_chunk) + } +} + +impl FromIterator for OwnedChunkedArray { + fn from_iter>(iter: T) -> Self { + let chunks: Vec = iter.into_iter().collect(); + let dtype = chunks + .first() + .map(|c| c.dtype().clone()) + .expect("Cannot create a chunked array from an empty iterator"); + Self::new(chunks, dtype) + } +} + +impl ArrayFlatten for ChunkedArray<'_> { + fn flatten<'a>(self) -> VortexResult> + where + Self: 'a, + { + Ok(Flattened::Chunked(self)) + } +} + +impl AcceptArrayVisitor for ChunkedArray<'_> { + fn accept(&self, visitor: &mut dyn ArrayVisitor) -> VortexResult<()> { + visitor.visit_child("chunk_ends", &self.chunk_ends())?; + for (idx, chunk) in self.chunks().enumerate() { + visitor.visit_child(format!("[{}]", idx).as_str(), &chunk)?; + } + Ok(()) + } +} + +impl ArrayTrait for ChunkedArray<'_> { + fn len(&self) -> usize { + usize::try_from(scalar_at(&self.chunk_ends(), self.nchunks()).unwrap()).unwrap() + } +} + +impl ArrayValidity for ChunkedArray<'_> { + fn is_valid(&self, _index: usize) -> bool { + todo!() + } + + fn logical_validity(&self) -> LogicalValidity { + todo!() + } +} + +#[cfg(test)] +mod test { + use vortex::ptype::NativePType; + use vortex_schema::{DType, IntWidth, Nullability, Signedness}; + + use crate::array::chunked::{ChunkedArray, OwnedChunkedArray}; + use crate::{Array, IntoArray}; + + #[allow(dead_code)] + fn chunked_array() -> OwnedChunkedArray { + ChunkedArray::new( + vec![ + vec![1u64, 2, 3].into_array(), + vec![4u64, 5, 6].into_array(), + vec![7u64, 8, 9].into_array(), + ], + DType::Int( + IntWidth::_64, + Signedness::Unsigned, + Nullability::NonNullable, + ), + ) + } + + #[allow(dead_code)] + fn assert_equal_slices(arr: Array, slice: &[T]) { + let mut values = Vec::with_capacity(arr.len()); + ChunkedArray::try_from(arr) + .unwrap() + .chunks() + .map(|a| a.flatten_primitive().unwrap()) + .for_each(|a| values.extend_from_slice(a.typed_data::())); + assert_eq!(values, slice); + } + + // FIXME(ngates): bring back when slicing is a compute function. + // #[test] + // pub fn slice_middle() { + // assert_equal_slices(chunked_array().slice(2, 5).unwrap(), &[3u64, 4, 5]) + // } + // + // #[test] + // pub fn slice_begin() { + // assert_equal_slices(chunked_array().slice(1, 3).unwrap(), &[2u64, 3]); + // } + // + // #[test] + // pub fn slice_aligned() { + // assert_equal_slices(chunked_array().slice(3, 6).unwrap(), &[4u64, 5, 6]); + // } + // + // #[test] + // pub fn slice_many_aligned() { + // assert_equal_slices(chunked_array().slice(0, 6).unwrap(), &[1u64, 2, 3, 4, 5, 6]); + // } + // + // #[test] + // pub fn slice_end() { + // assert_equal_slices(chunked_array().slice(7, 8).unwrap(), &[8u64]); + // } +} diff --git a/vortex-array2/src/array/chunked/stats.rs b/vortex-array2/src/array/chunked/stats.rs new file mode 100644 index 0000000000..0cb8e521b2 --- /dev/null +++ b/vortex-array2/src/array/chunked/stats.rs @@ -0,0 +1,13 @@ +use std::collections::HashMap; + +use vortex::scalar::Scalar; +use vortex_error::VortexResult; + +use crate::array::chunked::ChunkedArray; +use crate::stats::{ArrayStatisticsCompute, Stat}; + +impl ArrayStatisticsCompute for ChunkedArray<'_> { + fn compute_statistics(&self, _stat: Stat) -> VortexResult> { + todo!() + } +} diff --git a/vortex-array2/src/array/mod.rs b/vortex-array2/src/array/mod.rs index 48103db386..187188234b 100644 --- a/vortex-array2/src/array/mod.rs +++ b/vortex-array2/src/array/mod.rs @@ -1,3 +1,4 @@ pub mod bool; +pub mod chunked; pub mod primitive; pub mod r#struct; diff --git a/vortex-array2/src/array/primitive/compute/as_arrow.rs b/vortex-array2/src/array/primitive/compute/as_arrow.rs index 58abc4c7fc..cbc402411d 100644 --- a/vortex-array2/src/array/primitive/compute/as_arrow.rs +++ b/vortex-array2/src/array/primitive/compute/as_arrow.rs @@ -10,7 +10,6 @@ use vortex_error::VortexResult; use crate::array::primitive::PrimitiveArray; use crate::compute::as_arrow::AsArrowArray; use crate::validity::ArrayValidity; -use crate::ArrayTrait; impl AsArrowArray for PrimitiveArray<'_> { fn as_arrow(&self) -> VortexResult { diff --git a/vortex-array2/src/array/primitive/compute/as_contiguous.rs b/vortex-array2/src/array/primitive/compute/as_contiguous.rs index e94251c438..717da79372 100644 --- a/vortex-array2/src/array/primitive/compute/as_contiguous.rs +++ b/vortex-array2/src/array/primitive/compute/as_contiguous.rs @@ -5,7 +5,7 @@ use vortex_error::VortexResult; use crate::array::primitive::PrimitiveArray; use crate::compute::as_contiguous::AsContiguousFn; use crate::validity::Validity; -use crate::{Array, ArrayTrait, IntoArray, OwnedArray}; +use crate::{Array, IntoArray, OwnedArray}; impl AsContiguousFn for PrimitiveArray<'_> { fn as_contiguous(&self, arrays: &[Array]) -> VortexResult { diff --git a/vortex-array2/src/array/primitive/compute/scalar_at.rs b/vortex-array2/src/array/primitive/compute/scalar_at.rs index aceb4ccfa5..810d13a068 100644 --- a/vortex-array2/src/array/primitive/compute/scalar_at.rs +++ b/vortex-array2/src/array/primitive/compute/scalar_at.rs @@ -6,7 +6,6 @@ use vortex_error::VortexResult; use crate::array::primitive::PrimitiveArray; use crate::compute::scalar_at::ScalarAtFn; use crate::validity::ArrayValidity; -use crate::ArrayTrait; impl ScalarAtFn for PrimitiveArray<'_> { fn scalar_at(&self, index: usize) -> VortexResult { diff --git a/vortex-array2/src/array/primitive/mod.rs b/vortex-array2/src/array/primitive/mod.rs index 1bb35dbd8e..fc7e86da5a 100644 --- a/vortex-array2/src/array/primitive/mod.rs +++ b/vortex-array2/src/array/primitive/mod.rs @@ -13,8 +13,8 @@ use vortex_schema::DType; use crate::buffer::Buffer; use crate::validity::{ArrayValidity, LogicalValidity, Validity, ValidityMetadata}; use crate::visitor::{AcceptArrayVisitor, ArrayVisitor}; +use crate::ArrayFlatten; use crate::{impl_encoding, IntoArray}; -use crate::{ArrayFlatten, ArrayMetadata}; impl_encoding!("vortex.primitive", Primitive); @@ -93,17 +93,9 @@ impl ArrayFlatten for PrimitiveArray<'_> { } impl ArrayTrait for PrimitiveArray<'_> { - fn dtype(&self) -> &DType { - self.array().dtype() - } - fn len(&self) -> usize { self.buffer().len() / self.ptype().byte_width() } - - fn metadata(&self) -> Arc { - Arc::new(self.metadata().clone()) - } } impl ArrayValidity for PrimitiveArray<'_> { diff --git a/vortex-array2/src/array/struct/mod.rs b/vortex-array2/src/array/struct/mod.rs index 3d97321bf6..e17df95edf 100644 --- a/vortex-array2/src/array/struct/mod.rs +++ b/vortex-array2/src/array/struct/mod.rs @@ -9,8 +9,8 @@ use crate::stats::ArrayStatisticsCompute; use crate::validity::{ArrayValidity, LogicalValidity}; use crate::visitor::{AcceptArrayVisitor, ArrayVisitor}; use crate::ArrayData; +use crate::ArrayFlatten; use crate::{impl_encoding, ToArray}; -use crate::{ArrayFlatten, ArrayMetadata}; impl_encoding!("vortex.struct", Struct); @@ -81,17 +81,9 @@ impl ArrayFlatten for StructArray<'_> { } impl ArrayTrait for StructArray<'_> { - fn dtype(&self) -> &DType { - self.array().dtype() - } - fn len(&self) -> usize { self.metadata().length } - - fn metadata(&self) -> Arc { - Arc::new(self.metadata().clone()) - } } impl ArrayValidity for StructArray<'_> { diff --git a/vortex-array2/src/flatten.rs b/vortex-array2/src/flatten.rs index 1ab7105499..341c53a394 100644 --- a/vortex-array2/src/flatten.rs +++ b/vortex-array2/src/flatten.rs @@ -1,6 +1,7 @@ use vortex_error::VortexResult; use crate::array::bool::BoolArray; +use crate::array::chunked::ChunkedArray; use crate::array::primitive::PrimitiveArray; use crate::array::r#struct::StructArray; use crate::encoding::ArrayEncoding; @@ -9,6 +10,7 @@ use crate::{Array, IntoArray}; /// The set of encodings that can be converted to Arrow with zero-copy. pub enum Flattened<'a> { Bool(BoolArray<'a>), + Chunked(ChunkedArray<'a>), Primitive(PrimitiveArray<'a>), Struct(StructArray<'a>), } @@ -39,6 +41,7 @@ impl<'a> IntoArray<'a> for Flattened<'a> { Flattened::Bool(a) => a.into_array(), Flattened::Primitive(a) => a.into_array(), Flattened::Struct(a) => a.into_array(), + Flattened::Chunked(a) => a.into_array(), } } } diff --git a/vortex-array2/src/implementation.rs b/vortex-array2/src/implementation.rs index 5e762fcf7b..a8716f5c9f 100644 --- a/vortex-array2/src/implementation.rs +++ b/vortex-array2/src/implementation.rs @@ -28,6 +28,7 @@ macro_rules! impl_encoding { use $crate::{ Array, ArrayDef, + ArrayMetadata, ArrayTrait, Flattened, TypedArray, diff --git a/vortex-array2/src/lib.rs b/vortex-array2/src/lib.rs index 5c9f3e8716..9c8b1283d0 100644 --- a/vortex-array2/src/lib.rs +++ b/vortex-array2/src/lib.rs @@ -18,7 +18,6 @@ mod view; mod visitor; use std::fmt::{Debug, Display, Formatter}; -use std::sync::Arc; pub use context::*; pub use data::*; @@ -136,6 +135,7 @@ pub trait TryFromArrayParts<'v, M: ArrayMetadata>: Sized + 'v { pub trait ArrayTrait: ArrayEncodingRef + ArrayCompute + + ArrayDType + ArrayFlatten + ArrayValidity + AcceptArrayVisitor @@ -143,8 +143,6 @@ pub trait ArrayTrait: + ArrayStatisticsCompute + ToArrayData { - fn dtype(&self) -> &DType; - fn len(&self) -> usize; fn is_empty(&self) -> bool { @@ -152,8 +150,6 @@ pub trait ArrayTrait: self.len() == 0 } - fn metadata(&self) -> Arc; - fn nbytes(&self) -> usize { let mut visitor = NBytesVisitor(0); self.accept(&mut visitor).unwrap(); @@ -161,6 +157,10 @@ pub trait ArrayTrait: } } +pub trait ArrayDType { + fn dtype(&self) -> &DType; +} + struct NBytesVisitor(usize); impl ArrayVisitor for NBytesVisitor { fn visit_child(&mut self, _name: &str, array: &Array) -> VortexResult<()> { diff --git a/vortex-array2/src/typed.rs b/vortex-array2/src/typed.rs index 6555c7fc59..3ab142de9c 100644 --- a/vortex-array2/src/typed.rs +++ b/vortex-array2/src/typed.rs @@ -10,8 +10,8 @@ use crate::encoding::{ArrayEncodingRef, EncodingRef}; use crate::stats::{ArrayStatistics, Stat, Statistics}; use crate::visitor::ArrayVisitor; use crate::{ - Array, ArrayData, ArrayDef, ArrayParts, IntoArray, IntoArrayData, ToArrayData, ToStatic, - TryDeserializeArrayMetadata, + Array, ArrayDType, ArrayData, ArrayDef, ArrayParts, IntoArray, IntoArrayData, ToArray, + ToArrayData, ToStatic, TryDeserializeArrayMetadata, }; #[derive(Debug)] @@ -43,6 +43,18 @@ impl TypedArray<'_, D> { &self.array } + pub fn len(&self) -> usize { + self.array.with_dyn(|a| a.len()) + } + + pub fn is_empty(&self) -> bool { + self.array.with_dyn(|a| a.is_empty()) + } + + pub fn dtype(&self) -> &DType { + self.array.dtype() + } + pub fn metadata(&self) -> &D::Metadata { &self.metadata } @@ -91,6 +103,12 @@ impl<'a, D: ArrayDef> TryFrom<&'a Array<'a>> for TypedArray<'a, D> { } } +impl ArrayDType for TypedArray<'_, D> { + fn dtype(&self) -> &DType { + self.array().dtype() + } +} + impl ArrayEncodingRef for TypedArray<'_, D> { fn encoding(&self) -> EncodingRef { self.array().encoding() @@ -107,6 +125,29 @@ impl ArrayStatistics for TypedArray<'_, D> { } } +impl ToStatic for TypedArray<'_, D> { + type Static = TypedArray<'static, D>; + + fn to_static(&self) -> Self::Static { + TypedArray { + array: Array::Data(self.to_array_data()), + metadata: self.metadata.clone(), + } + } +} + +impl<'a, D: ArrayDef> AsRef> for TypedArray<'a, D> { + fn as_ref(&self) -> &Array<'a> { + &self.array + } +} + +impl ToArray for TypedArray<'_, D> { + fn to_array(&self) -> Array { + self.array.clone() + } +} + impl<'a, D: ArrayDef> IntoArray<'a> for TypedArray<'a, D> { fn into_array(self) -> Array<'a> { self.array