1use std::cmp::Ordering;
4use std::fmt::{Debug, Display, Formatter};
5use std::hash::Hash;
6use std::panic::RefUnwindSafe;
7
8use num_traits::bounds::UpperBounded;
9use num_traits::{FromPrimitive, Num, NumCast, ToPrimitive};
10use vortex_error::{VortexError, VortexResult, vortex_err};
11
12use crate::DType;
13use crate::DType::*;
14use crate::half::f16;
15use crate::nullability::Nullability::NonNullable;
16
17#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Hash, prost::Enumeration)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
21#[repr(u8)]
22pub enum PType {
23 U8 = 0,
25 U16 = 1,
27 U32 = 2,
29 U64 = 3,
31 I8 = 4,
33 I16 = 5,
35 I32 = 6,
37 I64 = 7,
39 F16 = 8,
41 F32 = 9,
43 F64 = 10,
45}
46
47pub trait NativePType:
49 Send
50 + Sync
51 + Clone
52 + Copy
53 + Debug
54 + Display
55 + Default
56 + RefUnwindSafe
57 + Num
58 + NumCast
59 + FromPrimitive
60 + ToBytes
61 + TryFromBytes
62 + 'static
63{
64 const PTYPE: PType;
66
67 fn is_nan(self) -> bool;
70
71 fn is_infinite(self) -> bool;
74
75 fn total_compare(self, other: Self) -> Ordering;
77
78 #[inline]
80 fn is_le(self, other: Self) -> bool {
81 self.total_compare(other).is_le()
82 }
83
84 #[inline]
86 fn is_lt(self, other: Self) -> bool {
87 self.total_compare(other).is_lt()
88 }
89
90 #[inline]
92 fn is_ge(self, other: Self) -> bool {
93 self.total_compare(other).is_ge()
94 }
95
96 #[inline]
98 fn is_gt(self, other: Self) -> bool {
99 self.total_compare(other).is_gt()
100 }
101
102 fn is_eq(self, other: Self) -> bool;
104}
105
106macro_rules! native_ptype {
107 ($T:ty, $ptype:tt) => {
108 impl NativePType for $T {
109 const PTYPE: PType = PType::$ptype;
110
111 #[inline]
112 fn is_nan(self) -> bool {
113 false
114 }
115
116 #[inline]
117 fn is_infinite(self) -> bool {
118 false
119 }
120
121 #[inline]
122 fn total_compare(self, other: Self) -> Ordering {
123 self.cmp(&other)
124 }
125
126 #[inline]
127 fn is_eq(self, other: Self) -> bool {
128 self == other
129 }
130 }
131 };
132}
133
134macro_rules! native_float_ptype {
135 ($T:ty, $ptype:tt) => {
136 impl NativePType for $T {
137 const PTYPE: PType = PType::$ptype;
138
139 #[inline]
140 fn is_nan(self) -> bool {
141 <$T>::is_nan(self)
142 }
143
144 #[inline]
145 fn is_infinite(self) -> bool {
146 <$T>::is_infinite(self)
147 }
148
149 #[inline]
150 fn total_compare(self, other: Self) -> Ordering {
151 self.total_cmp(&other)
152 }
153
154 #[inline]
155 fn is_eq(self, other: Self) -> bool {
156 self.to_bits() == other.to_bits()
157 }
158 }
159 };
160}
161
162native_ptype!(u8, U8);
163native_ptype!(u16, U16);
164native_ptype!(u32, U32);
165native_ptype!(u64, U64);
166native_ptype!(i8, I8);
167native_ptype!(i16, I16);
168native_ptype!(i32, I32);
169native_ptype!(i64, I64);
170native_float_ptype!(f16, F16);
171native_float_ptype!(f32, F32);
172native_float_ptype!(f64, F64);
173
174#[macro_export]
176macro_rules! match_each_native_ptype {
177 (
178 $self:expr,integral: |
179 $integral_enc:ident |
180 $intbody:block,floating_point: |
181 $floating_point_enc:ident |
182 $floatbody:block
183 ) => {{
184 use $crate::PType;
185 use $crate::half::f16;
186 match $self {
187 PType::I8 => {
188 type $integral_enc = i8;
189 $intbody
190 }
191 PType::I16 => {
192 type $integral_enc = i16;
193 $intbody
194 }
195 PType::I32 => {
196 type $integral_enc = i32;
197 $intbody
198 }
199 PType::I64 => {
200 type $integral_enc = i64;
201 $intbody
202 }
203 PType::U8 => {
204 type $integral_enc = u8;
205 $intbody
206 }
207 PType::U16 => {
208 type $integral_enc = u16;
209 $intbody
210 }
211 PType::U32 => {
212 type $integral_enc = u32;
213 $intbody
214 }
215 PType::U64 => {
216 type $integral_enc = u64;
217 $intbody
218 }
219 PType::F16 => {
220 type $floating_point_enc = f16;
221 $floatbody
222 }
223 PType::F32 => {
224 type $floating_point_enc = f32;
225 $floatbody
226 }
227 PType::F64 => {
228 type $floating_point_enc = f64;
229 $floatbody
230 }
231 }
232 }};
233 (
234 $self:expr,unsigned: |
235 $unsigned_enc:ident |
236 $unsigned_body:block,signed: |
237 $signed_enc:ident |
238 $signed_body:block,floating: |
239 $floating_point_enc:ident |
240 $floating_point_body:block
241 ) => {{
242 use $crate::PType;
243 use $crate::half::f16;
244 match $self {
245 PType::U8 => {
246 type $unsigned_enc = u8;
247 $unsigned_body
248 }
249 PType::U16 => {
250 type $unsigned_enc = u16;
251 $unsigned_body
252 }
253 PType::U32 => {
254 type $unsigned_enc = u32;
255 $unsigned_body
256 }
257 PType::U64 => {
258 type $unsigned_enc = u64;
259 $unsigned_body
260 }
261 PType::I8 => {
262 type $signed_enc = i8;
263 $signed_body
264 }
265 PType::I16 => {
266 type $signed_enc = i16;
267 $signed_body
268 }
269 PType::I32 => {
270 type $signed_enc = i32;
271 $signed_body
272 }
273 PType::I64 => {
274 type $signed_enc = i64;
275 $signed_body
276 }
277 PType::F16 => {
278 type $floating_point_enc = f16;
279 $floating_point_body
280 }
281 PType::F32 => {
282 type $floating_point_enc = f32;
283 $floating_point_body
284 }
285 PType::F64 => {
286 type $floating_point_enc = f64;
287 $floating_point_body
288 }
289 }
290 }};
291 ($self:expr, | $tname:ident | $body:block) => {{
292 use $crate::PType;
293 use $crate::half::f16;
294 match $self {
295 PType::I8 => {
296 type $tname = i8;
297 $body
298 }
299 PType::I16 => {
300 type $tname = i16;
301 $body
302 }
303 PType::I32 => {
304 type $tname = i32;
305 $body
306 }
307 PType::I64 => {
308 type $tname = i64;
309 $body
310 }
311 PType::U8 => {
312 type $tname = u8;
313 $body
314 }
315 PType::U16 => {
316 type $tname = u16;
317 $body
318 }
319 PType::U32 => {
320 type $tname = u32;
321 $body
322 }
323 PType::U64 => {
324 type $tname = u64;
325 $body
326 }
327 PType::F16 => {
328 type $tname = f16;
329 $body
330 }
331 PType::F32 => {
332 type $tname = f32;
333 $body
334 }
335 PType::F64 => {
336 type $tname = f64;
337 $body
338 }
339 }
340 }};
341}
342
343#[macro_export]
345macro_rules! match_each_integer_ptype {
346 ($self:expr, | $enc:ident | $body:block) => {{
347 use $crate::PType;
348 match $self {
349 PType::I8 => {
350 type $enc = i8;
351 $body
352 }
353 PType::I16 => {
354 type $enc = i16;
355 $body
356 }
357 PType::I32 => {
358 type $enc = i32;
359 $body
360 }
361 PType::I64 => {
362 type $enc = i64;
363 $body
364 }
365 PType::U8 => {
366 type $enc = u8;
367 $body
368 }
369 PType::U16 => {
370 type $enc = u16;
371 $body
372 }
373 PType::U32 => {
374 type $enc = u32;
375 $body
376 }
377 PType::U64 => {
378 type $enc = u64;
379 $body
380 }
381 other => panic!("Unsupported ptype {other}"),
382 }
383 }};
384}
385
386#[macro_export]
388macro_rules! match_each_unsigned_integer_ptype {
389 ($self:expr, | $enc:ident | $body:block) => {{
390 use $crate::PType;
391 match $self {
392 PType::U8 => {
393 type $enc = u8;
394 $body
395 }
396 PType::U16 => {
397 type $enc = u16;
398 $body
399 }
400 PType::U32 => {
401 type $enc = u32;
402 $body
403 }
404 PType::U64 => {
405 type $enc = u64;
406 $body
407 }
408 other => panic!("Unsupported ptype {other}"),
409 }
410 }};
411}
412
413#[macro_export]
415macro_rules! match_each_signed_integer_ptype {
416 ($self:expr, | $enc:ident | $body:block) => {{
417 use $crate::PType;
418 match $self {
419 PType::I8 => {
420 type $enc = i8;
421 $body
422 }
423 PType::I16 => {
424 type $enc = i16;
425 $body
426 }
427 PType::I32 => {
428 type $enc = i32;
429 $body
430 }
431 PType::I64 => {
432 type $enc = i64;
433 $body
434 }
435 other => panic!("Unsupported ptype {other}"),
436 }
437 }};
438}
439
440#[macro_export]
442macro_rules! match_each_float_ptype {
443 ($self:expr, | $enc:ident | $body:block) => {{
444 use vortex_dtype::half::f16;
445 use $crate::PType;
446 match $self {
447 PType::F16 => {
448 type $enc = f16;
449 $body
450 }
451 PType::F32 => {
452 type $enc = f32;
453 $body
454 }
455 PType::F64 => {
456 type $enc = f64;
457 $body
458 }
459 other => panic!("Unsupported ptype {other}"),
460 }
461 }};
462}
463
464#[macro_export]
468macro_rules! match_each_native_simd_ptype {
469 ($self:expr, | $enc:ident | $body:block) => {{
470 use $crate::PType;
471 match $self {
472 PType::I8 => {
473 type $enc = i8;
474 $body
475 }
476 PType::I16 => {
477 type $enc = i16;
478 $body
479 }
480 PType::I32 => {
481 type $enc = i32;
482 $body
483 }
484 PType::I64 => {
485 type $enc = i64;
486 $body
487 }
488 PType::U8 => {
489 type $enc = u8;
490 $body
491 }
492 PType::U16 => {
493 type $enc = u16;
494 $body
495 }
496 PType::U32 => {
497 type $enc = u32;
498 $body
499 }
500 PType::U64 => {
501 type $enc = u64;
502 $body
503 }
504 PType::F16 => panic!("f16 does not implement simd::SimdElement"),
505 PType::F32 => {
506 type $enc = f32;
507 $body
508 }
509 PType::F64 => {
510 type $enc = f64;
511 $body
512 }
513 }
514 }};
515}
516
517impl PType {
518 pub const fn is_unsigned_int(self) -> bool {
520 matches!(self, Self::U8 | Self::U16 | Self::U32 | Self::U64)
521 }
522
523 pub const fn is_signed_int(self) -> bool {
525 matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64)
526 }
527
528 pub const fn is_int(self) -> bool {
531 self.is_unsigned_int() || self.is_signed_int()
532 }
533
534 pub const fn is_float(self) -> bool {
536 matches!(self, Self::F16 | Self::F32 | Self::F64)
537 }
538
539 pub const fn byte_width(&self) -> usize {
541 match_each_native_ptype!(self, |T| { size_of::<T>() })
542 }
543
544 pub const fn bit_width(&self) -> usize {
546 self.byte_width() * 8
547 }
548
549 pub fn max_value_as_u64(&self) -> u64 {
552 match_each_native_ptype!(self, |T| {
553 <T as UpperBounded>::max_value()
554 .to_u64()
555 .unwrap_or(u64::MAX)
556 })
557 }
558
559 pub const fn to_signed(self) -> Self {
561 match self {
562 Self::U8 => Self::I8,
563 Self::U16 => Self::I16,
564 Self::U32 => Self::I32,
565 Self::U64 => Self::I64,
566 _ => self,
567 }
568 }
569
570 pub const fn to_unsigned(self) -> Self {
573 match self {
574 Self::I8 => Self::U8,
575 Self::I16 => Self::U16,
576 Self::I32 => Self::U32,
577 Self::I64 => Self::U64,
578 _ => self,
579 }
580 }
581}
582
583impl Display for PType {
584 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
585 match self {
586 Self::U8 => write!(f, "u8"),
587 Self::U16 => write!(f, "u16"),
588 Self::U32 => write!(f, "u32"),
589 Self::U64 => write!(f, "u64"),
590 Self::I8 => write!(f, "i8"),
591 Self::I16 => write!(f, "i16"),
592 Self::I32 => write!(f, "i32"),
593 Self::I64 => write!(f, "i64"),
594 Self::F16 => write!(f, "f16"),
595 Self::F32 => write!(f, "f32"),
596 Self::F64 => write!(f, "f64"),
597 }
598 }
599}
600
601impl TryFrom<&DType> for PType {
602 type Error = VortexError;
603
604 #[inline]
605 fn try_from(value: &DType) -> VortexResult<Self> {
606 match value {
607 Primitive(p, _) => Ok(*p),
608 _ => Err(vortex_err!("Cannot convert DType {} into PType", value)),
609 }
610 }
611}
612
613impl From<PType> for &DType {
614 fn from(item: PType) -> Self {
615 match item {
617 PType::I8 => &Primitive(PType::I8, NonNullable),
618 PType::I16 => &Primitive(PType::I16, NonNullable),
619 PType::I32 => &Primitive(PType::I32, NonNullable),
620 PType::I64 => &Primitive(PType::I64, NonNullable),
621 PType::U8 => &Primitive(PType::U8, NonNullable),
622 PType::U16 => &Primitive(PType::U16, NonNullable),
623 PType::U32 => &Primitive(PType::U32, NonNullable),
624 PType::U64 => &Primitive(PType::U64, NonNullable),
625 PType::F16 => &Primitive(PType::F16, NonNullable),
626 PType::F32 => &Primitive(PType::F32, NonNullable),
627 PType::F64 => &Primitive(PType::F64, NonNullable),
628 }
629 }
630}
631
632impl From<PType> for DType {
633 fn from(item: PType) -> Self {
634 Primitive(item, NonNullable)
635 }
636}
637
638pub trait ToBytes: Sized {
640 fn to_le_bytes(&self) -> &[u8];
642}
643
644pub trait TryFromBytes: Sized {
646 fn try_from_le_bytes(bytes: &[u8]) -> VortexResult<Self>;
648}
649
650macro_rules! try_from_bytes {
651 ($T:ty) => {
652 impl ToBytes for $T {
653 #[inline]
654 #[allow(clippy::size_of_in_element_count)]
655 fn to_le_bytes(&self) -> &[u8] {
656 let raw_ptr = self as *const $T as *const u8;
659 unsafe { std::slice::from_raw_parts(raw_ptr, std::mem::size_of::<$T>()) }
660 }
661 }
662
663 impl TryFromBytes for $T {
664 fn try_from_le_bytes(bytes: &[u8]) -> VortexResult<Self> {
665 Ok(<$T>::from_le_bytes(bytes.try_into().map_err(|_| {
666 vortex_err!("Failed to convert bytes into {}", stringify!($T))
667 })?))
668 }
669 }
670 };
671}
672
673try_from_bytes!(u8);
674try_from_bytes!(u16);
675try_from_bytes!(u32);
676try_from_bytes!(u64);
677try_from_bytes!(i8);
678try_from_bytes!(i16);
679try_from_bytes!(i32);
680try_from_bytes!(i64);
681try_from_bytes!(f16);
682try_from_bytes!(f32);
683try_from_bytes!(f64);
684
685#[cfg(test)]
686mod tests {
687 use super::*;
688
689 #[test]
690 fn try_from_bytes() {
691 assert_eq!(u8::try_from_le_bytes(&[0x01]).unwrap(), 0x01);
692 assert_eq!(u16::try_from_le_bytes(&[0x01, 0x02]).unwrap(), 0x0201);
693 assert_eq!(
694 u32::try_from_le_bytes(&[0x01, 0x02, 0x03, 0x04]).unwrap(),
695 0x04030201
696 );
697 assert_eq!(
698 u64::try_from_le_bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]).unwrap(),
699 0x0807060504030201
700 );
701 }
702
703 #[test]
704 fn to_bytes_rt() {
705 assert_eq!(&0x01u8.to_le_bytes(), &[0x01]);
706 assert_eq!(&0x0201u16.to_le_bytes(), &[0x01, 0x02]);
707
708 assert_eq!(u8::try_from_le_bytes(&42_u8.to_le_bytes()).unwrap(), 42);
709 assert_eq!(u16::try_from_le_bytes(&42_u16.to_le_bytes()).unwrap(), 42);
710 assert_eq!(u32::try_from_le_bytes(&42_u32.to_le_bytes()).unwrap(), 42);
711 assert_eq!(u64::try_from_le_bytes(&42_u64.to_le_bytes()).unwrap(), 42);
712 assert_eq!(i8::try_from_le_bytes(&42_i8.to_le_bytes()).unwrap(), 42);
713 assert_eq!(i16::try_from_le_bytes(&42_i16.to_le_bytes()).unwrap(), 42);
714 assert_eq!(i32::try_from_le_bytes(&42_i32.to_le_bytes()).unwrap(), 42);
715 assert_eq!(i64::try_from_le_bytes(&42_i64.to_le_bytes()).unwrap(), 42);
716 assert_eq!(
717 f16::try_from_le_bytes(&f16::from_f32(42.0).to_le_bytes()).unwrap(),
718 f16::from_f32(42.0)
719 );
720 assert_eq!(
721 f32::try_from_le_bytes(&42.0_f32.to_le_bytes()).unwrap(),
722 42.0
723 );
724 assert_eq!(
725 f64::try_from_le_bytes(&42.0_f64.to_le_bytes()).unwrap(),
726 42.0
727 );
728 }
729
730 #[test]
731 fn max_value_u64() {
732 assert_eq!(PType::U8.max_value_as_u64(), u8::MAX as u64);
733 assert_eq!(PType::U16.max_value_as_u64(), u16::MAX as u64);
734 assert_eq!(PType::U32.max_value_as_u64(), u32::MAX as u64);
735 assert_eq!(PType::U64.max_value_as_u64(), u64::MAX);
736 assert_eq!(PType::I8.max_value_as_u64(), i8::MAX as u64);
737 assert_eq!(PType::I16.max_value_as_u64(), i16::MAX as u64);
738 assert_eq!(PType::I32.max_value_as_u64(), i32::MAX as u64);
739 assert_eq!(PType::I64.max_value_as_u64(), i64::MAX as u64);
740 assert_eq!(PType::F16.max_value_as_u64(), 65504); assert_eq!(PType::F32.max_value_as_u64(), u64::MAX);
742 assert_eq!(PType::F64.max_value_as_u64(), u64::MAX);
743 }
744
745 #[test]
746 fn widths() {
747 assert_eq!(PType::U8.byte_width(), 1);
748 assert_eq!(PType::U16.byte_width(), 2);
749 assert_eq!(PType::U32.byte_width(), 4);
750 assert_eq!(PType::U64.byte_width(), 8);
751 assert_eq!(PType::I8.byte_width(), 1);
752 assert_eq!(PType::I16.byte_width(), 2);
753 assert_eq!(PType::I32.byte_width(), 4);
754 assert_eq!(PType::I64.byte_width(), 8);
755 assert_eq!(PType::F16.byte_width(), 2);
756 assert_eq!(PType::F32.byte_width(), 4);
757 assert_eq!(PType::F64.byte_width(), 8);
758
759 assert_eq!(PType::U8.bit_width(), 8);
760 assert_eq!(PType::U16.bit_width(), 16);
761 assert_eq!(PType::U32.bit_width(), 32);
762 assert_eq!(PType::U64.bit_width(), 64);
763 assert_eq!(PType::I8.bit_width(), 8);
764 assert_eq!(PType::I16.bit_width(), 16);
765 assert_eq!(PType::I32.bit_width(), 32);
766 assert_eq!(PType::I64.bit_width(), 64);
767 assert_eq!(PType::F16.bit_width(), 16);
768 assert_eq!(PType::F32.bit_width(), 32);
769 assert_eq!(PType::F64.bit_width(), 64);
770 }
771
772 #[test]
773 fn native_ptype_nan_handling() {
774 let a = f32::NAN;
775 let b = f32::NAN;
776 assert_ne!(a, b);
777 assert!(<f32 as NativePType>::is_nan(a));
778 assert!(<f32 as NativePType>::is_nan(b));
779 assert!(<f32 as NativePType>::is_eq(a, b));
780 assert!(<f32 as NativePType>::total_compare(a, b) == Ordering::Equal);
781 }
782
783 #[test]
784 fn to_signed() {
785 assert_eq!(PType::U8.to_signed(), PType::I8);
786 assert_eq!(PType::U16.to_signed(), PType::I16);
787 assert_eq!(PType::U32.to_signed(), PType::I32);
788 assert_eq!(PType::U64.to_signed(), PType::I64);
789 assert_eq!(PType::I8.to_signed(), PType::I8);
790 assert_eq!(PType::I16.to_signed(), PType::I16);
791 assert_eq!(PType::I32.to_signed(), PType::I32);
792 assert_eq!(PType::I64.to_signed(), PType::I64);
793 assert_eq!(PType::F16.to_signed(), PType::F16);
794 assert_eq!(PType::F32.to_signed(), PType::F32);
795 assert_eq!(PType::F64.to_signed(), PType::F64);
796 }
797
798 #[test]
799 fn to_unsigned() {
800 assert_eq!(PType::U8.to_unsigned(), PType::U8);
801 assert_eq!(PType::U16.to_unsigned(), PType::U16);
802 assert_eq!(PType::U32.to_unsigned(), PType::U32);
803 assert_eq!(PType::U64.to_unsigned(), PType::U64);
804 assert_eq!(PType::I8.to_unsigned(), PType::U8);
805 assert_eq!(PType::I16.to_unsigned(), PType::U16);
806 assert_eq!(PType::I32.to_unsigned(), PType::U32);
807 assert_eq!(PType::I64.to_unsigned(), PType::U64);
808 assert_eq!(PType::F16.to_unsigned(), PType::F16);
809 assert_eq!(PType::F32.to_unsigned(), PType::F32);
810 assert_eq!(PType::F64.to_unsigned(), PType::F64);
811 }
812
813 #[test]
814 fn to_dtype() {
815 assert_eq!(DType::from(PType::U8), Primitive(PType::U8, NonNullable));
816 assert_eq!(DType::from(PType::U16), Primitive(PType::U16, NonNullable));
817 assert_eq!(DType::from(PType::U32), Primitive(PType::U32, NonNullable));
818 assert_eq!(DType::from(PType::U64), Primitive(PType::U64, NonNullable));
819 assert_eq!(DType::from(PType::I8), Primitive(PType::I8, NonNullable));
820 assert_eq!(DType::from(PType::I16), Primitive(PType::I16, NonNullable));
821 assert_eq!(DType::from(PType::I32), Primitive(PType::I32, NonNullable));
822 assert_eq!(DType::from(PType::I64), Primitive(PType::I64, NonNullable));
823 assert_eq!(DType::from(PType::F16), Primitive(PType::F16, NonNullable));
824 assert_eq!(DType::from(PType::F32), Primitive(PType::F32, NonNullable));
825 assert_eq!(DType::from(PType::F64), Primitive(PType::F64, NonNullable));
826 }
827}