Skip to main content

fory_core/row/
row.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::collections::BTreeMap;
19
20use crate::error::Error;
21use crate::types::{Date, Duration, Timestamp};
22
23use super::reader::{ArrayView, MapView};
24use super::writer::{ArrayWriter, MapWriter, ValueWriter};
25
26/// Static Row Format behavior for one schema value.
27///
28/// This trait is public because `ForyRow` implementations are generated in
29/// downstream crates. Most applications should derive `ForyRow` instead of
30/// implementing it directly.
31#[doc(hidden)]
32pub trait RowValue {
33    /// Zero-copy projection returned when this value is read.
34    type View<'a>;
35
36    /// Natural fixed width, or `None` for an offset-addressed value.
37    const FIXED_SIZE: Option<usize>;
38
39    /// Writes exactly one value to its container-selected destination.
40    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error>;
41
42    /// Reads exactly one value from its container-resolved bytes.
43    fn read<'a>(bytes: &'a [u8]) -> Result<Self::View<'a>, Error>;
44
45    /// Returns true when this value should set its container null bit.
46    fn is_null(&self) -> bool {
47        false
48    }
49
50    /// Produces the projection for a set null bit.
51    fn read_null<'a>() -> Result<Self::View<'a>, Error> {
52        Err(Error::invalid_data(
53            "null row value cannot be read as a non-optional type",
54        ))
55    }
56}
57
58/// A self-contained Standard Row Format root.
59///
60/// Derived structs, arrays, and maps implement this marker. Scalar, string,
61/// binary, and optional values are field/element values rather than row roots.
62pub trait Row: RowValue {}
63
64macro_rules! impl_fixed_row_value {
65    ($ty:ty, $size:expr) => {
66        impl RowValue for $ty {
67            type View<'a> = Self;
68
69            const FIXED_SIZE: Option<usize> = Some($size);
70
71            #[inline(always)]
72            fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
73                writer.write_bytes(&self.to_le_bytes())
74            }
75
76            #[inline(always)]
77            fn read(bytes: &[u8]) -> Result<Self, Error> {
78                Ok(Self::from_le_bytes(read_fixed(bytes)?))
79            }
80        }
81    };
82}
83
84impl RowValue for bool {
85    type View<'a> = Self;
86
87    const FIXED_SIZE: Option<usize> = Some(1);
88
89    #[inline(always)]
90    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
91        writer.write_bytes(&[u8::from(*self)])
92    }
93
94    #[inline(always)]
95    fn read(bytes: &[u8]) -> Result<Self, Error> {
96        match read_fixed::<1>(bytes)?[0] {
97            0 => Ok(false),
98            1 => Ok(true),
99            _ => Err(Error::invalid_data("row boolean must be encoded as 0 or 1")),
100        }
101    }
102}
103
104impl RowValue for i8 {
105    type View<'a> = Self;
106
107    const FIXED_SIZE: Option<usize> = Some(1);
108
109    #[inline(always)]
110    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
111        writer.write_bytes(&self.to_le_bytes())
112    }
113
114    #[inline(always)]
115    fn read(bytes: &[u8]) -> Result<Self, Error> {
116        Ok(Self::from_le_bytes(read_fixed(bytes)?))
117    }
118}
119
120impl_fixed_row_value!(i16, 2);
121impl_fixed_row_value!(i32, 4);
122impl_fixed_row_value!(i64, 8);
123impl_fixed_row_value!(f32, 4);
124impl_fixed_row_value!(f64, 8);
125
126impl RowValue for String {
127    type View<'a> = &'a str;
128
129    const FIXED_SIZE: Option<usize> = None;
130
131    #[inline(always)]
132    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
133        writer.write_bytes(self.as_bytes())
134    }
135
136    #[inline]
137    fn read(bytes: &[u8]) -> Result<&str, Error> {
138        std::str::from_utf8(bytes).map_err(|_| Error::invalid_data("invalid UTF-8 in row string"))
139    }
140}
141
142impl RowValue for &str {
143    type View<'a> = &'a str;
144
145    const FIXED_SIZE: Option<usize> = None;
146
147    #[inline(always)]
148    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
149        writer.write_bytes(self.as_bytes())
150    }
151
152    #[inline]
153    fn read(bytes: &[u8]) -> Result<&str, Error> {
154        std::str::from_utf8(bytes).map_err(|_| Error::invalid_data("invalid UTF-8 in row string"))
155    }
156}
157
158impl RowValue for Vec<u8> {
159    type View<'a> = &'a [u8];
160
161    const FIXED_SIZE: Option<usize> = None;
162
163    #[inline(always)]
164    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
165        writer.write_bytes(self)
166    }
167
168    #[inline(always)]
169    fn read(bytes: &[u8]) -> Result<&[u8], Error> {
170        Ok(bytes)
171    }
172}
173
174impl RowValue for &[u8] {
175    type View<'a> = &'a [u8];
176
177    const FIXED_SIZE: Option<usize> = None;
178
179    #[inline(always)]
180    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
181        writer.write_bytes(self)
182    }
183
184    #[inline(always)]
185    fn read(bytes: &[u8]) -> Result<&[u8], Error> {
186        Ok(bytes)
187    }
188}
189
190impl<T: RowValue> RowValue for Option<T> {
191    type View<'a> = Option<T::View<'a>>;
192
193    const FIXED_SIZE: Option<usize> = T::FIXED_SIZE;
194
195    #[inline(always)]
196    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
197        match self {
198            Some(value) => value.write(writer),
199            None => Err(Error::invalid_data(
200                "a null row value must be written by its container",
201            )),
202        }
203    }
204
205    #[inline(always)]
206    fn read<'a>(bytes: &'a [u8]) -> Result<Self::View<'a>, Error> {
207        T::read(bytes).map(Some)
208    }
209
210    #[inline(always)]
211    fn is_null(&self) -> bool {
212        self.is_none()
213    }
214
215    #[inline(always)]
216    fn read_null<'a>() -> Result<Self::View<'a>, Error> {
217        Ok(None)
218    }
219}
220
221impl RowValue for Date {
222    type View<'a> = Self;
223
224    const FIXED_SIZE: Option<usize> = Some(4);
225
226    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
227        let days = i32::try_from(self.epoch_days()).map_err(|_| {
228            Error::invalid_data(format!(
229                "row date day count {} exceeds date32 range",
230                self.epoch_days()
231            ))
232        })?;
233        writer.write_bytes(&days.to_le_bytes())
234    }
235
236    fn read(bytes: &[u8]) -> Result<Self, Error> {
237        let days = i32::from_le_bytes(read_fixed(bytes)?);
238        Ok(Date::from_epoch_days(i64::from(days)))
239    }
240}
241
242impl RowValue for Timestamp {
243    type View<'a> = Self;
244
245    const FIXED_SIZE: Option<usize> = Some(8);
246
247    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
248        writer.write_bytes(&self.to_epoch_micros()?.to_le_bytes())
249    }
250
251    fn read(bytes: &[u8]) -> Result<Self, Error> {
252        Ok(Timestamp::from_epoch_micros(i64::from_le_bytes(
253            read_fixed(bytes)?,
254        )))
255    }
256}
257
258impl RowValue for Duration {
259    type View<'a> = Self;
260
261    const FIXED_SIZE: Option<usize> = Some(8);
262
263    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
264        writer.write_bytes(&self.to_micros()?.to_le_bytes())
265    }
266
267    fn read(bytes: &[u8]) -> Result<Self, Error> {
268        Ok(Duration::from_micros(i64::from_le_bytes(read_fixed(
269            bytes,
270        )?)))
271    }
272}
273
274impl<T: RowValue, const N: usize> RowValue for [T; N] {
275    type View<'a> = ArrayView<'a, T>;
276
277    const FIXED_SIZE: Option<usize> = None;
278
279    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
280        let mut array_writer = ArrayWriter::<T>::new(N, writer.into_variable()?)?;
281        for (index, value) in self.iter().enumerate() {
282            array_writer.write(index, value)?;
283        }
284        Ok(())
285    }
286
287    fn read(bytes: &[u8]) -> Result<Self::View<'_>, Error> {
288        let view = ArrayView::new(bytes)?;
289        if view.len() != N {
290            return Err(Error::invalid_data(format!(
291                "row fixed array expected {N} elements, found {}",
292                view.len()
293            )));
294        }
295        Ok(view)
296    }
297}
298
299impl<T: RowValue, const N: usize> Row for [T; N] {}
300
301impl<T: RowValue> RowValue for Vec<T> {
302    type View<'a> = ArrayView<'a, T>;
303
304    const FIXED_SIZE: Option<usize> = None;
305
306    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
307        let mut array_writer = ArrayWriter::<T>::new(self.len(), writer.into_variable()?)?;
308        for (index, value) in self.iter().enumerate() {
309            array_writer.write(index, value)?;
310        }
311        Ok(())
312    }
313
314    fn read(bytes: &[u8]) -> Result<Self::View<'_>, Error> {
315        ArrayView::new(bytes)
316    }
317}
318
319impl<T: RowValue> Row for Vec<T> {}
320
321impl<K, V> RowValue for BTreeMap<K, V>
322where
323    K: RowValue + Ord,
324    V: RowValue,
325{
326    type View<'a> = MapView<'a, K, V>;
327
328    const FIXED_SIZE: Option<usize> = None;
329
330    fn write(&self, writer: ValueWriter<'_, '_>) -> Result<(), Error> {
331        let mut map_writer = MapWriter::new(writer.into_variable()?);
332        map_writer.write(self)
333    }
334
335    fn read(bytes: &[u8]) -> Result<Self::View<'_>, Error> {
336        MapView::new(bytes)
337    }
338}
339
340impl<K, V> Row for BTreeMap<K, V>
341where
342    K: RowValue + Ord,
343    V: RowValue,
344{
345}
346
347fn read_fixed<const N: usize>(bytes: &[u8]) -> Result<[u8; N], Error> {
348    if bytes.len() != N {
349        return Err(Error::invalid_data(format!(
350            "row fixed-width value expected {N} bytes, found {}",
351            bytes.len()
352        )));
353    }
354    let mut value = [0u8; N];
355    value.copy_from_slice(bytes);
356    Ok(value)
357}