## Coverage Report

#### Created: 2025-11-17 14:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/arrow-rs/arrow-buffer/src/native.rs

    Line
    Count
    Source
    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
    18
    use crate::{IntervalDayTime, IntervalMonthDayNano, i256};
    19
    use half::f16;
    20
    21
    mod 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
    50
    pub 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
    93
    macro_rules! native_integer {
    94
        ($t: ty $(, $from:ident)*) => {
    95
            impl private::Sealed for $t {}
    96
            impl ArrowNativeType for $t {
    97
                #[inline]
    98
    83.5M
                fn from_usize(v: usize) -> Option<Self> {
    99
    83.5M
                    v.try_into().ok()
    100
    83.5M
                }
    101
    102
                #[inline]
    103
    442k
                fn to_usize(self) -> Option<usize> {
    104
    442k
                    self.try_into().ok()
    105
    442k
                }
    106
    107
                #[inline]
    108
    87.2k
                fn to_isize(self) -> Option<isize> {
    109
    87.2k
                    self.try_into().ok()
    110
    87.2k
                }
    111
    112
                #[inline]
    113
    0
                fn to_i64(self) -> Option<i64> {
    114
    0
                    self.try_into().ok()
    115
    0
                }
    116
    117
                #[inline]
    118
    249M
                fn as_usize(self) -> usize {
    119
    249M
                    self as _
    120
    249M
                }
    121
    122
                #[inline]
    123
    80.9k
                fn usize_as(i: usize) -> Self {
    124
    80.9k
                    i as _
    125
    80.9k
                }
    126
            }
    127
        };
    128
    }
    129
    130
    native_integer!(i8);
    131
    native_integer!(i16);
    132
    native_integer!(i32);
    133
    native_integer!(i64);
    134
    native_integer!(i128);
    135
    native_integer!(u8);
    136
    native_integer!(u16);
    137
    native_integer!(u32);
    138
    native_integer!(u64);
    139
    native_integer!(u128);
    140
    141
    macro_rules! native_float {
    142
        ($t:ty, $s:ident, $as_usize: expr, $i:ident, $usize_as: expr) => {
    143
            impl private::Sealed for $t {}
    144
            impl ArrowNativeType for $t {
    145
                #[inline]
    146
                fn from_usize(_: usize) -> Option<Self> {
    147
                    None
    148
                }
    149
    150
                #[inline]
    151
                fn to_usize(self) -> Option<usize> {
    152
                    None
    153
                }
    154
    155
                #[inline]
    156
                fn to_isize(self) -> Option<isize> {
    157
                    None
    158
                }
    159
    160
                #[inline]
    161
    0
                fn to_i64(self) -> Option<i64> {
    162
    0
                    None
    163
    0
                }
    164
    165
                #[inline]
    166
                fn as_usize($s) -> usize {
    167
                    $as_usize
    168
                }
    169
    170
                #[inline]
    171
    1
                fn usize_as($i: usize) -> Self {
    172
                    $usize_as
    173
    1
                }
    174
            }
    175
        };
    176
    }
    177
    178
    native_float!(f16, self, self.to_f32() as _, i, f16::from_f32(i as _));
    179
    native_float!(f32, self, self as _, i, i as _);
    180
    native_float!(f64, self, self as _, i, i as _);
    181
    182
    impl private::Sealed for i256 {}
    183
    impl ArrowNativeType for i256 {
    184
    0
        fn from_usize(u: usize) -> Option<Self> {
    185
    0
            Some(Self::from_parts(u as u128, 0))
    186
    0
        }
    187
    188
    0
        fn as_usize(self) -> usize {
    189
    0
            self.to_parts().0 as usize
    190
    0
        }
    191
    192
    0
        fn usize_as(i: usize) -> Self {
    193
    0
            Self::from_parts(i as u128, 0)
    194
    0
        }
    195
    196
    0
        fn to_usize(self) -> Option<usize> {
    197
    0
            let (low, high) = self.to_parts();
    198
    0
            if high != 0 {
    199
    0
                return None;
    200
    0
            }
    201
    0
            low.try_into().ok()
    202
    0
        }
    203
    204
    0
        fn to_isize(self) -> Option<isize> {
    205
    0
            self.to_i128()?.try_into().ok()
    206
    0
        }
    207
    208
    0
        fn to_i64(self) -> Option<i64> {
    209
    0
            self.to_i128()?.try_into().ok()
    210
    0
        }
    211
    }
    212
    213
    impl private::Sealed for IntervalMonthDayNano {}
    214
    impl ArrowNativeType for IntervalMonthDayNano {
    215
    0
        fn from_usize(_: usize) -> Option<Self> {
    216
    0
            None
    217
    0
        }
    218
    219
    0
        fn as_usize(self) -> usize {
    220
    0
            ((self.months as u64) | ((self.days as u64) << 32)) as usize
    221
    0
        }
    222
    223
    0
        fn usize_as(i: usize) -> Self {
    224
    0
            Self::new(i as _, ((i as u64) >> 32) as _, 0)
    225
    0
        }
    226
    227
    0
        fn to_usize(self) -> Option<usize> {
    228
    0
            None
    229
    0
        }
    230
    231
    0
        fn to_isize(self) -> Option<isize> {
    232
    0
            None
    233
    0
        }
    234
    235
    0
        fn to_i64(self) -> Option<i64> {
    236
    0
            None
    237
    0
        }
    238
    }
    239
    240
    impl private::Sealed for IntervalDayTime {}
    241
    impl ArrowNativeType for IntervalDayTime {
    242
    0
        fn from_usize(_: usize) -> Option<Self> {
    243
    0
            None
    244
    0
        }
    245
    246
    0
        fn as_usize(self) -> usize {
    247
    0
            ((self.days as u64) | ((self.milliseconds as u64) << 32)) as usize
    248
    0
        }
    249
    250
    0
        fn usize_as(i: usize) -> Self {
    251
    0
            Self::new(i as _, ((i as u64) >> 32) as _)
    252
    0
        }
    253
    254
    0
        fn to_usize(self) -> Option<usize> {
    255
    0
            None
    256
    0
        }
    257
    258
    0
        fn to_isize(self) -> Option<isize> {
    259
    0
            None
    260
    0
        }
    261
    262
    0
        fn to_i64(self) -> Option<i64> {
    263
    0
            None
    264
    0
        }
    265
    }
    266
    267
    /// Allows conversion from supported Arrow types to a byte slice.
    268
    pub trait ToByteSlice {
    269
        /// Converts this instance into a byte slice
    270
        fn to_byte_slice(&self) -> &[u8];
    271
    }
    272
    273
    impl<T: ArrowNativeType> ToByteSlice for [T] {
    274
        #[inline]
    275
    2
        fn to_byte_slice(&self) -> &[u8] {
    276
    2
            let raw_ptr = self.as_ptr() as *const u8;
    277
    2
            unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of_val(self)) }
    278
    2
        }
    279
    }
    280
    281
    impl<T: ArrowNativeType> ToByteSlice for T {
    282
        #[inline]
    283
    22.2k
        fn to_byte_slice(&self) -> &[u8] {
    284
    22.2k
            let raw_ptr = self as *const T as *const u8;
    285
    22.2k
            unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of::<T>()) }
    286
    22.2k
        }
    287
    }
    288
    289
    #[cfg(test)]
    290
    mod tests {
    291
        use super::*;
    292
    293
        #[test]
    294
        fn test_i256() {
    295
            let a = i256::from_parts(0, 0);
    296
            assert_eq!(a.as_usize(), 0);
    297
            assert_eq!(a.to_usize().unwrap(), 0);
    298
            assert_eq!(a.to_isize().unwrap(), 0);
    299
    300
            let a = i256::from_parts(0, -1);
    301
            assert_eq!(a.as_usize(), 0);
    302
            assert!(a.to_usize().is_none());
    303
            assert!(a.to_usize().is_none());
    304
    305
            let a = i256::from_parts(u128::MAX, -1);
    306
            assert_eq!(a.as_usize(), usize::MAX);
    307
            assert!(a.to_usize().is_none());
    308
            assert_eq!(a.to_isize().unwrap(), -1);
    309
        }
    310
    311
        #[test]
    312
        fn test_interval_usize() {
    313
            assert_eq!(IntervalDayTime::new(1, 0).as_usize(), 1);
    314
            assert_eq!(IntervalMonthDayNano::new(1, 0, 0).as_usize(), 1);
    315
    316
            let a = IntervalDayTime::new(23, 53);
    317
            let b = IntervalDayTime::usize_as(a.as_usize());
    318
            assert_eq!(a, b);
    319
    320
            let a = IntervalMonthDayNano::new(23, 53, 0);
    321
            let b = IntervalMonthDayNano::usize_as(a.as_usize());
    322
            assert_eq!(a, b);
    323
        }
    324
    }