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