Skip to main content

vortex_array/array/
plugin.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::fmt;
5use std::fmt::Debug;
6use std::fmt::Formatter;
7use std::sync::Arc;
8
9use vortex_buffer::ByteBuffer;
10use vortex_error::VortexResult;
11use vortex_error::vortex_ensure;
12use vortex_session::VortexSession;
13
14use crate::ArrayRef;
15use crate::IntoArray;
16use crate::array::Array;
17use crate::array::ArrayId;
18use crate::array::VTable;
19use crate::buffer::BufferHandle;
20use crate::dtype::DType;
21use crate::serde::ArrayChildren;
22
23/// Reference-counted array plugin.
24pub type ArrayPluginRef = Arc<dyn ArrayPlugin>;
25
26/// The wire representation produced by an in-memory array's serializer.
27///
28/// A serializer may reuse the in-memory array's buffers and children with [`Self::from_array`],
29/// or return different parts when an older wire representation requires a lossless structural
30/// downgrade.
31#[derive(Clone, Debug)]
32pub struct ArraySerialization {
33    /// The concrete array ID to write on the wire.
34    pub serialized_id: ArrayId,
35    /// Encoding-specific metadata written into the array node.
36    pub metadata: Vec<u8>,
37    /// Top-level buffers written for this array node.
38    pub buffers: Vec<ByteBuffer>,
39    /// Child arrays to serialize recursively.
40    pub children: Vec<ArrayRef>,
41}
42
43impl ArraySerialization {
44    /// Create a wire representation from an ID, metadata, buffers, and children.
45    pub fn new(
46        serialized_id: ArrayId,
47        metadata: Vec<u8>,
48        buffers: Vec<ByteBuffer>,
49        children: Vec<ArrayRef>,
50    ) -> Self {
51        Self {
52            serialized_id,
53            metadata,
54            buffers,
55            children,
56        }
57    }
58
59    /// Reuse an in-memory array's buffers and children with the supplied serialized metadata.
60    pub fn from_array(serialized_id: ArrayId, array: &ArrayRef, metadata: Vec<u8>) -> Self {
61        Self::new(serialized_id, metadata, array.buffers(), array.children())
62    }
63}
64
65/// The borrowed wire components passed to an array deserializer.
66pub struct ArrayDeserialization<'a> {
67    /// The exact array ID found on the wire.
68    pub serialized_id: ArrayId,
69    /// The logical dtype supplied by the containing format.
70    pub dtype: &'a DType,
71    /// The logical array length supplied by the containing format.
72    pub len: usize,
73    /// Encoding-specific metadata from the array node.
74    pub metadata: &'a [u8],
75    /// Top-level buffers referenced by the array node.
76    pub buffers: &'a [BufferHandle],
77    /// Lazily decoded child arrays referenced by the array node.
78    pub children: &'a dyn ArrayChildren,
79}
80
81impl<'a> ArrayDeserialization<'a> {
82    /// Create borrowed deserialization input from a wire ID and its serialized components.
83    pub fn new(
84        serialized_id: ArrayId,
85        dtype: &'a DType,
86        len: usize,
87        metadata: &'a [u8],
88        buffers: &'a [BufferHandle],
89        children: &'a dyn ArrayChildren,
90    ) -> Self {
91        Self {
92            serialized_id,
93            dtype,
94            len,
95            metadata,
96            buffers,
97            children,
98        }
99    }
100}
101
102/// Registry trait for serializing and deserializing an in-memory array representation.
103///
104/// A plugin has one [`id`](Self::id) for the in-memory representation and one or more
105/// [`serialized_ids`](Self::serialized_ids) for wire representations. Its serializer chooses the
106/// wire representation, and the serialization context validates that the chosen ID is permitted
107/// before it is written.
108///
109/// Every serialized ID is also registered for deserialization. A current plugin may therefore
110/// deserialize several historical IDs into the same in-memory representation. A reader that
111/// predates a newer ID has no registration for it and reports it as unknown instead of silently
112/// interpreting an unsupported representation.
113pub trait ArrayPlugin: 'static + Send + Sync {
114    /// Returns the ID of the in-memory array representation handled by this plugin.
115    fn id(&self) -> ArrayId;
116
117    /// Returns the serialized array IDs understood by this plugin, ordered oldest to newest.
118    ///
119    /// The default uses the in-memory ID as the sole wire ID. Override this for an in-memory array
120    /// that has multiple serialized variants. IDs retained only for reading may also be included;
121    /// the single serializer need not select them.
122    fn serialized_ids(&self) -> Vec<ArrayId> {
123        vec![self.id()]
124    }
125
126    /// Serialize `array` to its wire representation.
127    ///
128    /// This function is called only for arrays whose in-memory encoding matches [`id`](Self::id).
129    /// The returned ID must be declared by [`serialized_ids`](Self::serialized_ids). Return
130    /// `Ok(None)` when the array cannot be serialized.
131    fn serialize(
132        &self,
133        array: &ArrayRef,
134        session: &VortexSession,
135    ) -> VortexResult<Option<ArraySerialization>>;
136
137    /// Deserialize one recognized wire representation into the current in-memory array.
138    ///
139    /// `serialized_id` identifies the exact representation encountered on disk. The returned
140    /// array does not necessarily have to use this plugin's in-memory ID; this supports legacy
141    /// representations that are normalized into another current in-memory array. Implementations
142    /// must validate the contract of that exact ID rather than accepting every form understood by
143    /// the current in-memory representation under an older ID.
144    fn deserialize(
145        &self,
146        parts: ArrayDeserialization<'_>,
147        session: &VortexSession,
148    ) -> VortexResult<ArrayRef>;
149
150    /// Can this plugin emit an array with the given encoding.
151    ///
152    /// By default, this is just the [ID][Self::id] of the plugin, but
153    /// can be overridden if this plugin instance supports reading/writing multiple arrays.
154    fn is_supported_encoding(&self, id: &ArrayId) -> bool {
155        self.id() == *id
156    }
157}
158
159impl Debug for dyn ArrayPlugin {
160    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
161        f.debug_tuple("ArrayPlugin").field(&self.id()).finish()
162    }
163}
164
165impl<V: VTable> ArrayPlugin for V {
166    fn id(&self) -> ArrayId {
167        VTable::id(self)
168    }
169
170    fn serialize(
171        &self,
172        array: &ArrayRef,
173        session: &VortexSession,
174    ) -> VortexResult<Option<ArraySerialization>> {
175        vortex_ensure!(
176            self.id() == array.encoding_id(),
177            "array plugin {} cannot serialize in-memory array {}",
178            self.id(),
179            array.encoding_id(),
180        );
181        Ok(V::serialize(array.as_::<V>(), session)?
182            .map(|metadata| ArraySerialization::from_array(self.id(), array, metadata)))
183    }
184
185    fn deserialize(
186        &self,
187        parts: ArrayDeserialization<'_>,
188        session: &VortexSession,
189    ) -> VortexResult<ArrayRef> {
190        vortex_ensure!(
191            self.id() == parts.serialized_id,
192            "array plugin {} does not recognize serialized ID {}",
193            self.id(),
194            parts.serialized_id,
195        );
196        Ok(Array::<V>::try_from_parts(V::deserialize(
197            self,
198            parts.dtype,
199            parts.len,
200            parts.metadata,
201            parts.buffers,
202            parts.children,
203            session,
204        )?)?
205        .into_array())
206    }
207}