use std::any::Any;
use std::fmt::{Debug, Display, Formatter};
use std::sync::Arc;
use arcref::ArcRef;
use vortex_buffer::ByteBuffer;
use vortex_dtype::DType;
use vortex_error::{VortexExpect, VortexResult, vortex_bail, vortex_err};
use crate::serde::ArrayChildren;
use crate::vtable::{EncodeVTable, SerdeVTable, VTable};
use crate::{Array, ArrayRef, Canonical, DeserializeMetadata};
pub type EncodingId = ArcRef<str>;
pub type EncodingRef = ArcRef<dyn Encoding>;
pub trait Encoding: 'static + private::Sealed + Send + Sync + Debug {
fn as_any(&self) -> &dyn Any;
fn to_encoding(&self) -> EncodingRef;
fn into_encoding(self) -> EncodingRef
where
Self: Sized;
fn id(&self) -> EncodingId;
fn build(
&self,
dtype: &DType,
len: usize,
metadata: &[u8],
buffers: &[ByteBuffer],
children: &dyn ArrayChildren,
) -> VortexResult<ArrayRef>;
fn encode(&self, input: &Canonical, like: Option<&dyn Array>)
-> VortexResult<Option<ArrayRef>>;
}
#[repr(transparent)]
pub struct EncodingAdapter<V: VTable>(V::Encoding);
impl<V: VTable> Encoding for EncodingAdapter<V> {
fn as_any(&self) -> &dyn Any {
self
}
fn to_encoding(&self) -> EncodingRef {
ArcRef::new_arc(Arc::new(EncodingAdapter::<V>(self.0.clone())))
}
fn into_encoding(self) -> EncodingRef
where
Self: Sized,
{
todo!()
}
fn id(&self) -> EncodingId {
V::id(&self.0)
}
fn build(
&self,
dtype: &DType,
len: usize,
metadata: &[u8],
buffers: &[ByteBuffer],
children: &dyn ArrayChildren,
) -> VortexResult<ArrayRef> {
let metadata =
<<V::SerdeVTable as SerdeVTable<V>>::Metadata as DeserializeMetadata>::deserialize(
metadata,
)?;
let array = <V::SerdeVTable as SerdeVTable<V>>::build(
&self.0, dtype, len, &metadata, buffers, children,
)?;
assert_eq!(array.len(), len, "Array length mismatch after building");
assert_eq!(array.dtype(), dtype, "Array dtype mismatch after building");
Ok(array.to_array())
}
fn encode(
&self,
input: &Canonical,
like: Option<&dyn Array>,
) -> VortexResult<Option<ArrayRef>> {
let downcast_like = like
.map(|like| {
like.as_opt::<V>().ok_or_else(|| {
vortex_err!(
"Like array {} does not match requested encoding {}",
like.encoding_id(),
self.id()
)
})
})
.transpose()?;
let Some(array) =
<V::EncodeVTable as EncodeVTable<V>>::encode(&self.0, input, downcast_like)?
else {
return Ok(None);
};
let input = input.as_ref();
if array.len() != input.len() {
vortex_bail!(
"Array length mismatch after encoding: {} != {}",
array.len(),
input.len()
);
}
if array.dtype() != input.dtype() {
vortex_bail!(
"Array dtype mismatch after encoding: {} != {}",
array.dtype(),
input.dtype()
);
}
Ok(Some(array.to_array()))
}
}
impl<V: VTable> Debug for EncodingAdapter<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Encoding").field("id", &self.id()).finish()
}
}
impl Display for dyn Encoding + '_ {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.id())
}
}
impl PartialEq for dyn Encoding + '_ {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl Eq for dyn Encoding + '_ {}
impl dyn Encoding + '_ {
pub fn as_<V: VTable>(&self) -> &V::Encoding {
self.as_any()
.downcast_ref::<EncodingAdapter<V>>()
.map(|e| &e.0)
.vortex_expect("Encoding is not of the expected type")
}
}
mod private {
use super::*;
pub trait Sealed {}
impl<V: VTable> Sealed for EncodingAdapter<V> {}
}