arrow_buffer/
native.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 crate::{i256, IntervalDayTime, IntervalMonthDayNano};
19use half::f16;
20
21mod private {
22    pub trait Sealed {}
23}
24
25/// Trait expressing a Rust type that has the same in-memory representation as
26/// Arrow.
27///
28/// This includes `i16`, `f32`, but excludes `bool` (which in arrow is
29/// represented in bits).
30///
31/// In little endian machines, types that implement [`ArrowNativeType`] can be
32/// memcopied to arrow buffers as is.
33///
34/// # Transmute Safety
35///
36/// A type T implementing this trait means that any arbitrary slice of bytes of length and
37/// alignment `size_of::<T>()` can be safely interpreted as a value of that type without
38/// being unsound, i.e. potentially resulting in undefined behaviour.
39///
40/// Note: in the case of floating point numbers this transmutation can result in a signalling
41/// NaN, which, whilst sound, can be unwieldy. In general, whilst it is perfectly sound to
42/// reinterpret bytes as different types using this trait, it is likely unwise. For more information
43/// see [f32::from_bits] and [f64::from_bits].
44///
45/// Note: `bool` is restricted to `0` or `1`, and so `bool: !ArrowNativeType`
46///
47/// # Sealed
48///
49/// Due to the above restrictions, this trait is sealed to prevent accidental misuse
50pub trait ArrowNativeType:
51    std::fmt::Debug + Send + Sync + Copy + PartialOrd + Default + private::Sealed + 'static
52{
53    /// Returns the byte width of this native type.
54    fn get_byte_width() -> usize {
55        std::mem::size_of::<Self>()
56    }
57
58    /// Convert native integer type from usize
59    ///
60    /// Returns `None` if [`Self`] is not an integer or conversion would result
61    /// in truncation/overflow
62    fn from_usize(_: usize) -> Option<Self>;
63
64    /// Convert to usize according to the [`as`] operator
65    ///
66    /// [`as`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
67    fn as_usize(self) -> usize;
68
69    /// Convert from usize according to the [`as`] operator
70    ///
71    /// [`as`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
72    fn usize_as(i: usize) -> Self;
73
74    /// Convert native type to usize.
75    ///
76    /// Returns `None` if [`Self`] is not an integer or conversion would result
77    /// in truncation/overflow
78    fn to_usize(self) -> Option<usize>;
79
80    /// Convert native type to isize.
81    ///
82    /// Returns `None` if [`Self`] is not an integer or conversion would result
83    /// in truncation/overflow
84    fn to_isize(self) -> Option<isize>;
85
86    /// Convert native type to i64.
87    ///
88    /// Returns `None` if [`Self`] is not an integer or conversion would result
89    /// in truncation/overflow
90    fn to_i64(self) -> Option<i64>;
91
92    /// Convert native type from i32.
93    ///
94    /// Returns `None` if [`Self`] is not `i32`
95    #[deprecated(note = "please use `Option::Some` instead")]
96    fn from_i32(_: i32) -> Option<Self> {
97        None
98    }
99
100    /// Convert native type from i64.
101    ///
102    /// Returns `None` if [`Self`] is not `i64`
103    #[deprecated(note = "please use `Option::Some` instead")]
104    fn from_i64(_: i64) -> Option<Self> {
105        None
106    }
107
108    /// Convert native type from i128.
109    ///
110    /// Returns `None` if [`Self`] is not `i128`
111    #[deprecated(note = "please use `Option::Some` instead")]
112    fn from_i128(_: i128) -> Option<Self> {
113        None
114    }
115}
116
117macro_rules! native_integer {
118    ($t: ty $(, $from:ident)*) => {
119        impl private::Sealed for $t {}
120        impl ArrowNativeType for $t {
121            #[inline]
122            fn from_usize(v: usize) -> Option<Self> {
123                v.try_into().ok()
124            }
125
126            #[inline]
127            fn to_usize(self) -> Option<usize> {
128                self.try_into().ok()
129            }
130
131            #[inline]
132            fn to_isize(self) -> Option<isize> {
133                self.try_into().ok()
134            }
135
136            #[inline]
137            fn to_i64(self) -> Option<i64> {
138                self.try_into().ok()
139            }
140
141            #[inline]
142            fn as_usize(self) -> usize {
143                self as _
144            }
145
146            #[inline]
147            fn usize_as(i: usize) -> Self {
148                i as _
149            }
150
151
152            $(
153                #[inline]
154                fn $from(v: $t) -> Option<Self> {
155                    Some(v)
156                }
157            )*
158        }
159    };
160}
161
162native_integer!(i8);
163native_integer!(i16);
164native_integer!(i32, from_i32);
165native_integer!(i64, from_i64);
166native_integer!(i128, from_i128);
167native_integer!(u8);
168native_integer!(u16);
169native_integer!(u32);
170native_integer!(u64);
171native_integer!(u128);
172
173macro_rules! native_float {
174    ($t:ty, $s:ident, $as_usize: expr, $i:ident, $usize_as: expr) => {
175        impl private::Sealed for $t {}
176        impl ArrowNativeType for $t {
177            #[inline]
178            fn from_usize(_: usize) -> Option<Self> {
179                None
180            }
181
182            #[inline]
183            fn to_usize(self) -> Option<usize> {
184                None
185            }
186
187            #[inline]
188            fn to_isize(self) -> Option<isize> {
189                None
190            }
191
192            #[inline]
193            fn to_i64(self) -> Option<i64> {
194                None
195            }
196
197            #[inline]
198            fn as_usize($s) -> usize {
199                $as_usize
200            }
201
202            #[inline]
203            fn usize_as($i: usize) -> Self {
204                $usize_as
205            }
206        }
207    };
208}
209
210native_float!(f16, self, self.to_f32() as _, i, f16::from_f32(i as _));
211native_float!(f32, self, self as _, i, i as _);
212native_float!(f64, self, self as _, i, i as _);
213
214impl private::Sealed for i256 {}
215impl ArrowNativeType for i256 {
216    fn from_usize(u: usize) -> Option<Self> {
217        Some(Self::from_parts(u as u128, 0))
218    }
219
220    fn as_usize(self) -> usize {
221        self.to_parts().0 as usize
222    }
223
224    fn usize_as(i: usize) -> Self {
225        Self::from_parts(i as u128, 0)
226    }
227
228    fn to_usize(self) -> Option<usize> {
229        let (low, high) = self.to_parts();
230        if high != 0 {
231            return None;
232        }
233        low.try_into().ok()
234    }
235
236    fn to_isize(self) -> Option<isize> {
237        self.to_i128()?.try_into().ok()
238    }
239
240    fn to_i64(self) -> Option<i64> {
241        self.to_i128()?.try_into().ok()
242    }
243}
244
245impl private::Sealed for IntervalMonthDayNano {}
246impl ArrowNativeType for IntervalMonthDayNano {
247    fn from_usize(_: usize) -> Option<Self> {
248        None
249    }
250
251    fn as_usize(self) -> usize {
252        ((self.months as u64) | ((self.days as u64) << 32)) as usize
253    }
254
255    fn usize_as(i: usize) -> Self {
256        Self::new(i as _, ((i as u64) >> 32) as _, 0)
257    }
258
259    fn to_usize(self) -> Option<usize> {
260        None
261    }
262
263    fn to_isize(self) -> Option<isize> {
264        None
265    }
266
267    fn to_i64(self) -> Option<i64> {
268        None
269    }
270}
271
272impl private::Sealed for IntervalDayTime {}
273impl ArrowNativeType for IntervalDayTime {
274    fn from_usize(_: usize) -> Option<Self> {
275        None
276    }
277
278    fn as_usize(self) -> usize {
279        ((self.days as u64) | ((self.milliseconds as u64) << 32)) as usize
280    }
281
282    fn usize_as(i: usize) -> Self {
283        Self::new(i as _, ((i as u64) >> 32) as _)
284    }
285
286    fn to_usize(self) -> Option<usize> {
287        None
288    }
289
290    fn to_isize(self) -> Option<isize> {
291        None
292    }
293
294    fn to_i64(self) -> Option<i64> {
295        None
296    }
297}
298
299/// Allows conversion from supported Arrow types to a byte slice.
300pub trait ToByteSlice {
301    /// Converts this instance into a byte slice
302    fn to_byte_slice(&self) -> &[u8];
303}
304
305impl<T: ArrowNativeType> ToByteSlice for [T] {
306    #[inline]
307    fn to_byte_slice(&self) -> &[u8] {
308        let raw_ptr = self.as_ptr() as *const u8;
309        unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of_val(self)) }
310    }
311}
312
313impl<T: ArrowNativeType> ToByteSlice for T {
314    #[inline]
315    fn to_byte_slice(&self) -> &[u8] {
316        let raw_ptr = self as *const T as *const u8;
317        unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of::<T>()) }
318    }
319}
320
321#[cfg(test)]
322mod tests {
323    use super::*;
324
325    #[test]
326    fn test_i256() {
327        let a = i256::from_parts(0, 0);
328        assert_eq!(a.as_usize(), 0);
329        assert_eq!(a.to_usize().unwrap(), 0);
330        assert_eq!(a.to_isize().unwrap(), 0);
331
332        let a = i256::from_parts(0, -1);
333        assert_eq!(a.as_usize(), 0);
334        assert!(a.to_usize().is_none());
335        assert!(a.to_usize().is_none());
336
337        let a = i256::from_parts(u128::MAX, -1);
338        assert_eq!(a.as_usize(), usize::MAX);
339        assert!(a.to_usize().is_none());
340        assert_eq!(a.to_isize().unwrap(), -1);
341    }
342
343    #[test]
344    fn test_interval_usize() {
345        assert_eq!(IntervalDayTime::new(1, 0).as_usize(), 1);
346        assert_eq!(IntervalMonthDayNano::new(1, 0, 0).as_usize(), 1);
347
348        let a = IntervalDayTime::new(23, 53);
349        let b = IntervalDayTime::usize_as(a.as_usize());
350        assert_eq!(a, b);
351
352        let a = IntervalMonthDayNano::new(23, 53, 0);
353        let b = IntervalMonthDayNano::usize_as(a.as_usize());
354        assert_eq!(a, b);
355    }
356}