vortex_array/macros.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
//! The core Vortex macro to create new encodings and array types.
use crate::encoding::{ArrayEncodingRef, EncodingRef};
use crate::{ArrayData, ToArrayData};
impl<A: AsRef<ArrayData>> ToArrayData for A {
fn to_array(&self) -> ArrayData {
self.as_ref().clone()
}
}
/// Macro to generate all the necessary code for a new type of array encoding. Including:
/// 1. New Array type that implements `AsRef<ArrayData>`, `GetArrayMetadata`, `ToArray`, `IntoArray`, and multiple useful `From`/`TryFrom` implementations.
/// 2. New Encoding type that implements `ArrayEncoding`.
/// 3. New metadata type that implements `ArrayMetadata`.
#[macro_export]
macro_rules! impl_encoding {
($id:literal, $code:expr, $Name:ident) => {
$crate::paste::paste! {
#[derive(std::fmt::Debug, Clone)]
#[repr(transparent)]
pub struct [<$Name Array>]($crate::ArrayData);
impl $crate::IntoArrayData for [<$Name Array>] {
fn into_array(self) -> $crate::ArrayData {
self.0
}
}
impl AsRef<$crate::ArrayData> for [<$Name Array>] {
fn as_ref(&self) -> &$crate::ArrayData {
&self.0
}
}
impl [<$Name Array>] {
#[allow(dead_code)]
fn metadata(&self) -> &[<$Name Metadata>] {
use vortex_error::VortexExpect;
self.0.metadata::<[<$Name Metadata>]>()
.vortex_expect("Metadata should be tied to the encoding")
}
#[allow(dead_code)]
fn try_from_parts(
dtype: vortex_dtype::DType,
len: usize,
metadata: [<$Name Metadata>],
children: std::sync::Arc<[$crate::ArrayData]>,
stats: $crate::stats::StatsSet,
) -> VortexResult<Self> {
Self::try_from($crate::ArrayData::try_new_owned(
&[<$Name Encoding>],
dtype,
len,
std::sync::Arc::new(metadata),
None,
children,
stats
)?)
}
/// Optionally downcast an [`ArrayData`](crate::ArrayData) instance to a specific encoding.
///
/// Preferred in cases where a backtrace isn't needed, like when trying multiple encoding to go
/// down different code paths.
pub fn maybe_from(data: impl AsRef<$crate::ArrayData>) -> Option<Self> {
let data = data.as_ref();
(data.encoding().id() == <[<$Name Encoding>] as $crate::encoding::Encoding>::ID).then_some(Self(data.clone()))
}
}
impl TryFrom<$crate::ArrayData> for [<$Name Array>] {
type Error = vortex_error::VortexError;
fn try_from(data: $crate::ArrayData) -> vortex_error::VortexResult<Self> {
if data.encoding().id() != <[<$Name Encoding>] as $crate::encoding::Encoding>::ID {
vortex_error::vortex_bail!(
"Mismatched encoding {}, expected {}",
data.encoding().id().as_ref(),
<[<$Name Encoding>] as $crate::encoding::Encoding>::ID,
);
}
Ok(Self(data))
}
}
// NOTE(ngates): this is the cheeky one.... Since we know that Arrays are structurally
// equal to ArrayData, we can transmute a &ArrayData to a &Array.
impl<'a> TryFrom<&'a $crate::ArrayData> for &'a [<$Name Array>] {
type Error = vortex_error::VortexError;
fn try_from(data: &'a $crate::ArrayData) -> vortex_error::VortexResult<Self> {
if data.encoding().id() != <[<$Name Encoding>] as $crate::encoding::Encoding>::ID {
vortex_error::vortex_bail!(
"Mismatched encoding {}, expected {}",
data.encoding().id().as_ref(),
<[<$Name Encoding>] as $crate::encoding::Encoding>::ID,
);
}
Ok(unsafe { std::mem::transmute::<&$crate::ArrayData, &[<$Name Array>]>(data) })
}
}
/// The array encoding
#[derive(std::fmt::Debug)]
pub struct [<$Name Encoding>];
impl $crate::encoding::Encoding for [<$Name Encoding>] {
const ID: $crate::encoding::EncodingId = $crate::encoding::EncodingId::new($id, $code);
type Array = [<$Name Array>];
type Metadata = [<$Name Metadata>];
}
impl $crate::encoding::EncodingVTable for [<$Name Encoding>] {
#[inline]
fn id(&self) -> $crate::encoding::EncodingId {
<[<$Name Encoding>] as $crate::encoding::Encoding>::ID
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
/// Implement ArrayMetadata
impl $crate::ArrayMetadata for [<$Name Metadata>] {
#[inline]
fn as_any(&self) -> &dyn std::any::Any {
self
}
#[inline]
fn as_any_arc(self: std::sync::Arc<Self>) -> std::sync::Arc<dyn std::any::Any + std::marker::Send + std::marker::Sync> {
self
}
}
}
};
}
impl<T: AsRef<ArrayData>> ArrayEncodingRef for T {
fn encoding(&self) -> EncodingRef {
self.as_ref().encoding()
}
}
impl AsRef<ArrayData> for ArrayData {
fn as_ref(&self) -> &ArrayData {
self
}
}