1use core::fmt::Display;
5use std::cmp::Ordering;
6use std::hash::{Hash, Hasher};
7
8use num_traits::NumCast;
9use paste::paste;
10use vortex_dtype::half::f16;
11use vortex_dtype::{NativePType, PType, ToBytes};
12use vortex_error::{VortexError, VortexExpect, VortexResult, vortex_bail, vortex_err};
13
14#[derive(Debug, Clone, Copy)]
19pub enum PValue {
20 U8(u8),
22 U16(u16),
24 U32(u32),
26 U64(u64),
28 I8(i8),
30 I16(i16),
32 I32(i32),
34 I64(i64),
36 F16(f16),
38 F32(f32),
40 F64(f64),
42}
43
44impl PartialEq for PValue {
45 fn eq(&self, other: &Self) -> bool {
46 match (self, other) {
47 (Self::U8(s), o) => o.as_u64().vortex_expect("upcast") == *s as u64,
48 (Self::U16(s), o) => o.as_u64().vortex_expect("upcast") == *s as u64,
49 (Self::U32(s), o) => o.as_u64().vortex_expect("upcast") == *s as u64,
50 (Self::U64(s), o) => o.as_u64().vortex_expect("upcast") == *s,
51 (Self::I8(s), o) => o.as_i64().vortex_expect("upcast") == *s as i64,
52 (Self::I16(s), o) => o.as_i64().vortex_expect("upcast") == *s as i64,
53 (Self::I32(s), o) => o.as_i64().vortex_expect("upcast") == *s as i64,
54 (Self::I64(s), o) => o.as_i64().vortex_expect("upcast") == *s,
55 (Self::F16(s), Self::F16(o)) => s.is_eq(*o),
56 (Self::F32(s), Self::F32(o)) => s.is_eq(*o),
57 (Self::F64(s), Self::F64(o)) => s.is_eq(*o),
58 (..) => false,
59 }
60 }
61}
62
63impl Eq for PValue {}
64
65impl PartialOrd for PValue {
66 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
67 match (self, other) {
68 (Self::U8(s), o) => Some((*s as u64).cmp(&o.as_u64().vortex_expect("upcast"))),
69 (Self::U16(s), o) => Some((*s as u64).cmp(&o.as_u64().vortex_expect("upcast"))),
70 (Self::U32(s), o) => Some((*s as u64).cmp(&o.as_u64().vortex_expect("upcast"))),
71 (Self::U64(s), o) => Some((*s).cmp(&o.as_u64().vortex_expect("upcast"))),
72 (Self::I8(s), o) => Some((*s as i64).cmp(&o.as_i64().vortex_expect("upcast"))),
73 (Self::I16(s), o) => Some((*s as i64).cmp(&o.as_i64().vortex_expect("upcast"))),
74 (Self::I32(s), o) => Some((*s as i64).cmp(&o.as_i64().vortex_expect("upcast"))),
75 (Self::I64(s), o) => Some((*s).cmp(&o.as_i64().vortex_expect("upcast"))),
76 (Self::F16(s), Self::F16(o)) => Some(s.total_compare(*o)),
77 (Self::F32(s), Self::F32(o)) => Some(s.total_compare(*o)),
78 (Self::F64(s), Self::F64(o)) => Some(s.total_compare(*o)),
79 (..) => None,
80 }
81 }
82}
83
84impl Hash for PValue {
85 fn hash<H: Hasher>(&self, state: &mut H) {
86 match self {
87 PValue::U8(_) | PValue::U16(_) | PValue::U32(_) | PValue::U64(_) => {
88 self.as_u64().vortex_expect("upcast").hash(state)
89 }
90 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
91 self.as_i64().vortex_expect("upcast").hash(state)
92 }
93 PValue::F16(v) => v.to_le_bytes().hash(state),
94 PValue::F32(v) => v.to_le_bytes().hash(state),
95 PValue::F64(v) => v.to_le_bytes().hash(state),
96 }
97 }
98}
99
100impl ToBytes for PValue {
101 fn to_le_bytes(&self) -> &[u8] {
102 match self {
103 PValue::U8(v) => v.to_le_bytes(),
104 PValue::U16(v) => v.to_le_bytes(),
105 PValue::U32(v) => v.to_le_bytes(),
106 PValue::U64(v) => v.to_le_bytes(),
107 PValue::I8(v) => v.to_le_bytes(),
108 PValue::I16(v) => v.to_le_bytes(),
109 PValue::I32(v) => v.to_le_bytes(),
110 PValue::I64(v) => v.to_le_bytes(),
111 PValue::F16(v) => v.to_le_bytes(),
112 PValue::F32(v) => v.to_le_bytes(),
113 PValue::F64(v) => v.to_le_bytes(),
114 }
115 }
116}
117
118macro_rules! as_primitive {
119 ($T:ty, $PT:tt) => {
120 paste! {
121 #[doc = "Access PValue as `" $T "`, returning `None` if conversion is unsuccessful"]
122 pub fn [<as_ $T>](self) -> Option<$T> {
123 match self {
124 PValue::U8(v) => <$T as NumCast>::from(v),
125 PValue::U16(v) => <$T as NumCast>::from(v),
126 PValue::U32(v) => <$T as NumCast>::from(v),
127 PValue::U64(v) => <$T as NumCast>::from(v),
128 PValue::I8(v) => <$T as NumCast>::from(v),
129 PValue::I16(v) => <$T as NumCast>::from(v),
130 PValue::I32(v) => <$T as NumCast>::from(v),
131 PValue::I64(v) => <$T as NumCast>::from(v),
132 PValue::F16(v) => <$T as NumCast>::from(v),
133 PValue::F32(v) => <$T as NumCast>::from(v),
134 PValue::F64(v) => <$T as NumCast>::from(v),
135 }
136 }
137 }
138 };
139}
140
141impl PValue {
142 pub fn zero(ptype: PType) -> PValue {
144 match ptype {
145 PType::U8 => PValue::U8(0),
146 PType::U16 => PValue::U16(0),
147 PType::U32 => PValue::U32(0),
148 PType::U64 => PValue::U64(0),
149 PType::I8 => PValue::I8(0),
150 PType::I16 => PValue::I16(0),
151 PType::I32 => PValue::I32(0),
152 PType::I64 => PValue::I64(0),
153 PType::F16 => PValue::F16(f16::from_f32(0.0)),
154 PType::F32 => PValue::F32(0.0),
155 PType::F64 => PValue::F64(0.0),
156 }
157 }
158
159 pub fn ptype(&self) -> PType {
161 match self {
162 Self::U8(_) => PType::U8,
163 Self::U16(_) => PType::U16,
164 Self::U32(_) => PType::U32,
165 Self::U64(_) => PType::U64,
166 Self::I8(_) => PType::I8,
167 Self::I16(_) => PType::I16,
168 Self::I32(_) => PType::I32,
169 Self::I64(_) => PType::I64,
170 Self::F16(_) => PType::F16,
171 Self::F32(_) => PType::F32,
172 Self::F64(_) => PType::F64,
173 }
174 }
175
176 pub fn is_instance_of(&self, ptype: &PType) -> bool {
178 &self.ptype() == ptype
179 }
180
181 #[inline]
185 pub fn as_primitive<T: NativePType + TryFrom<PValue, Error = VortexError>>(
186 &self,
187 ) -> Result<T, VortexError> {
188 T::try_from(*self)
189 }
190
191 pub fn reinterpret_cast(&self, ptype: PType) -> Self {
199 if ptype == self.ptype() {
200 return *self;
201 }
202
203 assert_eq!(
204 ptype.byte_width(),
205 self.ptype().byte_width(),
206 "Cannot reinterpret cast between types of different widths"
207 );
208
209 match self {
210 PValue::U8(v) => u8::cast_signed(*v).into(),
211 PValue::U16(v) => match ptype {
212 PType::I16 => u16::cast_signed(*v).into(),
213 PType::F16 => f16::from_bits(*v).into(),
214 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
215 },
216 PValue::U32(v) => match ptype {
217 PType::I32 => u32::cast_signed(*v).into(),
218 PType::F32 => f32::from_bits(*v).into(),
219 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
220 },
221 PValue::U64(v) => match ptype {
222 PType::I64 => u64::cast_signed(*v).into(),
223 PType::F64 => f64::from_bits(*v).into(),
224 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
225 },
226 PValue::I8(v) => i8::cast_unsigned(*v).into(),
227 PValue::I16(v) => match ptype {
228 PType::U16 => i16::cast_unsigned(*v).into(),
229 PType::F16 => f16::from_bits(v.cast_unsigned()).into(),
230 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
231 },
232 PValue::I32(v) => match ptype {
233 PType::U32 => i32::cast_unsigned(*v).into(),
234 PType::F32 => f32::from_bits(i32::cast_unsigned(*v)).into(),
235 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
236 },
237 PValue::I64(v) => match ptype {
238 PType::U64 => i64::cast_unsigned(*v).into(),
239 PType::F64 => f64::from_bits(i64::cast_unsigned(*v)).into(),
240 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
241 },
242 PValue::F16(v) => match ptype {
243 PType::U16 => v.to_bits().into(),
244 PType::I16 => v.to_bits().cast_signed().into(),
245 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
246 },
247 PValue::F32(v) => match ptype {
248 PType::U32 => f32::to_bits(*v).into(),
249 PType::I32 => f32::to_bits(*v).cast_signed().into(),
250 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
251 },
252 PValue::F64(v) => match ptype {
253 PType::U64 => f64::to_bits(*v).into(),
254 PType::I64 => f64::to_bits(*v).cast_signed().into(),
255 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
256 },
257 }
258 }
259
260 as_primitive!(i8, I8);
261 as_primitive!(i16, I16);
262 as_primitive!(i32, I32);
263 as_primitive!(i64, I64);
264 as_primitive!(u8, U8);
265 as_primitive!(u16, U16);
266 as_primitive!(u32, U32);
267 as_primitive!(u64, U64);
268 as_primitive!(f16, F16);
269 as_primitive!(f32, F32);
270 as_primitive!(f64, F64);
271}
272
273macro_rules! int_pvalue {
274 ($T:ty, $PT:tt) => {
275 impl TryFrom<PValue> for $T {
276 type Error = VortexError;
277
278 fn try_from(value: PValue) -> Result<Self, Self::Error> {
279 match value {
280 PValue::U8(v) => <$T as NumCast>::from(v),
281 PValue::U16(v) => <$T as NumCast>::from(v),
282 PValue::U32(v) => <$T as NumCast>::from(v),
283 PValue::U64(v) => <$T as NumCast>::from(v),
284 PValue::I8(v) => <$T as NumCast>::from(v),
285 PValue::I16(v) => <$T as NumCast>::from(v),
286 PValue::I32(v) => <$T as NumCast>::from(v),
287 PValue::I64(v) => <$T as NumCast>::from(v),
288 _ => None,
289 }
290 .ok_or_else(|| {
291 vortex_err!("Cannot read primitive value {:?} as {}", value, PType::$PT)
292 })
293 }
294 }
295 };
296}
297
298macro_rules! float_pvalue {
299 ($T:ty, $PT:tt) => {
300 impl TryFrom<PValue> for $T {
301 type Error = VortexError;
302
303 fn try_from(value: PValue) -> Result<Self, Self::Error> {
304 match value {
305 PValue::U8(u) => <Self as NumCast>::from(u),
306 PValue::U16(u) => <Self as NumCast>::from(u),
307 PValue::U32(u) => <Self as NumCast>::from(u),
308 PValue::U64(u) => <Self as NumCast>::from(u),
309 PValue::I8(i) => <Self as NumCast>::from(i),
310 PValue::I16(i) => <Self as NumCast>::from(i),
311 PValue::I32(i) => <Self as NumCast>::from(i),
312 PValue::I64(i) => <Self as NumCast>::from(i),
313 PValue::F16(f) => <Self as NumCast>::from(f),
314 PValue::F32(f) => <Self as NumCast>::from(f),
315 PValue::F64(f) => <Self as NumCast>::from(f),
316 }
317 .ok_or_else(|| {
318 vortex_err!("Cannot read primitive value {:?} as {}", value, PType::$PT)
319 })
320 }
321 }
322 };
323}
324
325int_pvalue!(u8, U8);
326int_pvalue!(u16, U16);
327int_pvalue!(u32, U32);
328int_pvalue!(u64, U64);
329int_pvalue!(usize, U64);
330int_pvalue!(i8, I8);
331int_pvalue!(i16, I16);
332int_pvalue!(i32, I32);
333int_pvalue!(i64, I64);
334
335float_pvalue!(f16, F16);
336float_pvalue!(f32, F32);
337float_pvalue!(f64, F64);
338
339macro_rules! impl_pvalue {
340 ($T:ty, $PT:tt) => {
341 impl From<$T> for PValue {
342 fn from(value: $T) -> Self {
343 PValue::$PT(value)
344 }
345 }
346 };
347}
348
349impl_pvalue!(u8, U8);
350impl_pvalue!(u16, U16);
351impl_pvalue!(u32, U32);
352impl_pvalue!(u64, U64);
353impl_pvalue!(i8, I8);
354impl_pvalue!(i16, I16);
355impl_pvalue!(i32, I32);
356impl_pvalue!(i64, I64);
357impl_pvalue!(f16, F16);
358impl_pvalue!(f32, F32);
359impl_pvalue!(f64, F64);
360
361impl From<usize> for PValue {
362 #[inline]
363 fn from(value: usize) -> PValue {
364 PValue::U64(value as u64)
365 }
366}
367
368impl Display for PValue {
369 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
370 match self {
371 Self::U8(v) => write!(f, "{v}u8"),
372 Self::U16(v) => write!(f, "{v}u16"),
373 Self::U32(v) => write!(f, "{v}u32"),
374 Self::U64(v) => write!(f, "{v}u64"),
375 Self::I8(v) => write!(f, "{v}i8"),
376 Self::I16(v) => write!(f, "{v}i16"),
377 Self::I32(v) => write!(f, "{v}i32"),
378 Self::I64(v) => write!(f, "{v}i64"),
379 Self::F16(v) => write!(f, "{v}f16"),
380 Self::F32(v) => write!(f, "{v}f32"),
381 Self::F64(v) => write!(f, "{v}f64"),
382 }
383 }
384}
385
386pub(super) trait CoercePValue: Sized {
387 fn coerce(value: PValue) -> VortexResult<Self>;
392}
393
394macro_rules! int_coerce {
395 ($T:ty) => {
396 impl CoercePValue for $T {
397 fn coerce(value: PValue) -> VortexResult<Self> {
398 Self::try_from(value)
399 }
400 }
401 };
402}
403
404int_coerce!(u8);
405int_coerce!(u16);
406int_coerce!(u32);
407int_coerce!(u64);
408int_coerce!(i8);
409int_coerce!(i16);
410int_coerce!(i32);
411int_coerce!(i64);
412
413impl CoercePValue for f16 {
414 #[allow(clippy::cast_possible_truncation)]
415 fn coerce(value: PValue) -> VortexResult<Self> {
416 match value {
427 PValue::U8(u) => Ok(Self::from_bits(u as u16)),
428 PValue::U16(u) => Ok(Self::from_bits(u)),
429 PValue::U32(u) => Ok(Self::from_bits(u as u16)),
430 PValue::U64(u) => Ok(Self::from_bits(u as u16)),
431 PValue::F16(u) => Ok(u),
432 PValue::F32(f) => {
433 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f32 to f16"))
434 }
435 PValue::F64(f) => {
436 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f64 to f16"))
437 }
438 _ => vortex_bail!("Cannot coerce {value:?} to f16: type not supported for coercion"),
439 }
440 }
441}
442
443impl CoercePValue for f32 {
444 #[allow(clippy::cast_possible_truncation)]
445 fn coerce(value: PValue) -> VortexResult<Self> {
446 match value {
448 PValue::U8(u) => Ok(Self::from_bits(u as u32)),
449 PValue::U16(u) => Ok(Self::from_bits(u as u32)),
450 PValue::U32(u) => Ok(Self::from_bits(u)),
451 PValue::U64(u) => Ok(Self::from_bits(u as u32)),
452 PValue::F16(f) => {
453 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f16 to f32"))
454 }
455 PValue::F32(f) => Ok(f),
456 PValue::F64(f) => {
457 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f64 to f32"))
458 }
459 _ => vortex_bail!("Unsupported PValue {value:?} type for f32"),
460 }
461 }
462}
463
464impl CoercePValue for f64 {
465 fn coerce(value: PValue) -> VortexResult<Self> {
466 match value {
468 PValue::U8(u) => Ok(Self::from_bits(u as u64)),
469 PValue::U16(u) => Ok(Self::from_bits(u as u64)),
470 PValue::U32(u) => Ok(Self::from_bits(u as u64)),
471 PValue::U64(u) => Ok(Self::from_bits(u)),
472 PValue::F16(f) => {
473 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f16 to f64"))
474 }
475 PValue::F32(f) => {
476 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f32 to f64"))
477 }
478 PValue::F64(f) => Ok(f),
479 _ => vortex_bail!("Unsupported PValue {value:?} type for f64"),
480 }
481 }
482}
483
484#[cfg(test)]
485#[allow(clippy::disallowed_types)]
486mod test {
487 use std::cmp::Ordering;
488 use std::collections::HashSet;
489
490 use vortex_dtype::PType;
491 use vortex_dtype::half::f16;
492
493 use crate::PValue;
494
495 #[test]
496 pub fn test_is_instance_of() {
497 assert!(PValue::U8(10).is_instance_of(&PType::U8));
498 assert!(!PValue::U8(10).is_instance_of(&PType::U16));
499 assert!(!PValue::U8(10).is_instance_of(&PType::I8));
500 assert!(!PValue::U8(10).is_instance_of(&PType::F16));
501
502 assert!(PValue::I8(10).is_instance_of(&PType::I8));
503 assert!(!PValue::I8(10).is_instance_of(&PType::I16));
504 assert!(!PValue::I8(10).is_instance_of(&PType::U8));
505 assert!(!PValue::I8(10).is_instance_of(&PType::F16));
506
507 assert!(PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::F16));
508 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::F32));
509 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::U16));
510 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::I16));
511 }
512
513 #[test]
514 fn test_compare_different_types() {
515 assert_eq!(
516 PValue::I8(4).partial_cmp(&PValue::I8(5)),
517 Some(Ordering::Less)
518 );
519 assert_eq!(
520 PValue::I8(4).partial_cmp(&PValue::I64(5)),
521 Some(Ordering::Less)
522 );
523 }
524
525 #[test]
526 fn test_hash() {
527 let set = HashSet::from([
528 PValue::U8(1),
529 PValue::U16(1),
530 PValue::U32(1),
531 PValue::U64(1),
532 PValue::I8(1),
533 PValue::I16(1),
534 PValue::I32(1),
535 PValue::I64(1),
536 PValue::I8(-1),
537 PValue::I16(-1),
538 PValue::I32(-1),
539 PValue::I64(-1),
540 ]);
541 assert_eq!(set.len(), 2);
542 }
543
544 #[test]
545 fn test_zero_values() {
546 assert_eq!(PValue::zero(PType::U8), PValue::U8(0));
547 assert_eq!(PValue::zero(PType::U16), PValue::U16(0));
548 assert_eq!(PValue::zero(PType::U32), PValue::U32(0));
549 assert_eq!(PValue::zero(PType::U64), PValue::U64(0));
550 assert_eq!(PValue::zero(PType::I8), PValue::I8(0));
551 assert_eq!(PValue::zero(PType::I16), PValue::I16(0));
552 assert_eq!(PValue::zero(PType::I32), PValue::I32(0));
553 assert_eq!(PValue::zero(PType::I64), PValue::I64(0));
554 assert_eq!(PValue::zero(PType::F16), PValue::F16(f16::from_f32(0.0)));
555 assert_eq!(PValue::zero(PType::F32), PValue::F32(0.0));
556 assert_eq!(PValue::zero(PType::F64), PValue::F64(0.0));
557 }
558
559 #[test]
560 fn test_ptype() {
561 assert_eq!(PValue::U8(10).ptype(), PType::U8);
562 assert_eq!(PValue::U16(10).ptype(), PType::U16);
563 assert_eq!(PValue::U32(10).ptype(), PType::U32);
564 assert_eq!(PValue::U64(10).ptype(), PType::U64);
565 assert_eq!(PValue::I8(10).ptype(), PType::I8);
566 assert_eq!(PValue::I16(10).ptype(), PType::I16);
567 assert_eq!(PValue::I32(10).ptype(), PType::I32);
568 assert_eq!(PValue::I64(10).ptype(), PType::I64);
569 assert_eq!(PValue::F16(f16::from_f32(10.0)).ptype(), PType::F16);
570 assert_eq!(PValue::F32(10.0).ptype(), PType::F32);
571 assert_eq!(PValue::F64(10.0).ptype(), PType::F64);
572 }
573
574 #[test]
575 fn test_reinterpret_cast_same_type() {
576 let value = PValue::U32(42);
577 assert_eq!(value.reinterpret_cast(PType::U32), value);
578 }
579
580 #[test]
581 fn test_reinterpret_cast_u8_i8() {
582 let value = PValue::U8(255);
583 let casted = value.reinterpret_cast(PType::I8);
584 assert_eq!(casted, PValue::I8(-1));
585 }
586
587 #[test]
588 fn test_reinterpret_cast_u16_types() {
589 let value = PValue::U16(12345);
590
591 let as_i16 = value.reinterpret_cast(PType::I16);
593 assert_eq!(as_i16, PValue::I16(12345));
594
595 let as_f16 = value.reinterpret_cast(PType::F16);
597 assert_eq!(as_f16, PValue::F16(f16::from_bits(12345)));
598 }
599
600 #[test]
601 fn test_reinterpret_cast_u32_types() {
602 let value = PValue::U32(0x3f800000); let as_f32 = value.reinterpret_cast(PType::F32);
606 assert_eq!(as_f32, PValue::F32(1.0));
607
608 let value2 = PValue::U32(0x80000000);
610 let as_i32 = value2.reinterpret_cast(PType::I32);
611 assert_eq!(as_i32, PValue::I32(i32::MIN));
612 }
613
614 #[test]
615 fn test_reinterpret_cast_f32_to_u32() {
616 let value = PValue::F32(1.0);
617 let as_u32 = value.reinterpret_cast(PType::U32);
618 assert_eq!(as_u32, PValue::U32(0x3f800000));
619 }
620
621 #[test]
622 fn test_reinterpret_cast_f64_to_i64() {
623 let value = PValue::F64(1.0);
624 let as_i64 = value.reinterpret_cast(PType::I64);
625 assert_eq!(as_i64, PValue::I64(0x3ff0000000000000_i64));
626 }
627
628 #[test]
629 #[should_panic(expected = "Cannot reinterpret cast between types of different widths")]
630 fn test_reinterpret_cast_different_widths() {
631 let value = PValue::U8(42);
632 let _ = value.reinterpret_cast(PType::U16);
633 }
634
635 #[test]
636 fn test_as_primitive_conversions() {
637 assert_eq!(PValue::U8(42).as_u8(), Some(42));
639 assert_eq!(PValue::I8(42).as_u8(), Some(42));
640 assert_eq!(PValue::U16(255).as_u8(), Some(255));
641 assert_eq!(PValue::U16(256).as_u8(), None); assert_eq!(PValue::I32(42).as_i32(), Some(42));
645 assert_eq!(PValue::U32(42).as_i32(), Some(42));
646 assert_eq!(PValue::I64(42).as_i32(), Some(42));
647 assert_eq!(PValue::U64(u64::MAX).as_i32(), None); assert_eq!(PValue::F64(42.5).as_f64(), Some(42.5));
651 assert_eq!(PValue::F32(42.5).as_f64(), Some(42.5f64));
652 assert_eq!(PValue::I32(42).as_f64(), Some(42.0));
653 }
654
655 #[test]
656 fn test_try_from_pvalue_integers() {
657 assert_eq!(u8::try_from(PValue::U8(42)).unwrap(), 42);
659 assert_eq!(u8::try_from(PValue::I8(42)).unwrap(), 42);
660 assert!(u8::try_from(PValue::I8(-1)).is_err());
661 assert!(u8::try_from(PValue::U16(256)).is_err());
662
663 assert_eq!(i32::try_from(PValue::I32(42)).unwrap(), 42);
665 assert_eq!(i32::try_from(PValue::I16(-100)).unwrap(), -100);
666 assert!(i32::try_from(PValue::U64(u64::MAX)).is_err());
667
668 assert!(i32::try_from(PValue::F32(42.5)).is_err());
670 }
671
672 #[test]
673 fn test_try_from_pvalue_floats() {
674 assert_eq!(f32::try_from(PValue::F32(42.5)).unwrap(), 42.5);
676 assert_eq!(f32::try_from(PValue::I32(42)).unwrap(), 42.0);
677 assert_eq!(f32::try_from(PValue::U8(255)).unwrap(), 255.0);
678
679 assert_eq!(f64::try_from(PValue::F64(42.5)).unwrap(), 42.5);
681 assert_eq!(f64::try_from(PValue::F32(42.5)).unwrap(), 42.5f64);
682 assert_eq!(f64::try_from(PValue::I64(-100)).unwrap(), -100.0);
683 }
684
685 #[test]
686 fn test_from_usize() {
687 let value: PValue = 42usize.into();
688 assert_eq!(value, PValue::U64(42));
689
690 let max_value: PValue = usize::MAX.into();
691 assert_eq!(max_value, PValue::U64(usize::MAX as u64));
692 }
693
694 #[test]
695 fn test_equality_cross_types() {
696 assert_eq!(PValue::U8(42), PValue::U16(42));
698 assert_eq!(PValue::U8(42), PValue::U32(42));
699 assert_eq!(PValue::U8(42), PValue::U64(42));
700 assert_eq!(PValue::I8(42), PValue::I16(42));
701 assert_eq!(PValue::I8(42), PValue::I32(42));
702 assert_eq!(PValue::I8(42), PValue::I64(42));
703
704 assert_eq!(PValue::U8(42), PValue::I8(42));
706 assert_eq!(PValue::U32(42), PValue::I32(42));
707
708 assert_eq!(PValue::F32(42.0), PValue::F32(42.0));
710 assert_eq!(PValue::F64(42.0), PValue::F64(42.0));
711 assert_ne!(PValue::F32(42.0), PValue::F64(42.0)); assert_ne!(PValue::F32(42.0), PValue::I32(42));
715 }
716
717 #[test]
718 fn test_partial_ord_cross_types() {
719 assert_eq!(
721 PValue::U8(10).partial_cmp(&PValue::U16(20)),
722 Some(Ordering::Less)
723 );
724 assert_eq!(
725 PValue::U32(30).partial_cmp(&PValue::U8(20)),
726 Some(Ordering::Greater)
727 );
728
729 assert_eq!(
731 PValue::I8(-10).partial_cmp(&PValue::I64(0)),
732 Some(Ordering::Less)
733 );
734 assert_eq!(
735 PValue::I32(10).partial_cmp(&PValue::I16(10)),
736 Some(Ordering::Equal)
737 );
738
739 assert_eq!(
741 PValue::F32(1.0).partial_cmp(&PValue::F32(2.0)),
742 Some(Ordering::Less)
743 );
744 assert_eq!(
745 PValue::F64(2.0).partial_cmp(&PValue::F64(1.0)),
746 Some(Ordering::Greater)
747 );
748
749 assert_eq!(
751 PValue::U32(42).partial_cmp(&PValue::I32(42)),
752 Some(Ordering::Equal)
753 ); assert_eq!(PValue::F32(42.0).partial_cmp(&PValue::I32(42)), None);
755 assert_eq!(PValue::F32(42.0).partial_cmp(&PValue::F64(42.0)), None);
756 }
757
758 #[test]
759 fn test_to_le_bytes() {
760 use vortex_dtype::ToBytes;
761
762 assert_eq!(PValue::U8(0x12).to_le_bytes(), &[0x12]);
763 assert_eq!(PValue::U16(0x1234).to_le_bytes(), &[0x34, 0x12]);
764 assert_eq!(
765 PValue::U32(0x12345678).to_le_bytes(),
766 &[0x78, 0x56, 0x34, 0x12]
767 );
768
769 assert_eq!(PValue::I8(-1).to_le_bytes(), &[0xFF]);
770 assert_eq!(PValue::I16(-1).to_le_bytes(), &[0xFF, 0xFF]);
771
772 let f32_bytes = PValue::F32(1.0).to_le_bytes();
773 assert_eq!(f32_bytes.len(), 4);
774
775 let f64_bytes = PValue::F64(1.0).to_le_bytes();
776 assert_eq!(f64_bytes.len(), 8);
777 }
778
779 #[test]
780 fn test_f16_special_values() {
781 let nan = f16::NAN;
783 let nan_value = PValue::F16(nan);
784 assert!(nan_value.as_f16().unwrap().is_nan());
785
786 let inf = f16::INFINITY;
788 let inf_value = PValue::F16(inf);
789 assert!(inf_value.as_f16().unwrap().is_infinite());
790
791 assert_eq!(
793 PValue::F16(nan).partial_cmp(&PValue::F16(nan)),
794 Some(Ordering::Equal)
795 );
796 }
797
798 #[test]
799 fn test_coerce_pvalue() {
800 use super::CoercePValue;
801
802 assert_eq!(u32::coerce(PValue::U16(42)).unwrap(), 42u32);
804 assert_eq!(i64::coerce(PValue::I32(-42)).unwrap(), -42i64);
805
806 assert_eq!(f32::coerce(PValue::U32(0x3f800000)).unwrap(), 1.0f32);
808 assert_eq!(
809 f64::coerce(PValue::U64(0x3ff0000000000000)).unwrap(),
810 1.0f64
811 );
812 }
813}