polars_arrow/types/
native.rs

1use std::hash::{Hash, Hasher};
2use std::ops::Neg;
3use std::panic::RefUnwindSafe;
4
5use bytemuck::{Pod, Zeroable};
6use polars_utils::min_max::MinMax;
7use polars_utils::nulls::IsNull;
8use polars_utils::total_ord::{ToTotalOrd, TotalEq, TotalHash, TotalOrd, TotalOrdWrap};
9
10use super::PrimitiveType;
11use super::aligned_bytes::*;
12
13/// Sealed trait implemented by all physical types that can be allocated,
14/// serialized and deserialized by this crate.
15/// All O(N) allocations in this crate are done for this trait alone.
16pub trait NativeType:
17    super::private::Sealed
18    + Pod
19    + Send
20    + Sync
21    + Sized
22    + RefUnwindSafe
23    + std::fmt::Debug
24    + std::fmt::Display
25    + PartialEq
26    + Default
27    + Copy
28    + TotalOrd
29    + IsNull
30    + MinMax
31{
32    /// The corresponding variant of [`PrimitiveType`].
33    const PRIMITIVE: PrimitiveType;
34
35    /// Type denoting its representation as bytes.
36    /// This is `[u8; N]` where `N = size_of::<T>`.
37    type Bytes: AsRef<[u8]>
38        + AsMut<[u8]>
39        + std::ops::Index<usize, Output = u8>
40        + std::ops::IndexMut<usize, Output = u8>
41        + for<'a> TryFrom<&'a [u8]>
42        + std::fmt::Debug
43        + Default
44        + IntoIterator<Item = u8>;
45
46    /// Type denoting its representation as aligned bytes.
47    ///
48    /// This is `[u8; N]` where `N = size_of::<Self>` and has alignment `align_of::<Self>`.
49    type AlignedBytes: AlignedBytes<Unaligned = Self::Bytes> + From<Self> + Into<Self>;
50
51    /// To bytes in little endian
52    fn to_le_bytes(&self) -> Self::Bytes;
53
54    /// To bytes in big endian
55    fn to_be_bytes(&self) -> Self::Bytes;
56
57    /// From bytes in little endian
58    fn from_le_bytes(bytes: Self::Bytes) -> Self;
59
60    /// From bytes in big endian
61    fn from_be_bytes(bytes: Self::Bytes) -> Self;
62}
63
64macro_rules! native_type {
65    ($type:ty, $aligned:ty, $primitive_type:expr) => {
66        impl NativeType for $type {
67            const PRIMITIVE: PrimitiveType = $primitive_type;
68
69            type Bytes = [u8; std::mem::size_of::<Self>()];
70            type AlignedBytes = $aligned;
71
72            #[inline]
73            fn to_le_bytes(&self) -> Self::Bytes {
74                Self::to_le_bytes(*self)
75            }
76
77            #[inline]
78            fn to_be_bytes(&self) -> Self::Bytes {
79                Self::to_be_bytes(*self)
80            }
81
82            #[inline]
83            fn from_le_bytes(bytes: Self::Bytes) -> Self {
84                Self::from_le_bytes(bytes)
85            }
86
87            #[inline]
88            fn from_be_bytes(bytes: Self::Bytes) -> Self {
89                Self::from_be_bytes(bytes)
90            }
91        }
92    };
93}
94
95native_type!(u8, Bytes1Alignment1, PrimitiveType::UInt8);
96native_type!(u16, Bytes2Alignment2, PrimitiveType::UInt16);
97native_type!(u32, Bytes4Alignment4, PrimitiveType::UInt32);
98native_type!(u64, Bytes8Alignment8, PrimitiveType::UInt64);
99native_type!(i8, Bytes1Alignment1, PrimitiveType::Int8);
100native_type!(i16, Bytes2Alignment2, PrimitiveType::Int16);
101native_type!(i32, Bytes4Alignment4, PrimitiveType::Int32);
102native_type!(i64, Bytes8Alignment8, PrimitiveType::Int64);
103native_type!(f32, Bytes4Alignment4, PrimitiveType::Float32);
104native_type!(f64, Bytes8Alignment8, PrimitiveType::Float64);
105native_type!(i128, Bytes16Alignment16, PrimitiveType::Int128);
106native_type!(u128, Bytes16Alignment16, PrimitiveType::UInt128);
107
108/// The in-memory representation of the DayMillisecond variant of arrow's "Interval" logical type.
109#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroable, Pod)]
110#[allow(non_camel_case_types)]
111#[repr(C)]
112pub struct days_ms(pub i32, pub i32);
113
114impl days_ms {
115    /// A new [`days_ms`].
116    #[inline]
117    pub fn new(days: i32, milliseconds: i32) -> Self {
118        Self(days, milliseconds)
119    }
120
121    /// The number of days
122    #[inline]
123    pub fn days(&self) -> i32 {
124        self.0
125    }
126
127    /// The number of milliseconds
128    #[inline]
129    pub fn milliseconds(&self) -> i32 {
130        self.1
131    }
132}
133
134impl TotalEq for days_ms {
135    #[inline]
136    fn tot_eq(&self, other: &Self) -> bool {
137        self == other
138    }
139}
140
141impl TotalOrd for days_ms {
142    #[inline]
143    fn tot_cmp(&self, other: &Self) -> std::cmp::Ordering {
144        self.days()
145            .cmp(&other.days())
146            .then(self.milliseconds().cmp(&other.milliseconds()))
147    }
148}
149
150impl MinMax for days_ms {
151    fn nan_min_lt(&self, other: &Self) -> bool {
152        self < other
153    }
154
155    fn nan_max_lt(&self, other: &Self) -> bool {
156        self < other
157    }
158}
159
160impl NativeType for days_ms {
161    const PRIMITIVE: PrimitiveType = PrimitiveType::DaysMs;
162
163    type Bytes = [u8; 8];
164    type AlignedBytes = Bytes8Alignment4;
165
166    #[inline]
167    fn to_le_bytes(&self) -> Self::Bytes {
168        let days = self.0.to_le_bytes();
169        let ms = self.1.to_le_bytes();
170        let mut result = [0; 8];
171        result[0] = days[0];
172        result[1] = days[1];
173        result[2] = days[2];
174        result[3] = days[3];
175        result[4] = ms[0];
176        result[5] = ms[1];
177        result[6] = ms[2];
178        result[7] = ms[3];
179        result
180    }
181
182    #[inline]
183    fn to_be_bytes(&self) -> Self::Bytes {
184        let days = self.0.to_be_bytes();
185        let ms = self.1.to_be_bytes();
186        let mut result = [0; 8];
187        result[0] = days[0];
188        result[1] = days[1];
189        result[2] = days[2];
190        result[3] = days[3];
191        result[4] = ms[0];
192        result[5] = ms[1];
193        result[6] = ms[2];
194        result[7] = ms[3];
195        result
196    }
197
198    #[inline]
199    fn from_le_bytes(bytes: Self::Bytes) -> Self {
200        let mut days = [0; 4];
201        days[0] = bytes[0];
202        days[1] = bytes[1];
203        days[2] = bytes[2];
204        days[3] = bytes[3];
205        let mut ms = [0; 4];
206        ms[0] = bytes[4];
207        ms[1] = bytes[5];
208        ms[2] = bytes[6];
209        ms[3] = bytes[7];
210        Self(i32::from_le_bytes(days), i32::from_le_bytes(ms))
211    }
212
213    #[inline]
214    fn from_be_bytes(bytes: Self::Bytes) -> Self {
215        let mut days = [0; 4];
216        days[0] = bytes[0];
217        days[1] = bytes[1];
218        days[2] = bytes[2];
219        days[3] = bytes[3];
220        let mut ms = [0; 4];
221        ms[0] = bytes[4];
222        ms[1] = bytes[5];
223        ms[2] = bytes[6];
224        ms[3] = bytes[7];
225        Self(i32::from_be_bytes(days), i32::from_be_bytes(ms))
226    }
227}
228
229/// The in-memory representation of the MonthDayNano variant of the "Interval" logical type.
230#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroable, Pod)]
231#[allow(non_camel_case_types)]
232#[repr(C)]
233pub struct months_days_ns(pub i32, pub i32, pub i64);
234
235impl IsNull for months_days_ns {
236    const HAS_NULLS: bool = false;
237    type Inner = months_days_ns;
238
239    fn is_null(&self) -> bool {
240        false
241    }
242
243    fn unwrap_inner(self) -> Self::Inner {
244        self
245    }
246}
247
248impl months_days_ns {
249    /// A new [`months_days_ns`].
250    #[inline]
251    pub fn new(months: i32, days: i32, nanoseconds: i64) -> Self {
252        Self(months, days, nanoseconds)
253    }
254
255    /// The number of months
256    #[inline]
257    pub fn months(&self) -> i32 {
258        self.0
259    }
260
261    /// The number of days
262    #[inline]
263    pub fn days(&self) -> i32 {
264        self.1
265    }
266
267    /// The number of nanoseconds
268    #[inline]
269    pub fn ns(&self) -> i64 {
270        self.2
271    }
272}
273
274impl TotalEq for months_days_ns {
275    #[inline]
276    fn tot_eq(&self, other: &Self) -> bool {
277        self == other
278    }
279}
280
281impl TotalOrd for months_days_ns {
282    #[inline]
283    fn tot_cmp(&self, other: &Self) -> std::cmp::Ordering {
284        self.months()
285            .cmp(&other.months())
286            .then(self.days().cmp(&other.days()))
287            .then(self.ns().cmp(&other.ns()))
288    }
289}
290
291impl MinMax for months_days_ns {
292    fn nan_min_lt(&self, other: &Self) -> bool {
293        self < other
294    }
295
296    fn nan_max_lt(&self, other: &Self) -> bool {
297        self < other
298    }
299}
300
301impl NativeType for months_days_ns {
302    const PRIMITIVE: PrimitiveType = PrimitiveType::MonthDayNano;
303
304    type Bytes = [u8; 16];
305    type AlignedBytes = Bytes16Alignment8;
306
307    #[inline]
308    fn to_le_bytes(&self) -> Self::Bytes {
309        let months = self.months().to_le_bytes();
310        let days = self.days().to_le_bytes();
311        let ns = self.ns().to_le_bytes();
312        let mut result = [0; 16];
313        result[0] = months[0];
314        result[1] = months[1];
315        result[2] = months[2];
316        result[3] = months[3];
317        result[4] = days[0];
318        result[5] = days[1];
319        result[6] = days[2];
320        result[7] = days[3];
321        (0..8).for_each(|i| {
322            result[8 + i] = ns[i];
323        });
324        result
325    }
326
327    #[inline]
328    fn to_be_bytes(&self) -> Self::Bytes {
329        let months = self.months().to_be_bytes();
330        let days = self.days().to_be_bytes();
331        let ns = self.ns().to_be_bytes();
332        let mut result = [0; 16];
333        result[0] = months[0];
334        result[1] = months[1];
335        result[2] = months[2];
336        result[3] = months[3];
337        result[4] = days[0];
338        result[5] = days[1];
339        result[6] = days[2];
340        result[7] = days[3];
341        (0..8).for_each(|i| {
342            result[8 + i] = ns[i];
343        });
344        result
345    }
346
347    #[inline]
348    fn from_le_bytes(bytes: Self::Bytes) -> Self {
349        let mut months = [0; 4];
350        months[0] = bytes[0];
351        months[1] = bytes[1];
352        months[2] = bytes[2];
353        months[3] = bytes[3];
354        let mut days = [0; 4];
355        days[0] = bytes[4];
356        days[1] = bytes[5];
357        days[2] = bytes[6];
358        days[3] = bytes[7];
359        let mut ns = [0; 8];
360        (0..8).for_each(|i| {
361            ns[i] = bytes[8 + i];
362        });
363        Self(
364            i32::from_le_bytes(months),
365            i32::from_le_bytes(days),
366            i64::from_le_bytes(ns),
367        )
368    }
369
370    #[inline]
371    fn from_be_bytes(bytes: Self::Bytes) -> Self {
372        let mut months = [0; 4];
373        months[0] = bytes[0];
374        months[1] = bytes[1];
375        months[2] = bytes[2];
376        months[3] = bytes[3];
377        let mut days = [0; 4];
378        days[0] = bytes[4];
379        days[1] = bytes[5];
380        days[2] = bytes[6];
381        days[3] = bytes[7];
382        let mut ns = [0; 8];
383        (0..8).for_each(|i| {
384            ns[i] = bytes[8 + i];
385        });
386        Self(
387            i32::from_be_bytes(months),
388            i32::from_be_bytes(days),
389            i64::from_be_bytes(ns),
390        )
391    }
392}
393
394impl IsNull for days_ms {
395    const HAS_NULLS: bool = false;
396    type Inner = days_ms;
397    fn is_null(&self) -> bool {
398        false
399    }
400    fn unwrap_inner(self) -> Self::Inner {
401        self
402    }
403}
404
405impl std::fmt::Display for days_ms {
406    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
407        write!(f, "{}d {}ms", self.days(), self.milliseconds())
408    }
409}
410
411impl std::fmt::Display for months_days_ns {
412    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413        write!(f, "{}m {}d {}ns", self.months(), self.days(), self.ns())
414    }
415}
416
417impl Neg for days_ms {
418    type Output = Self;
419
420    #[inline(always)]
421    fn neg(self) -> Self::Output {
422        Self::new(-self.days(), -self.milliseconds())
423    }
424}
425
426impl Neg for months_days_ns {
427    type Output = Self;
428
429    #[inline(always)]
430    fn neg(self) -> Self::Output {
431        Self::new(-self.months(), -self.days(), -self.ns())
432    }
433}
434
435/// Type representation of the Float16 physical type
436#[derive(Copy, Clone, Default, Zeroable, Pod)]
437#[allow(non_camel_case_types)]
438#[repr(C)]
439pub struct f16(pub u16);
440
441impl PartialEq for f16 {
442    #[inline]
443    fn eq(&self, other: &f16) -> bool {
444        if self.is_nan() || other.is_nan() {
445            false
446        } else {
447            (self.0 == other.0) || ((self.0 | other.0) & 0x7FFFu16 == 0)
448        }
449    }
450}
451
452/// Converts an f32 into a canonical form, where -0 == 0 and all NaNs map to
453/// the same value.
454#[inline]
455pub fn canonical_f16(x: f16) -> f16 {
456    // zero out the sign bit if the f16 is zero.
457    let convert_zero = f16(x.0 & (0x7FFF | (u16::from(x.0 & 0x7FFF == 0) << 15)));
458    if convert_zero.is_nan() {
459        f16::from_bits(0x7c00) // Canonical quiet NaN.
460    } else {
461        convert_zero
462    }
463}
464
465impl TotalHash for f16 {
466    #[inline(always)]
467    fn tot_hash<H>(&self, state: &mut H)
468    where
469        H: Hasher,
470    {
471        canonical_f16(*self).to_bits().hash(state)
472    }
473}
474
475impl ToTotalOrd for f16 {
476    type TotalOrdItem = TotalOrdWrap<f16>;
477    type SourceItem = f16;
478
479    #[inline]
480    fn to_total_ord(&self) -> Self::TotalOrdItem {
481        TotalOrdWrap(*self)
482    }
483
484    #[inline]
485    fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem {
486        ord_item.0
487    }
488}
489
490impl IsNull for f16 {
491    const HAS_NULLS: bool = false;
492    type Inner = f16;
493
494    #[inline(always)]
495    fn is_null(&self) -> bool {
496        false
497    }
498    fn unwrap_inner(self) -> Self::Inner {
499        self
500    }
501}
502
503// see https://github.com/starkat99/half-rs/blob/main/src/binary16.rs
504impl f16 {
505    /// The difference between 1.0 and the next largest representable number.
506    pub const EPSILON: f16 = f16(0x1400u16);
507
508    #[inline]
509    #[must_use]
510    pub(crate) const fn is_nan(self) -> bool {
511        self.0 & 0x7FFFu16 > 0x7C00u16
512    }
513
514    /// Casts from u16.
515    #[inline]
516    pub const fn from_bits(bits: u16) -> f16 {
517        f16(bits)
518    }
519
520    /// Casts to u16.
521    #[inline]
522    pub const fn to_bits(self) -> u16 {
523        self.0
524    }
525
526    /// Casts this `f16` to `f32`
527    pub fn to_f32(self) -> f32 {
528        let i = self.0;
529        // Check for signed zero
530        if i & 0x7FFFu16 == 0 {
531            return f32::from_bits((i as u32) << 16);
532        }
533
534        let half_sign = (i & 0x8000u16) as u32;
535        let half_exp = (i & 0x7C00u16) as u32;
536        let half_man = (i & 0x03FFu16) as u32;
537
538        // Check for an infinity or NaN when all exponent bits set
539        if half_exp == 0x7C00u32 {
540            // Check for signed infinity if mantissa is zero
541            if half_man == 0 {
542                let number = (half_sign << 16) | 0x7F80_0000u32;
543                return f32::from_bits(number);
544            } else {
545                // NaN, keep current mantissa but also set most significiant mantissa bit
546                let number = (half_sign << 16) | 0x7FC0_0000u32 | (half_man << 13);
547                return f32::from_bits(number);
548            }
549        }
550
551        // Calculate single-precision components with adjusted exponent
552        let sign = half_sign << 16;
553        // Unbias exponent
554        let unbiased_exp = ((half_exp as i32) >> 10) - 15;
555
556        // Check for subnormals, which will be normalized by adjusting exponent
557        if half_exp == 0 {
558            // Calculate how much to adjust the exponent by
559            let e = (half_man as u16).leading_zeros() - 6;
560
561            // Rebias and adjust exponent
562            let exp = (127 - 15 - e) << 23;
563            let man = (half_man << (14 + e)) & 0x7F_FF_FFu32;
564            return f32::from_bits(sign | exp | man);
565        }
566
567        // Rebias exponent for a normalized normal
568        let exp = ((unbiased_exp + 127) as u32) << 23;
569        let man = (half_man & 0x03FFu32) << 13;
570        f32::from_bits(sign | exp | man)
571    }
572
573    /// Casts an `f32` into `f16`
574    pub fn from_f32(value: f32) -> Self {
575        let x: u32 = value.to_bits();
576
577        // Extract IEEE754 components
578        let sign = x & 0x8000_0000u32;
579        let exp = x & 0x7F80_0000u32;
580        let man = x & 0x007F_FFFFu32;
581
582        // Check for all exponent bits being set, which is Infinity or NaN
583        if exp == 0x7F80_0000u32 {
584            // Set mantissa MSB for NaN (and also keep shifted mantissa bits)
585            let nan_bit = if man == 0 { 0 } else { 0x0200u32 };
586            return f16(((sign >> 16) | 0x7C00u32 | nan_bit | (man >> 13)) as u16);
587        }
588
589        // The number is normalized, start assembling half precision version
590        let half_sign = sign >> 16;
591        // Unbias the exponent, then bias for half precision
592        let unbiased_exp = ((exp >> 23) as i32) - 127;
593        let half_exp = unbiased_exp + 15;
594
595        // Check for exponent overflow, return +infinity
596        if half_exp >= 0x1F {
597            return f16((half_sign | 0x7C00u32) as u16);
598        }
599
600        // Check for underflow
601        if half_exp <= 0 {
602            // Check mantissa for what we can do
603            if 14 - half_exp > 24 {
604                // No rounding possibility, so this is a full underflow, return signed zero
605                return f16(half_sign as u16);
606            }
607            // Don't forget about hidden leading mantissa bit when assembling mantissa
608            let man = man | 0x0080_0000u32;
609            let mut half_man = man >> (14 - half_exp);
610            // Check for rounding (see comment above functions)
611            let round_bit = 1 << (13 - half_exp);
612            if (man & round_bit) != 0 && (man & (3 * round_bit - 1)) != 0 {
613                half_man += 1;
614            }
615            // No exponent for subnormals
616            return f16((half_sign | half_man) as u16);
617        }
618
619        // Rebias the exponent
620        let half_exp = (half_exp as u32) << 10;
621        let half_man = man >> 13;
622        // Check for rounding (see comment above functions)
623        let round_bit = 0x0000_1000u32;
624        if (man & round_bit) != 0 && (man & (3 * round_bit - 1)) != 0 {
625            // Round it
626            f16(((half_sign | half_exp | half_man) + 1) as u16)
627        } else {
628            f16((half_sign | half_exp | half_man) as u16)
629        }
630    }
631}
632
633impl std::fmt::Debug for f16 {
634    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
635        write!(f, "{:?}", self.to_f32())
636    }
637}
638
639impl std::fmt::Display for f16 {
640    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
641        write!(f, "{}", self.to_f32())
642    }
643}
644
645impl TotalEq for f16 {
646    #[inline]
647    fn tot_eq(&self, other: &Self) -> bool {
648        if self.is_nan() {
649            other.is_nan()
650        } else {
651            self == other
652        }
653    }
654}
655
656impl TotalOrd for f16 {
657    #[inline]
658    fn tot_cmp(&self, _other: &Self) -> std::cmp::Ordering {
659        unimplemented!()
660    }
661}
662
663impl MinMax for f16 {
664    fn nan_min_lt(&self, _other: &Self) -> bool {
665        unimplemented!()
666    }
667
668    fn nan_max_lt(&self, _other: &Self) -> bool {
669        unimplemented!()
670    }
671}
672
673impl NativeType for f16 {
674    const PRIMITIVE: PrimitiveType = PrimitiveType::Float16;
675
676    type Bytes = [u8; 2];
677    type AlignedBytes = Bytes2Alignment2;
678
679    #[inline]
680    fn to_le_bytes(&self) -> Self::Bytes {
681        self.0.to_le_bytes()
682    }
683
684    #[inline]
685    fn to_be_bytes(&self) -> Self::Bytes {
686        self.0.to_be_bytes()
687    }
688
689    #[inline]
690    fn from_be_bytes(bytes: Self::Bytes) -> Self {
691        Self(u16::from_be_bytes(bytes))
692    }
693
694    #[inline]
695    fn from_le_bytes(bytes: Self::Bytes) -> Self {
696        Self(u16::from_le_bytes(bytes))
697    }
698}
699
700/// Physical representation of a decimal
701#[derive(Clone, Copy, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
702#[allow(non_camel_case_types)]
703#[repr(C)]
704pub struct i256(pub ethnum::I256);
705
706impl i256 {
707    /// Returns a new [`i256`] from two `i128`.
708    pub fn from_words(hi: i128, lo: i128) -> Self {
709        Self(ethnum::I256::from_words(hi, lo))
710    }
711}
712
713impl TryFrom<i256> for i128 {
714    type Error = core::num::TryFromIntError;
715
716    fn try_from(value: i256) -> Result<Self, Self::Error> {
717        value.0.try_into()
718    }
719}
720
721impl IsNull for i256 {
722    const HAS_NULLS: bool = false;
723    type Inner = i256;
724    #[inline(always)]
725    fn is_null(&self) -> bool {
726        false
727    }
728    fn unwrap_inner(self) -> Self::Inner {
729        self
730    }
731}
732
733impl Neg for i256 {
734    type Output = Self;
735
736    #[inline]
737    fn neg(self) -> Self::Output {
738        let (a, b) = self.0.into_words();
739        Self(ethnum::I256::from_words(-a, b))
740    }
741}
742
743impl std::fmt::Debug for i256 {
744    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
745        write!(f, "{:?}", self.0)
746    }
747}
748
749impl std::fmt::Display for i256 {
750    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
751        write!(f, "{}", self.0)
752    }
753}
754
755unsafe impl Pod for i256 {}
756unsafe impl Zeroable for i256 {}
757
758impl TotalEq for i256 {
759    #[inline]
760    fn tot_eq(&self, other: &Self) -> bool {
761        self == other
762    }
763}
764
765impl TotalOrd for i256 {
766    #[inline]
767    fn tot_cmp(&self, other: &Self) -> std::cmp::Ordering {
768        self.cmp(other)
769    }
770}
771
772impl MinMax for i256 {
773    fn nan_min_lt(&self, other: &Self) -> bool {
774        self < other
775    }
776
777    fn nan_max_lt(&self, other: &Self) -> bool {
778        self < other
779    }
780}
781
782impl NativeType for i256 {
783    const PRIMITIVE: PrimitiveType = PrimitiveType::Int256;
784
785    type Bytes = [u8; 32];
786    type AlignedBytes = Bytes32Alignment16;
787
788    #[inline]
789    fn to_le_bytes(&self) -> Self::Bytes {
790        let mut bytes = [0u8; 32];
791        let (a, b) = self.0.into_words();
792        let a = a.to_le_bytes();
793        (0..16).for_each(|i| {
794            bytes[i] = a[i];
795        });
796
797        let b = b.to_le_bytes();
798        (0..16).for_each(|i| {
799            bytes[i + 16] = b[i];
800        });
801
802        bytes
803    }
804
805    #[inline]
806    fn to_be_bytes(&self) -> Self::Bytes {
807        let mut bytes = [0u8; 32];
808        let (a, b) = self.0.into_words();
809
810        let a = a.to_be_bytes();
811        (0..16).for_each(|i| {
812            bytes[i] = a[i];
813        });
814
815        let b = b.to_be_bytes();
816        (0..16).for_each(|i| {
817            bytes[i + 16] = b[i];
818        });
819
820        bytes
821    }
822
823    #[inline]
824    fn from_be_bytes(bytes: Self::Bytes) -> Self {
825        let (a, b) = bytes.split_at(16);
826        let a: [u8; 16] = a.try_into().unwrap();
827        let b: [u8; 16] = b.try_into().unwrap();
828        let a = i128::from_be_bytes(a);
829        let b = i128::from_be_bytes(b);
830        Self(ethnum::I256::from_words(a, b))
831    }
832
833    #[inline]
834    fn from_le_bytes(bytes: Self::Bytes) -> Self {
835        let (b, a) = bytes.split_at(16);
836        let a: [u8; 16] = a.try_into().unwrap();
837        let b: [u8; 16] = b.try_into().unwrap();
838        let a = i128::from_le_bytes(a);
839        let b = i128::from_le_bytes(b);
840        Self(ethnum::I256::from_words(a, b))
841    }
842}
843
844#[cfg(test)]
845mod test {
846    use super::*;
847    #[test]
848    fn test_f16_to_f32() {
849        let f = f16::from_f32(7.0);
850        assert_eq!(f.to_f32(), 7.0f32);
851
852        // 7.1 is NOT exactly representable in 16-bit, it's rounded
853        let f = f16::from_f32(7.1);
854        let diff = (f.to_f32() - 7.1f32).abs();
855        // diff must be <= 4 * EPSILON, as 7 has two more significant bits than 1
856        assert!(diff <= 4.0 * f16::EPSILON.to_f32());
857
858        assert_eq!(f16(0x0000_0001).to_f32(), 2.0f32.powi(-24));
859        assert_eq!(f16(0x0000_0005).to_f32(), 5.0 * 2.0f32.powi(-24));
860
861        assert_eq!(f16(0x0000_0001), f16::from_f32(2.0f32.powi(-24)));
862        assert_eq!(f16(0x0000_0005), f16::from_f32(5.0 * 2.0f32.powi(-24)));
863
864        assert_eq!(format!("{}", f16::from_f32(7.0)), "7".to_string());
865        assert_eq!(format!("{:?}", f16::from_f32(7.0)), "7.0".to_string());
866    }
867}