1use std::cmp::Ordering;
7use std::fmt::Debug;
8use std::fmt::Display;
9use std::fmt::Formatter;
10use std::hash::Hash;
11use std::ops::AddAssign;
12use std::panic::RefUnwindSafe;
13
14use num_traits::AsPrimitive;
15use num_traits::Bounded;
16use num_traits::Num;
17use num_traits::NumCast;
18use num_traits::PrimInt;
19use num_traits::ToPrimitive;
20use num_traits::Unsigned;
21use num_traits::bounds::UpperBounded;
22use vortex_error::VortexError;
23use vortex_error::VortexResult;
24use vortex_error::vortex_err;
25
26use crate::DType;
27use crate::FromPrimitiveOrF16;
28use crate::half::f16;
29use crate::nullability::Nullability::NonNullable;
30
31#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Hash, prost::Enumeration)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
35#[repr(u8)]
36pub enum PType {
37 U8 = 0,
39 U16 = 1,
41 U32 = 2,
43 U64 = 3,
45 I8 = 4,
47 I16 = 5,
49 I32 = 6,
51 I64 = 7,
53 F16 = 8,
55 F32 = 9,
57 F64 = 10,
59}
60
61pub trait IntegerPType:
68 NativePType + PrimInt + ToPrimitive + Bounded + AddAssign + AsPrimitive<usize>
69{
70 fn max_value_as_u64() -> u64 {
72 Self::PTYPE.max_value_as_u64()
73 }
74}
75
76impl<T> IntegerPType for T where
78 T: NativePType + PrimInt + ToPrimitive + Bounded + AddAssign + AsPrimitive<usize>
79{
80}
81
82pub trait UnsignedPType: IntegerPType + Unsigned {}
89
90impl<T> UnsignedPType for T where T: IntegerPType + Unsigned {}
92
93pub trait NativePType:
98 Send
99 + Sync
100 + Clone
101 + Copy
102 + Debug
103 + Display
104 + Default
105 + RefUnwindSafe
106 + Num
107 + NumCast
108 + FromPrimitiveOrF16
109 + ToBytes
110 + TryFromBytes
111 + private::Sealed
112 + 'static
113{
114 const PTYPE: PType;
116
117 fn is_nan(self) -> bool;
120
121 fn is_infinite(self) -> bool;
124
125 fn total_compare(self, other: Self) -> Ordering;
127
128 #[inline]
130 fn is_le(self, other: Self) -> bool {
131 self.total_compare(other).is_le()
132 }
133
134 #[inline]
136 fn is_lt(self, other: Self) -> bool {
137 self.total_compare(other).is_lt()
138 }
139
140 #[inline]
142 fn is_ge(self, other: Self) -> bool {
143 self.total_compare(other).is_ge()
144 }
145
146 #[inline]
148 fn is_gt(self, other: Self) -> bool {
149 self.total_compare(other).is_gt()
150 }
151
152 fn is_eq(self, other: Self) -> bool;
154
155 fn downcast<V: PTypeDowncast>(visitor: V) -> V::Output<Self>;
157
158 fn upcast<V: PTypeUpcast>(input: V::Input<Self>) -> V;
160}
161
162mod private {
163 use half::f16;
164
165 pub trait Sealed {}
167
168 impl Sealed for u8 {}
169 impl Sealed for u16 {}
170 impl Sealed for u32 {}
171 impl Sealed for u64 {}
172 impl Sealed for i8 {}
173 impl Sealed for i16 {}
174 impl Sealed for i32 {}
175 impl Sealed for i64 {}
176 impl Sealed for f16 {}
177 impl Sealed for f32 {}
178 impl Sealed for f64 {}
179}
180
181#[expect(missing_docs, reason = "method names are self-documenting")]
183pub trait PTypeDowncast {
184 type Output<T: NativePType>;
185
186 fn into_u8(self) -> Self::Output<u8>;
187 fn into_u16(self) -> Self::Output<u16>;
188 fn into_u32(self) -> Self::Output<u32>;
189 fn into_u64(self) -> Self::Output<u64>;
190 fn into_i8(self) -> Self::Output<i8>;
191 fn into_i16(self) -> Self::Output<i16>;
192 fn into_i32(self) -> Self::Output<i32>;
193 fn into_i64(self) -> Self::Output<i64>;
194 fn into_f16(self) -> Self::Output<f16>;
195 fn into_f32(self) -> Self::Output<f32>;
196 fn into_f64(self) -> Self::Output<f64>;
197}
198
199pub trait PTypeDowncastExt: PTypeDowncast {
201 fn downcast<T: NativePType>(self) -> Self::Output<T>
203 where
204 Self: Sized,
205 {
206 T::downcast(self)
207 }
208}
209
210impl<T: PTypeDowncast> PTypeDowncastExt for T {}
211
212macro_rules! impl_ptype_downcast {
213 ($T:ty) => {
214 #[inline]
215 fn downcast<V: PTypeDowncast>(visitor: V) -> V::Output<Self> {
216 paste::paste! { visitor.[<into_ $T>]() }
217 }
218
219 #[inline]
220 fn upcast<V: PTypeUpcast>(input: V::Input<Self>) -> V {
221 paste::paste! { V::[<from_ $T>](input) }
222 }
223 };
224}
225
226#[expect(missing_docs, reason = "method names are self-documenting")]
228pub trait PTypeUpcast {
229 type Input<T: NativePType>;
230
231 fn from_u8(input: Self::Input<u8>) -> Self;
232 fn from_u16(input: Self::Input<u16>) -> Self;
233 fn from_u32(input: Self::Input<u32>) -> Self;
234 fn from_u64(input: Self::Input<u64>) -> Self;
235 fn from_i8(input: Self::Input<i8>) -> Self;
236 fn from_i16(input: Self::Input<i16>) -> Self;
237 fn from_i32(input: Self::Input<i32>) -> Self;
238 fn from_i64(input: Self::Input<i64>) -> Self;
239 fn from_f16(input: Self::Input<f16>) -> Self;
240 fn from_f32(input: Self::Input<f32>) -> Self;
241 fn from_f64(input: Self::Input<f64>) -> Self;
242}
243
244macro_rules! native_ptype {
245 ($T:ty, $ptype:tt) => {
246 impl crate::NativeDType for $T {
247 fn dtype() -> DType {
248 DType::Primitive(PType::$ptype, crate::Nullability::NonNullable)
249 }
250 }
251
252 impl NativePType for $T {
253 const PTYPE: PType = PType::$ptype;
254
255 #[inline]
256 fn is_nan(self) -> bool {
257 false
258 }
259
260 #[inline]
261 fn is_infinite(self) -> bool {
262 false
263 }
264
265 #[inline]
266 fn total_compare(self, other: Self) -> Ordering {
267 self.cmp(&other)
268 }
269
270 #[inline]
271 fn is_eq(self, other: Self) -> bool {
272 self == other
273 }
274
275 impl_ptype_downcast!($T);
276 }
277 };
278}
279
280macro_rules! native_float_ptype {
281 ($T:ty, $ptype:tt) => {
282 impl crate::NativeDType for $T {
283 fn dtype() -> DType {
284 DType::Primitive(PType::$ptype, crate::Nullability::NonNullable)
285 }
286 }
287
288 impl NativePType for $T {
289 const PTYPE: PType = PType::$ptype;
290
291 #[inline]
292 fn is_nan(self) -> bool {
293 <$T>::is_nan(self)
294 }
295
296 #[inline]
297 fn is_infinite(self) -> bool {
298 <$T>::is_infinite(self)
299 }
300
301 #[inline]
302 fn total_compare(self, other: Self) -> Ordering {
303 self.total_cmp(&other)
304 }
305
306 #[inline]
307 fn is_eq(self, other: Self) -> bool {
308 self.to_bits() == other.to_bits()
309 }
310
311 impl_ptype_downcast!($T);
312 }
313 };
314}
315
316native_ptype!(u8, U8);
317native_ptype!(u16, U16);
318native_ptype!(u32, U32);
319native_ptype!(u64, U64);
320native_ptype!(i8, I8);
321native_ptype!(i16, I16);
322native_ptype!(i32, I32);
323native_ptype!(i64, I64);
324native_float_ptype!(f16, F16);
325native_float_ptype!(f32, F32);
326native_float_ptype!(f64, F64);
327
328#[macro_export]
330macro_rules! match_each_native_ptype {
331 (
332 $self:expr,integral: |
333 $integral_enc:ident |
334 $intbody:block,floating: |
335 $floating_point_enc:ident |
336 $floatbody:block
337 ) => {{
338 use $crate::PType;
339 use $crate::half::f16;
340 match $self {
341 PType::I8 => {
342 type $integral_enc = i8;
343 $intbody
344 }
345 PType::I16 => {
346 type $integral_enc = i16;
347 $intbody
348 }
349 PType::I32 => {
350 type $integral_enc = i32;
351 $intbody
352 }
353 PType::I64 => {
354 type $integral_enc = i64;
355 $intbody
356 }
357 PType::U8 => {
358 type $integral_enc = u8;
359 $intbody
360 }
361 PType::U16 => {
362 type $integral_enc = u16;
363 $intbody
364 }
365 PType::U32 => {
366 type $integral_enc = u32;
367 $intbody
368 }
369 PType::U64 => {
370 type $integral_enc = u64;
371 $intbody
372 }
373 PType::F16 => {
374 type $floating_point_enc = f16;
375 $floatbody
376 }
377 PType::F32 => {
378 type $floating_point_enc = f32;
379 $floatbody
380 }
381 PType::F64 => {
382 type $floating_point_enc = f64;
383 $floatbody
384 }
385 }
386 }};
387 (
388 $self:expr,unsigned: |
389 $unsigned_enc:ident |
390 $unsigned_body:block,signed: |
391 $signed_enc:ident |
392 $signed_body:block,floating: |
393 $floating_point_enc:ident |
394 $floating_point_body:block
395 ) => {{
396 use $crate::PType;
397 use $crate::half::f16;
398 match $self {
399 PType::U8 => {
400 type $unsigned_enc = u8;
401 $unsigned_body
402 }
403 PType::U16 => {
404 type $unsigned_enc = u16;
405 $unsigned_body
406 }
407 PType::U32 => {
408 type $unsigned_enc = u32;
409 $unsigned_body
410 }
411 PType::U64 => {
412 type $unsigned_enc = u64;
413 $unsigned_body
414 }
415 PType::I8 => {
416 type $signed_enc = i8;
417 $signed_body
418 }
419 PType::I16 => {
420 type $signed_enc = i16;
421 $signed_body
422 }
423 PType::I32 => {
424 type $signed_enc = i32;
425 $signed_body
426 }
427 PType::I64 => {
428 type $signed_enc = i64;
429 $signed_body
430 }
431 PType::F16 => {
432 type $floating_point_enc = f16;
433 $floating_point_body
434 }
435 PType::F32 => {
436 type $floating_point_enc = f32;
437 $floating_point_body
438 }
439 PType::F64 => {
440 type $floating_point_enc = f64;
441 $floating_point_body
442 }
443 }
444 }};
445 ($self:expr, | $tname:ident | $body:block) => {{
446 use $crate::PType;
447 use $crate::half::f16;
448 match $self {
449 PType::I8 => {
450 type $tname = i8;
451 $body
452 }
453 PType::I16 => {
454 type $tname = i16;
455 $body
456 }
457 PType::I32 => {
458 type $tname = i32;
459 $body
460 }
461 PType::I64 => {
462 type $tname = i64;
463 $body
464 }
465 PType::U8 => {
466 type $tname = u8;
467 $body
468 }
469 PType::U16 => {
470 type $tname = u16;
471 $body
472 }
473 PType::U32 => {
474 type $tname = u32;
475 $body
476 }
477 PType::U64 => {
478 type $tname = u64;
479 $body
480 }
481 PType::F16 => {
482 type $tname = f16;
483 $body
484 }
485 PType::F32 => {
486 type $tname = f32;
487 $body
488 }
489 PType::F64 => {
490 type $tname = f64;
491 $body
492 }
493 }
494 }};
495}
496
497#[macro_export]
499macro_rules! match_each_integer_ptype {
500 ($self:expr, | $enc:ident | $body:block) => {{
501 use $crate::PType;
502 match $self {
503 PType::I8 => {
504 type $enc = i8;
505 $body
506 }
507 PType::I16 => {
508 type $enc = i16;
509 $body
510 }
511 PType::I32 => {
512 type $enc = i32;
513 $body
514 }
515 PType::I64 => {
516 type $enc = i64;
517 $body
518 }
519 PType::U8 => {
520 type $enc = u8;
521 $body
522 }
523 PType::U16 => {
524 type $enc = u16;
525 $body
526 }
527 PType::U32 => {
528 type $enc = u32;
529 $body
530 }
531 PType::U64 => {
532 type $enc = u64;
533 $body
534 }
535 other => panic!("Unsupported ptype {other}"),
536 }
537 }};
538}
539
540#[macro_export]
542macro_rules! match_each_unsigned_integer_ptype {
543 ($self:expr, | $enc:ident | $body:block) => {{
544 use $crate::PType;
545 match $self {
546 PType::U8 => {
547 type $enc = u8;
548 $body
549 }
550 PType::U16 => {
551 type $enc = u16;
552 $body
553 }
554 PType::U32 => {
555 type $enc = u32;
556 $body
557 }
558 PType::U64 => {
559 type $enc = u64;
560 $body
561 }
562 other => panic!("Unsupported ptype {other}"),
563 }
564 }};
565}
566
567#[macro_export]
569macro_rules! match_each_signed_integer_ptype {
570 ($self:expr, | $enc:ident | $body:block) => {{
571 use $crate::PType;
572 match $self {
573 PType::I8 => {
574 type $enc = i8;
575 $body
576 }
577 PType::I16 => {
578 type $enc = i16;
579 $body
580 }
581 PType::I32 => {
582 type $enc = i32;
583 $body
584 }
585 PType::I64 => {
586 type $enc = i64;
587 $body
588 }
589 other => panic!("Unsupported ptype {other}"),
590 }
591 }};
592}
593
594#[macro_export]
596macro_rules! match_each_float_ptype {
597 ($self:expr, | $enc:ident | $body:block) => {{
598 use vortex_dtype::half::f16;
599 use $crate::PType;
600 match $self {
601 PType::F16 => {
602 type $enc = f16;
603 $body
604 }
605 PType::F32 => {
606 type $enc = f32;
607 $body
608 }
609 PType::F64 => {
610 type $enc = f64;
611 $body
612 }
613 other => panic!("Unsupported ptype {other}"),
614 }
615 }};
616}
617
618#[macro_export]
622macro_rules! match_each_native_simd_ptype {
623 ($self:expr, | $enc:ident | $body:block) => {{
624 use $crate::PType;
625 match $self {
626 PType::I8 => {
627 type $enc = i8;
628 $body
629 }
630 PType::I16 => {
631 type $enc = i16;
632 $body
633 }
634 PType::I32 => {
635 type $enc = i32;
636 $body
637 }
638 PType::I64 => {
639 type $enc = i64;
640 $body
641 }
642 PType::U8 => {
643 type $enc = u8;
644 $body
645 }
646 PType::U16 => {
647 type $enc = u16;
648 $body
649 }
650 PType::U32 => {
651 type $enc = u32;
652 $body
653 }
654 PType::U64 => {
655 type $enc = u64;
656 $body
657 }
658 PType::F16 => panic!("f16 does not implement simd::SimdElement"),
659 PType::F32 => {
660 type $enc = f32;
661 $body
662 }
663 PType::F64 => {
664 type $enc = f64;
665 $body
666 }
667 }
668 }};
669}
670
671#[macro_export]
673macro_rules! match_smallest_offset_type {
674 ($n_elements:expr, | $offset_type:ident | $body:block) => {{
675 let n_elements = $n_elements;
676 if n_elements <= u8::MAX as usize {
677 type $offset_type = u8;
678 $body
679 } else if n_elements <= u16::MAX as usize {
680 type $offset_type = u16;
681 $body
682 } else if n_elements <= u32::MAX as usize {
683 type $offset_type = u32;
684 $body
685 } else {
686 assert!(u64::try_from(n_elements).is_ok());
687 type $offset_type = u64;
688 $body
689 }
690 }};
691}
692
693impl PType {
694 #[inline]
696 pub const fn is_unsigned_int(self) -> bool {
697 matches!(self, Self::U8 | Self::U16 | Self::U32 | Self::U64)
698 }
699
700 #[inline]
702 pub const fn is_signed_int(self) -> bool {
703 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64)
704 }
705
706 #[inline]
709 pub const fn is_int(self) -> bool {
710 self.is_unsigned_int() || self.is_signed_int()
711 }
712
713 #[inline]
715 pub const fn is_float(self) -> bool {
716 matches!(self, Self::F16 | Self::F32 | Self::F64)
717 }
718
719 #[inline]
721 pub const fn byte_width(&self) -> usize {
722 match_each_native_ptype!(self, |T| { size_of::<T>() })
723 }
724
725 #[inline]
727 pub const fn bit_width(&self) -> usize {
728 self.byte_width() * 8
729 }
730
731 #[inline]
734 pub fn max_value_as_u64(&self) -> u64 {
735 match_each_native_ptype!(self, |T| {
736 <T as UpperBounded>::max_value()
737 .to_u64()
738 .unwrap_or(u64::MAX)
739 })
740 }
741
742 #[inline]
744 pub const fn to_signed(self) -> Self {
745 match self {
746 Self::U8 => Self::I8,
747 Self::U16 => Self::I16,
748 Self::U32 => Self::I32,
749 Self::U64 => Self::I64,
750 Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::F16 | Self::F32 | Self::F64 => {
751 self
752 }
753 }
754 }
755
756 #[inline]
759 pub const fn to_unsigned(self) -> Self {
760 match self {
761 Self::I8 => Self::U8,
762 Self::I16 => Self::U16,
763 Self::I32 => Self::U32,
764 Self::I64 => Self::U64,
765 Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::F16 | Self::F32 | Self::F64 => {
766 self
767 }
768 }
769 }
770
771 #[inline]
773 pub const fn min_unsigned_ptype_for_value(value: u64) -> Self {
774 if value <= u8::MAX as u64 {
775 Self::U8
776 } else if value <= u16::MAX as u64 {
777 Self::U16
778 } else if value <= u32::MAX as u64 {
779 Self::U32
780 } else {
781 Self::U64
782 }
783 }
784
785 #[inline]
787 pub const fn min_signed_ptype_for_value(value: i64) -> Self {
788 if value >= i8::MIN as i64 && value <= i8::MAX as i64 {
789 Self::I8
790 } else if value >= i16::MIN as i64 && value <= i16::MAX as i64 {
791 Self::I16
792 } else if value >= i32::MIN as i64 && value <= i32::MAX as i64 {
793 Self::I32
794 } else {
795 Self::I64
796 }
797 }
798
799 #[inline]
801 pub const fn max_unsigned_ptype(self, other: Self) -> Self {
802 debug_assert!(self.is_unsigned_int() && other.is_unsigned_int());
803 if self.byte_width() >= other.byte_width() {
804 self
805 } else {
806 other
807 }
808 }
809
810 #[inline]
812 pub const fn max_signed_ptype(self, other: Self) -> Self {
813 debug_assert!(self.is_signed_int() && other.is_signed_int());
814 if self.byte_width() >= other.byte_width() {
815 self
816 } else {
817 other
818 }
819 }
820}
821
822impl Display for PType {
823 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
824 match self {
825 Self::U8 => write!(f, "u8"),
826 Self::U16 => write!(f, "u16"),
827 Self::U32 => write!(f, "u32"),
828 Self::U64 => write!(f, "u64"),
829 Self::I8 => write!(f, "i8"),
830 Self::I16 => write!(f, "i16"),
831 Self::I32 => write!(f, "i32"),
832 Self::I64 => write!(f, "i64"),
833 Self::F16 => write!(f, "f16"),
834 Self::F32 => write!(f, "f32"),
835 Self::F64 => write!(f, "f64"),
836 }
837 }
838}
839
840impl TryFrom<&DType> for PType {
841 type Error = VortexError;
842
843 #[inline]
844 fn try_from(value: &DType) -> VortexResult<Self> {
845 if let DType::Primitive(p, _) = value {
846 Ok(*p)
847 } else {
848 Err(vortex_err!("Cannot convert DType {} into PType", value))
849 }
850 }
851}
852
853impl From<PType> for &DType {
854 fn from(item: PType) -> Self {
855 match item {
857 PType::I8 => &DType::Primitive(PType::I8, NonNullable),
858 PType::I16 => &DType::Primitive(PType::I16, NonNullable),
859 PType::I32 => &DType::Primitive(PType::I32, NonNullable),
860 PType::I64 => &DType::Primitive(PType::I64, NonNullable),
861 PType::U8 => &DType::Primitive(PType::U8, NonNullable),
862 PType::U16 => &DType::Primitive(PType::U16, NonNullable),
863 PType::U32 => &DType::Primitive(PType::U32, NonNullable),
864 PType::U64 => &DType::Primitive(PType::U64, NonNullable),
865 PType::F16 => &DType::Primitive(PType::F16, NonNullable),
866 PType::F32 => &DType::Primitive(PType::F32, NonNullable),
867 PType::F64 => &DType::Primitive(PType::F64, NonNullable),
868 }
869 }
870}
871
872impl From<PType> for DType {
873 fn from(item: PType) -> Self {
874 DType::Primitive(item, NonNullable)
875 }
876}
877
878pub trait ToBytes: Sized {
880 fn to_le_bytes(&self) -> &[u8];
882}
883
884pub trait TryFromBytes: Sized {
886 fn try_from_le_bytes(bytes: &[u8]) -> VortexResult<Self>;
888}
889
890macro_rules! try_from_bytes {
891 ($T:ty) => {
892 impl ToBytes for $T {
893 #[inline]
894 #[allow(clippy::size_of_in_element_count)]
895 fn to_le_bytes(&self) -> &[u8] {
896 let raw_ptr = self as *const $T as *const u8;
899 unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of::<$T>()) }
900 }
901 }
902
903 impl TryFromBytes for $T {
904 fn try_from_le_bytes(bytes: &[u8]) -> VortexResult<Self> {
905 Ok(<$T>::from_le_bytes(bytes.try_into().map_err(|_| {
906 vortex_err!("Failed to convert bytes into {}", stringify!($T))
907 })?))
908 }
909 }
910 };
911}
912
913try_from_bytes!(u8);
914try_from_bytes!(u16);
915try_from_bytes!(u32);
916try_from_bytes!(u64);
917try_from_bytes!(i8);
918try_from_bytes!(i16);
919try_from_bytes!(i32);
920try_from_bytes!(i64);
921try_from_bytes!(f16);
922try_from_bytes!(f32);
923try_from_bytes!(f64);
924
925pub trait PhysicalPType: NativePType {
927 type Physical: NativePType + Unsigned;
929}
930
931macro_rules! physical_ptype {
932 ($T:ty, $U:ty) => {
933 impl PhysicalPType for $T {
934 type Physical = $U;
935 }
936 };
937}
938
939physical_ptype!(i8, u8);
940physical_ptype!(i16, u16);
941physical_ptype!(i32, u32);
942physical_ptype!(i64, u64);
943physical_ptype!(u8, u8);
944physical_ptype!(u16, u16);
945physical_ptype!(u32, u32);
946physical_ptype!(u64, u64);
947
948#[cfg(test)]
949mod tests {
950 use super::*;
951
952 #[test]
953 fn try_from_bytes() {
954 assert_eq!(u8::try_from_le_bytes(&[0x01]).unwrap(), 0x01);
955 assert_eq!(u16::try_from_le_bytes(&[0x01, 0x02]).unwrap(), 0x0201);
956 assert_eq!(
957 u32::try_from_le_bytes(&[0x01, 0x02, 0x03, 0x04]).unwrap(),
958 0x04030201
959 );
960 assert_eq!(
961 u64::try_from_le_bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]).unwrap(),
962 0x0807060504030201
963 );
964 }
965
966 #[test]
967 fn to_bytes_rt() {
968 assert_eq!(&0x01u8.to_le_bytes(), &[0x01]);
969 assert_eq!(&0x0201u16.to_le_bytes(), &[0x01, 0x02]);
970
971 assert_eq!(u8::try_from_le_bytes(&42_u8.to_le_bytes()).unwrap(), 42);
972 assert_eq!(u16::try_from_le_bytes(&42_u16.to_le_bytes()).unwrap(), 42);
973 assert_eq!(u32::try_from_le_bytes(&42_u32.to_le_bytes()).unwrap(), 42);
974 assert_eq!(u64::try_from_le_bytes(&42_u64.to_le_bytes()).unwrap(), 42);
975 assert_eq!(i8::try_from_le_bytes(&42_i8.to_le_bytes()).unwrap(), 42);
976 assert_eq!(i16::try_from_le_bytes(&42_i16.to_le_bytes()).unwrap(), 42);
977 assert_eq!(i32::try_from_le_bytes(&42_i32.to_le_bytes()).unwrap(), 42);
978 assert_eq!(i64::try_from_le_bytes(&42_i64.to_le_bytes()).unwrap(), 42);
979 assert_eq!(
980 f16::try_from_le_bytes(&f16::from_f32(42.0).to_le_bytes()).unwrap(),
981 f16::from_f32(42.0)
982 );
983 assert_eq!(
984 f32::try_from_le_bytes(&42.0_f32.to_le_bytes()).unwrap(),
985 42.0
986 );
987 assert_eq!(
988 f64::try_from_le_bytes(&42.0_f64.to_le_bytes()).unwrap(),
989 42.0
990 );
991 }
992
993 #[test]
994 fn max_value_u64() {
995 assert_eq!(PType::U8.max_value_as_u64(), u8::MAX as u64);
996 assert_eq!(PType::U16.max_value_as_u64(), u16::MAX as u64);
997 assert_eq!(PType::U32.max_value_as_u64(), u32::MAX as u64);
998 assert_eq!(PType::U64.max_value_as_u64(), u64::MAX);
999 assert_eq!(PType::I8.max_value_as_u64(), i8::MAX as u64);
1000 assert_eq!(PType::I16.max_value_as_u64(), i16::MAX as u64);
1001 assert_eq!(PType::I32.max_value_as_u64(), i32::MAX as u64);
1002 assert_eq!(PType::I64.max_value_as_u64(), i64::MAX as u64);
1003 assert_eq!(PType::F16.max_value_as_u64(), 65504); assert_eq!(PType::F32.max_value_as_u64(), u64::MAX);
1005 assert_eq!(PType::F64.max_value_as_u64(), u64::MAX);
1006 }
1007
1008 #[test]
1009 fn widths() {
1010 assert_eq!(PType::U8.byte_width(), 1);
1011 assert_eq!(PType::U16.byte_width(), 2);
1012 assert_eq!(PType::U32.byte_width(), 4);
1013 assert_eq!(PType::U64.byte_width(), 8);
1014 assert_eq!(PType::I8.byte_width(), 1);
1015 assert_eq!(PType::I16.byte_width(), 2);
1016 assert_eq!(PType::I32.byte_width(), 4);
1017 assert_eq!(PType::I64.byte_width(), 8);
1018 assert_eq!(PType::F16.byte_width(), 2);
1019 assert_eq!(PType::F32.byte_width(), 4);
1020 assert_eq!(PType::F64.byte_width(), 8);
1021
1022 assert_eq!(PType::U8.bit_width(), 8);
1023 assert_eq!(PType::U16.bit_width(), 16);
1024 assert_eq!(PType::U32.bit_width(), 32);
1025 assert_eq!(PType::U64.bit_width(), 64);
1026 assert_eq!(PType::I8.bit_width(), 8);
1027 assert_eq!(PType::I16.bit_width(), 16);
1028 assert_eq!(PType::I32.bit_width(), 32);
1029 assert_eq!(PType::I64.bit_width(), 64);
1030 assert_eq!(PType::F16.bit_width(), 16);
1031 assert_eq!(PType::F32.bit_width(), 32);
1032 assert_eq!(PType::F64.bit_width(), 64);
1033 }
1034
1035 #[test]
1036 fn native_ptype_nan_handling() {
1037 let a = f32::NAN;
1038 let b = f32::NAN;
1039 assert_ne!(a, b);
1040 assert!(<f32 as NativePType>::is_nan(a));
1041 assert!(<f32 as NativePType>::is_nan(b));
1042 assert!(<f32 as NativePType>::is_eq(a, b));
1043 assert!(<f32 as NativePType>::total_compare(a, b) == Ordering::Equal);
1044 }
1045
1046 #[test]
1047 fn to_signed() {
1048 assert_eq!(PType::U8.to_signed(), PType::I8);
1049 assert_eq!(PType::U16.to_signed(), PType::I16);
1050 assert_eq!(PType::U32.to_signed(), PType::I32);
1051 assert_eq!(PType::U64.to_signed(), PType::I64);
1052 assert_eq!(PType::I8.to_signed(), PType::I8);
1053 assert_eq!(PType::I16.to_signed(), PType::I16);
1054 assert_eq!(PType::I32.to_signed(), PType::I32);
1055 assert_eq!(PType::I64.to_signed(), PType::I64);
1056 assert_eq!(PType::F16.to_signed(), PType::F16);
1057 assert_eq!(PType::F32.to_signed(), PType::F32);
1058 assert_eq!(PType::F64.to_signed(), PType::F64);
1059 }
1060
1061 #[test]
1062 fn to_unsigned() {
1063 assert_eq!(PType::U8.to_unsigned(), PType::U8);
1064 assert_eq!(PType::U16.to_unsigned(), PType::U16);
1065 assert_eq!(PType::U32.to_unsigned(), PType::U32);
1066 assert_eq!(PType::U64.to_unsigned(), PType::U64);
1067 assert_eq!(PType::I8.to_unsigned(), PType::U8);
1068 assert_eq!(PType::I16.to_unsigned(), PType::U16);
1069 assert_eq!(PType::I32.to_unsigned(), PType::U32);
1070 assert_eq!(PType::I64.to_unsigned(), PType::U64);
1071 assert_eq!(PType::F16.to_unsigned(), PType::F16);
1072 assert_eq!(PType::F32.to_unsigned(), PType::F32);
1073 assert_eq!(PType::F64.to_unsigned(), PType::F64);
1074 }
1075
1076 #[test]
1077 fn to_dtype() {
1078 assert_eq!(
1079 DType::from(PType::U8),
1080 DType::Primitive(PType::U8, NonNullable)
1081 );
1082 assert_eq!(
1083 DType::from(PType::U16),
1084 DType::Primitive(PType::U16, NonNullable)
1085 );
1086 assert_eq!(
1087 DType::from(PType::U32),
1088 DType::Primitive(PType::U32, NonNullable)
1089 );
1090 assert_eq!(
1091 DType::from(PType::U64),
1092 DType::Primitive(PType::U64, NonNullable)
1093 );
1094 assert_eq!(
1095 DType::from(PType::I8),
1096 DType::Primitive(PType::I8, NonNullable)
1097 );
1098 assert_eq!(
1099 DType::from(PType::I16),
1100 DType::Primitive(PType::I16, NonNullable)
1101 );
1102 assert_eq!(
1103 DType::from(PType::I32),
1104 DType::Primitive(PType::I32, NonNullable)
1105 );
1106 assert_eq!(
1107 DType::from(PType::I64),
1108 DType::Primitive(PType::I64, NonNullable)
1109 );
1110 assert_eq!(
1111 DType::from(PType::F16),
1112 DType::Primitive(PType::F16, NonNullable)
1113 );
1114 assert_eq!(
1115 DType::from(PType::F32),
1116 DType::Primitive(PType::F32, NonNullable)
1117 );
1118 assert_eq!(
1119 DType::from(PType::F64),
1120 DType::Primitive(PType::F64, NonNullable)
1121 );
1122 }
1123}