blob: c563f73cf5b964b5a18402221af34a665d9b6b49 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::{i256, IntervalDayTime, IntervalMonthDayNano};
use half::f16;
mod private {
pub trait Sealed {}
}
/// Trait expressing a Rust type that has the same in-memory representation as
/// Arrow.
///
/// This includes `i16`, `f32`, but excludes `bool` (which in arrow is
/// represented in bits).
///
/// In little endian machines, types that implement [`ArrowNativeType`] can be
/// memcopied to arrow buffers as is.
///
/// # Transmute Safety
///
/// A type T implementing this trait means that any arbitrary slice of bytes of length and
/// alignment `size_of::<T>()` can be safely interpreted as a value of that type without
/// being unsound, i.e. potentially resulting in undefined behaviour.
///
/// Note: in the case of floating point numbers this transmutation can result in a signalling
/// NaN, which, whilst sound, can be unwieldy. In general, whilst it is perfectly sound to
/// reinterpret bytes as different types using this trait, it is likely unwise. For more information
/// see [f32::from_bits] and [f64::from_bits].
///
/// Note: `bool` is restricted to `0` or `1`, and so `bool: !ArrowNativeType`
///
/// # Sealed
///
/// Due to the above restrictions, this trait is sealed to prevent accidental misuse
pub trait ArrowNativeType:
std::fmt::Debug + Send + Sync + Copy + PartialOrd + Default + private::Sealed + 'static
{
/// Returns the byte width of this native type.
fn get_byte_width() -> usize {
std::mem::size_of::<Self>()
}
/// Convert native integer type from usize
///
/// Returns `None` if [`Self`] is not an integer or conversion would result
/// in truncation/overflow
fn from_usize(_: usize) -> Option<Self>;
/// Convert to usize according to the [`as`] operator
///
/// [`as`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
fn as_usize(self) -> usize;
/// Convert from usize according to the [`as`] operator
///
/// [`as`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
fn usize_as(i: usize) -> Self;
/// Convert native type to usize.
///
/// Returns `None` if [`Self`] is not an integer or conversion would result
/// in truncation/overflow
fn to_usize(self) -> Option<usize>;
/// Convert native type to isize.
///
/// Returns `None` if [`Self`] is not an integer or conversion would result
/// in truncation/overflow
fn to_isize(self) -> Option<isize>;
/// Convert native type to i64.
///
/// Returns `None` if [`Self`] is not an integer or conversion would result
/// in truncation/overflow
fn to_i64(self) -> Option<i64>;
/// Convert native type from i32.
///
/// Returns `None` if [`Self`] is not `i32`
#[deprecated(note = "please use `Option::Some` instead")]
fn from_i32(_: i32) -> Option<Self> {
None
}
/// Convert native type from i64.
///
/// Returns `None` if [`Self`] is not `i64`
#[deprecated(note = "please use `Option::Some` instead")]
fn from_i64(_: i64) -> Option<Self> {
None
}
/// Convert native type from i128.
///
/// Returns `None` if [`Self`] is not `i128`
#[deprecated(note = "please use `Option::Some` instead")]
fn from_i128(_: i128) -> Option<Self> {
None
}
}
macro_rules! native_integer {
($t: ty $(, $from:ident)*) => {
impl private::Sealed for $t {}
impl ArrowNativeType for $t {
#[inline]
fn from_usize(v: usize) -> Option<Self> {
v.try_into().ok()
}
#[inline]
fn to_usize(self) -> Option<usize> {
self.try_into().ok()
}
#[inline]
fn to_isize(self) -> Option<isize> {
self.try_into().ok()
}
#[inline]
fn to_i64(self) -> Option<i64> {
self.try_into().ok()
}
#[inline]
fn as_usize(self) -> usize {
self as _
}
#[inline]
fn usize_as(i: usize) -> Self {
i as _
}
$(
#[inline]
fn $from(v: $t) -> Option<Self> {
Some(v)
}
)*
}
};
}
native_integer!(i8);
native_integer!(i16);
native_integer!(i32, from_i32);
native_integer!(i64, from_i64);
native_integer!(i128, from_i128);
native_integer!(u8);
native_integer!(u16);
native_integer!(u32);
native_integer!(u64);
native_integer!(u128);
macro_rules! native_float {
($t:ty, $s:ident, $as_usize: expr, $i:ident, $usize_as: expr) => {
impl private::Sealed for $t {}
impl ArrowNativeType for $t {
#[inline]
fn from_usize(_: usize) -> Option<Self> {
None
}
#[inline]
fn to_usize(self) -> Option<usize> {
None
}
#[inline]
fn to_isize(self) -> Option<isize> {
None
}
#[inline]
fn to_i64(self) -> Option<i64> {
None
}
#[inline]
fn as_usize($s) -> usize {
$as_usize
}
#[inline]
fn usize_as($i: usize) -> Self {
$usize_as
}
}
};
}
native_float!(f16, self, self.to_f32() as _, i, f16::from_f32(i as _));
native_float!(f32, self, self as _, i, i as _);
native_float!(f64, self, self as _, i, i as _);
impl private::Sealed for i256 {}
impl ArrowNativeType for i256 {
fn from_usize(u: usize) -> Option<Self> {
Some(Self::from_parts(u as u128, 0))
}
fn as_usize(self) -> usize {
self.to_parts().0 as usize
}
fn usize_as(i: usize) -> Self {
Self::from_parts(i as u128, 0)
}
fn to_usize(self) -> Option<usize> {
let (low, high) = self.to_parts();
if high != 0 {
return None;
}
low.try_into().ok()
}
fn to_isize(self) -> Option<isize> {
self.to_i128()?.try_into().ok()
}
fn to_i64(self) -> Option<i64> {
self.to_i128()?.try_into().ok()
}
}
impl private::Sealed for IntervalMonthDayNano {}
impl ArrowNativeType for IntervalMonthDayNano {
fn from_usize(_: usize) -> Option<Self> {
None
}
fn as_usize(self) -> usize {
((self.months as u64) | ((self.days as u64) << 32)) as usize
}
fn usize_as(i: usize) -> Self {
Self::new(i as _, ((i as u64) >> 32) as _, 0)
}
fn to_usize(self) -> Option<usize> {
None
}
fn to_isize(self) -> Option<isize> {
None
}
fn to_i64(self) -> Option<i64> {
None
}
}
impl private::Sealed for IntervalDayTime {}
impl ArrowNativeType for IntervalDayTime {
fn from_usize(_: usize) -> Option<Self> {
None
}
fn as_usize(self) -> usize {
((self.days as u64) | ((self.milliseconds as u64) << 32)) as usize
}
fn usize_as(i: usize) -> Self {
Self::new(i as _, ((i as u64) >> 32) as _)
}
fn to_usize(self) -> Option<usize> {
None
}
fn to_isize(self) -> Option<isize> {
None
}
fn to_i64(self) -> Option<i64> {
None
}
}
/// Allows conversion from supported Arrow types to a byte slice.
pub trait ToByteSlice {
/// Converts this instance into a byte slice
fn to_byte_slice(&self) -> &[u8];
}
impl<T: ArrowNativeType> ToByteSlice for [T] {
#[inline]
fn to_byte_slice(&self) -> &[u8] {
let raw_ptr = self.as_ptr() as *const u8;
unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of_val(self)) }
}
}
impl<T: ArrowNativeType> ToByteSlice for T {
#[inline]
fn to_byte_slice(&self) -> &[u8] {
let raw_ptr = self as *const T as *const u8;
unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of::<T>()) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_i256() {
let a = i256::from_parts(0, 0);
assert_eq!(a.as_usize(), 0);
assert_eq!(a.to_usize().unwrap(), 0);
assert_eq!(a.to_isize().unwrap(), 0);
let a = i256::from_parts(0, -1);
assert_eq!(a.as_usize(), 0);
assert!(a.to_usize().is_none());
assert!(a.to_usize().is_none());
let a = i256::from_parts(u128::MAX, -1);
assert_eq!(a.as_usize(), usize::MAX);
assert!(a.to_usize().is_none());
assert_eq!(a.to_isize().unwrap(), -1);
}
#[test]
fn test_interval_usize() {
assert_eq!(IntervalDayTime::new(1, 0).as_usize(), 1);
assert_eq!(IntervalMonthDayNano::new(1, 0, 0).as_usize(), 1);
let a = IntervalDayTime::new(23, 53);
let b = IntervalDayTime::usize_as(a.as_usize());
assert_eq!(a, b);
let a = IntervalMonthDayNano::new(23, 53, 0);
let b = IntervalMonthDayNano::usize_as(a.as_usize());
assert_eq!(a, b);
}
}