1use core::fmt::Display;
5use std::cmp::Ordering;
6use std::hash::{Hash, Hasher};
7
8use num_traits::{NumCast, ToPrimitive};
9use paste::paste;
10use vortex_dtype::half::f16;
11use vortex_dtype::{NativePType, PType, ToBytes};
12use vortex_error::{
13 VortexError, VortexExpect, VortexResult, vortex_bail, vortex_ensure, vortex_err,
14};
15
16#[derive(Debug, Clone, Copy)]
21pub enum PValue {
22 U8(u8),
24 U16(u16),
26 U32(u32),
28 U64(u64),
30 I8(i8),
32 I16(i16),
34 I32(i32),
36 I64(i64),
38 F16(f16),
40 F32(f32),
42 F64(f64),
44}
45
46impl PartialEq for PValue {
47 fn eq(&self, other: &Self) -> bool {
48 match (self, other) {
49 (Self::U8(s), o) => o.as_u64().vortex_expect("upcast") == *s as u64,
50 (Self::U16(s), o) => o.as_u64().vortex_expect("upcast") == *s as u64,
51 (Self::U32(s), o) => o.as_u64().vortex_expect("upcast") == *s as u64,
52 (Self::U64(s), o) => o.as_u64().vortex_expect("upcast") == *s,
53 (Self::I8(s), o) => o.as_i64().vortex_expect("upcast") == *s as i64,
54 (Self::I16(s), o) => o.as_i64().vortex_expect("upcast") == *s as i64,
55 (Self::I32(s), o) => o.as_i64().vortex_expect("upcast") == *s as i64,
56 (Self::I64(s), o) => o.as_i64().vortex_expect("upcast") == *s,
57 (Self::F16(s), Self::F16(o)) => s.is_eq(*o),
58 (Self::F32(s), Self::F32(o)) => s.is_eq(*o),
59 (Self::F64(s), Self::F64(o)) => s.is_eq(*o),
60 (..) => false,
61 }
62 }
63}
64
65impl Eq for PValue {}
66
67impl PartialOrd for PValue {
68 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
69 match (self, other) {
70 (Self::U8(s), o) => Some((*s as u64).cmp(&o.as_u64().vortex_expect("upcast"))),
71 (Self::U16(s), o) => Some((*s as u64).cmp(&o.as_u64().vortex_expect("upcast"))),
72 (Self::U32(s), o) => Some((*s as u64).cmp(&o.as_u64().vortex_expect("upcast"))),
73 (Self::U64(s), o) => Some((*s).cmp(&o.as_u64().vortex_expect("upcast"))),
74 (Self::I8(s), o) => Some((*s as i64).cmp(&o.as_i64().vortex_expect("upcast"))),
75 (Self::I16(s), o) => Some((*s as i64).cmp(&o.as_i64().vortex_expect("upcast"))),
76 (Self::I32(s), o) => Some((*s as i64).cmp(&o.as_i64().vortex_expect("upcast"))),
77 (Self::I64(s), o) => Some((*s).cmp(&o.as_i64().vortex_expect("upcast"))),
78 (Self::F16(s), Self::F16(o)) => Some(s.total_compare(*o)),
79 (Self::F32(s), Self::F32(o)) => Some(s.total_compare(*o)),
80 (Self::F64(s), Self::F64(o)) => Some(s.total_compare(*o)),
81 (..) => None,
82 }
83 }
84}
85
86impl Hash for PValue {
87 fn hash<H: Hasher>(&self, state: &mut H) {
88 match self {
89 PValue::U8(_) | PValue::U16(_) | PValue::U32(_) | PValue::U64(_) => {
90 self.as_u64().vortex_expect("upcast").hash(state)
91 }
92 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
93 self.as_i64().vortex_expect("upcast").hash(state)
94 }
95 PValue::F16(v) => v.to_le_bytes().hash(state),
96 PValue::F32(v) => v.to_le_bytes().hash(state),
97 PValue::F64(v) => v.to_le_bytes().hash(state),
98 }
99 }
100}
101
102impl ToBytes for PValue {
103 fn to_le_bytes(&self) -> &[u8] {
104 match self {
105 PValue::U8(v) => v.to_le_bytes(),
106 PValue::U16(v) => v.to_le_bytes(),
107 PValue::U32(v) => v.to_le_bytes(),
108 PValue::U64(v) => v.to_le_bytes(),
109 PValue::I8(v) => v.to_le_bytes(),
110 PValue::I16(v) => v.to_le_bytes(),
111 PValue::I32(v) => v.to_le_bytes(),
112 PValue::I64(v) => v.to_le_bytes(),
113 PValue::F16(v) => v.to_le_bytes(),
114 PValue::F32(v) => v.to_le_bytes(),
115 PValue::F64(v) => v.to_le_bytes(),
116 }
117 }
118}
119
120macro_rules! as_primitive {
121 ($T:ty, $PT:tt) => {
122 paste! {
123 #[doc = "Access PValue as `" $T "`, returning `None` if conversion is unsuccessful"]
124 pub fn [<as_ $T>](self) -> Option<$T> {
125 <$T>::try_from(self).ok()
126 }
127 }
128 };
129}
130
131impl PValue {
132 pub fn zero(ptype: PType) -> PValue {
134 match ptype {
135 PType::U8 => PValue::U8(0),
136 PType::U16 => PValue::U16(0),
137 PType::U32 => PValue::U32(0),
138 PType::U64 => PValue::U64(0),
139 PType::I8 => PValue::I8(0),
140 PType::I16 => PValue::I16(0),
141 PType::I32 => PValue::I32(0),
142 PType::I64 => PValue::I64(0),
143 PType::F16 => PValue::F16(f16::ZERO),
144 PType::F32 => PValue::F32(0.0),
145 PType::F64 => PValue::F64(0.0),
146 }
147 }
148
149 pub fn ptype(&self) -> PType {
151 match self {
152 Self::U8(_) => PType::U8,
153 Self::U16(_) => PType::U16,
154 Self::U32(_) => PType::U32,
155 Self::U64(_) => PType::U64,
156 Self::I8(_) => PType::I8,
157 Self::I16(_) => PType::I16,
158 Self::I32(_) => PType::I32,
159 Self::I64(_) => PType::I64,
160 Self::F16(_) => PType::F16,
161 Self::F32(_) => PType::F32,
162 Self::F64(_) => PType::F64,
163 }
164 }
165
166 pub fn is_instance_of(&self, ptype: &PType) -> bool {
168 &self.ptype() == ptype
169 }
170
171 #[inline]
175 pub fn cast<T: NativePType>(&self) -> T {
176 self.cast_opt::<T>().vortex_expect("as_primitive")
177 }
178
179 #[inline]
183 pub fn cast_opt<T: NativePType>(&self) -> Option<T> {
184 match *self {
185 PValue::U8(u) => T::from_u8(u),
186 PValue::U16(u) => T::from_u16(u),
187 PValue::U32(u) => T::from_u32(u),
188 PValue::U64(u) => T::from_u64(u),
189 PValue::I8(i) => T::from_i8(i),
190 PValue::I16(i) => T::from_i16(i),
191 PValue::I32(i) => T::from_i32(i),
192 PValue::I64(i) => T::from_i64(i),
193 PValue::F16(f) => T::from_f16(f),
194 PValue::F32(f) => T::from_f32(f),
195 PValue::F64(f) => T::from_f64(f),
196 }
197 }
198
199 pub fn is_nan(&self) -> bool {
201 match self {
202 PValue::F16(f) => f.is_nan(),
203 PValue::F32(f) => f.is_nan(),
204 PValue::F64(f) => f.is_nan(),
205 _ => false,
206 }
207 }
208
209 pub fn reinterpret_cast(&self, ptype: PType) -> Self {
217 if ptype == self.ptype() {
218 return *self;
219 }
220
221 assert_eq!(
222 ptype.byte_width(),
223 self.ptype().byte_width(),
224 "Cannot reinterpret cast between types of different widths"
225 );
226
227 match self {
228 PValue::U8(v) => u8::cast_signed(*v).into(),
229 PValue::U16(v) => match ptype {
230 PType::I16 => u16::cast_signed(*v).into(),
231 PType::F16 => f16::from_bits(*v).into(),
232 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
233 },
234 PValue::U32(v) => match ptype {
235 PType::I32 => u32::cast_signed(*v).into(),
236 PType::F32 => f32::from_bits(*v).into(),
237 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
238 },
239 PValue::U64(v) => match ptype {
240 PType::I64 => u64::cast_signed(*v).into(),
241 PType::F64 => f64::from_bits(*v).into(),
242 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
243 },
244 PValue::I8(v) => i8::cast_unsigned(*v).into(),
245 PValue::I16(v) => match ptype {
246 PType::U16 => i16::cast_unsigned(*v).into(),
247 PType::F16 => f16::from_bits(v.cast_unsigned()).into(),
248 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
249 },
250 PValue::I32(v) => match ptype {
251 PType::U32 => i32::cast_unsigned(*v).into(),
252 PType::F32 => f32::from_bits(i32::cast_unsigned(*v)).into(),
253 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
254 },
255 PValue::I64(v) => match ptype {
256 PType::U64 => i64::cast_unsigned(*v).into(),
257 PType::F64 => f64::from_bits(i64::cast_unsigned(*v)).into(),
258 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
259 },
260 PValue::F16(v) => match ptype {
261 PType::U16 => v.to_bits().into(),
262 PType::I16 => v.to_bits().cast_signed().into(),
263 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
264 },
265 PValue::F32(v) => match ptype {
266 PType::U32 => f32::to_bits(*v).into(),
267 PType::I32 => f32::to_bits(*v).cast_signed().into(),
268 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
269 },
270 PValue::F64(v) => match ptype {
271 PType::U64 => f64::to_bits(*v).into(),
272 PType::I64 => f64::to_bits(*v).cast_signed().into(),
273 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
274 },
275 }
276 }
277
278 as_primitive!(i8, I8);
279 as_primitive!(i16, I16);
280 as_primitive!(i32, I32);
281 as_primitive!(i64, I64);
282 as_primitive!(u8, U8);
283 as_primitive!(u16, U16);
284 as_primitive!(u32, U32);
285 as_primitive!(u64, U64);
286 as_primitive!(f16, F16);
287 as_primitive!(f32, F32);
288 as_primitive!(f64, F64);
289}
290
291macro_rules! int_pvalue {
292 ($T:ty, $PT:tt) => {
293 impl TryFrom<PValue> for $T {
294 type Error = VortexError;
295
296 fn try_from(value: PValue) -> Result<Self, Self::Error> {
297 match value {
298 PValue::U8(_)
299 | PValue::U16(_)
300 | PValue::U32(_)
301 | PValue::U64(_)
302 | PValue::I8(_)
303 | PValue::I16(_)
304 | PValue::I32(_)
305 | PValue::I64(_) => Some(value),
306 _ => None,
307 }
308 .and_then(|v| PValue::cast_opt(&v))
309 .ok_or_else(|| {
310 vortex_err!("Cannot read primitive value {:?} as {}", value, PType::$PT)
311 })
312 }
313 }
314 };
315}
316
317macro_rules! float_pvalue {
318 ($T:ty, $PT:tt) => {
319 impl TryFrom<PValue> for $T {
320 type Error = VortexError;
321
322 fn try_from(value: PValue) -> Result<Self, Self::Error> {
323 value.cast_opt().ok_or_else(|| {
324 vortex_err!("Cannot read primitive value {:?} as {}", value, PType::$PT)
325 })
326 }
327 }
328 };
329}
330
331impl TryFrom<PValue> for usize {
332 type Error = VortexError;
333
334 fn try_from(value: PValue) -> Result<Self, Self::Error> {
335 value
336 .cast_opt::<u64>()
337 .and_then(|v| v.to_usize())
338 .ok_or_else(|| vortex_err!("Cannot read primitive value {:?} as usize", value))
339 }
340}
341
342int_pvalue!(u8, U8);
343int_pvalue!(u16, U16);
344int_pvalue!(u32, U32);
345int_pvalue!(u64, U64);
346int_pvalue!(i8, I8);
347int_pvalue!(i16, I16);
348int_pvalue!(i32, I32);
349int_pvalue!(i64, I64);
350
351float_pvalue!(f16, F16);
352float_pvalue!(f32, F32);
353float_pvalue!(f64, F64);
354
355macro_rules! impl_pvalue {
356 ($T:ty, $PT:tt) => {
357 impl From<$T> for PValue {
358 fn from(value: $T) -> Self {
359 PValue::$PT(value)
360 }
361 }
362 };
363}
364
365impl_pvalue!(u8, U8);
366impl_pvalue!(u16, U16);
367impl_pvalue!(u32, U32);
368impl_pvalue!(u64, U64);
369impl_pvalue!(i8, I8);
370impl_pvalue!(i16, I16);
371impl_pvalue!(i32, I32);
372impl_pvalue!(i64, I64);
373impl_pvalue!(f16, F16);
374impl_pvalue!(f32, F32);
375impl_pvalue!(f64, F64);
376
377impl From<usize> for PValue {
378 #[inline]
379 fn from(value: usize) -> PValue {
380 PValue::U64(value as u64)
381 }
382}
383
384impl Display for PValue {
385 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
386 match self {
387 Self::U8(v) => write!(f, "{v}u8"),
388 Self::U16(v) => write!(f, "{v}u16"),
389 Self::U32(v) => write!(f, "{v}u32"),
390 Self::U64(v) => write!(f, "{v}u64"),
391 Self::I8(v) => write!(f, "{v}i8"),
392 Self::I16(v) => write!(f, "{v}i16"),
393 Self::I32(v) => write!(f, "{v}i32"),
394 Self::I64(v) => write!(f, "{v}i64"),
395 Self::F16(v) => write!(f, "{v}f16"),
396 Self::F32(v) => write!(f, "{v}f32"),
397 Self::F64(v) => write!(f, "{v}f64"),
398 }
399 }
400}
401
402pub(super) trait CoercePValue: Sized {
403 fn coerce(value: PValue) -> VortexResult<Self>;
408}
409
410macro_rules! int_coerce {
411 ($T:ty) => {
412 impl CoercePValue for $T {
413 #[inline]
414 fn coerce(value: PValue) -> VortexResult<Self> {
415 Self::try_from(value)
416 }
417 }
418 };
419}
420
421int_coerce!(u8);
422int_coerce!(u16);
423int_coerce!(u32);
424int_coerce!(u64);
425int_coerce!(i8);
426int_coerce!(i16);
427int_coerce!(i32);
428int_coerce!(i64);
429
430impl CoercePValue for f16 {
431 #[allow(clippy::cast_possible_truncation)]
432 fn coerce(value: PValue) -> VortexResult<Self> {
433 match value {
444 PValue::U8(u) => Ok(Self::from_bits(u as u16)),
445 PValue::U16(u) => Ok(Self::from_bits(u)),
446 PValue::U32(u) => {
447 vortex_ensure!(
448 u <= u16::MAX as u32,
449 "Cannot coerce U32 value to f16: value out of range"
450 );
451 Ok(Self::from_bits(u as u16))
452 }
453 PValue::U64(u) => {
454 vortex_ensure!(
455 u <= u16::MAX as u64,
456 "Cannot coerce U64 value to f16: value out of range"
457 );
458 Ok(Self::from_bits(u as u16))
459 }
460 PValue::F16(u) => Ok(u),
461 PValue::F32(f) => {
462 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f32 to f16"))
463 }
464 PValue::F64(f) => {
465 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f64 to f16"))
466 }
467 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
468 vortex_bail!("Cannot coerce {value:?} to f16: type not supported for coercion")
469 }
470 }
471 }
472}
473
474impl CoercePValue for f32 {
475 #[allow(clippy::cast_possible_truncation)]
476 fn coerce(value: PValue) -> VortexResult<Self> {
477 match value {
479 PValue::U8(u) => Ok(Self::from_bits(u as u32)),
480 PValue::U16(u) => Ok(Self::from_bits(u as u32)),
481 PValue::U32(u) => Ok(Self::from_bits(u)),
482 PValue::U64(u) => {
483 vortex_ensure!(
484 u <= u32::MAX as u64,
485 "Cannot coerce U64 value to f32: value out of range"
486 );
487 Ok(Self::from_bits(u as u32))
488 }
489 PValue::F16(f) => {
490 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f16 to f32"))
491 }
492 PValue::F32(f) => Ok(f),
493 PValue::F64(f) => {
494 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f64 to f32"))
495 }
496 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
497 vortex_bail!("Unsupported PValue {value:?} type for f32")
498 }
499 }
500 }
501}
502
503impl CoercePValue for f64 {
504 fn coerce(value: PValue) -> VortexResult<Self> {
505 match value {
507 PValue::U8(u) => Ok(Self::from_bits(u as u64)),
508 PValue::U16(u) => Ok(Self::from_bits(u as u64)),
509 PValue::U32(u) => Ok(Self::from_bits(u as u64)),
510 PValue::U64(u) => Ok(Self::from_bits(u)),
511 PValue::F16(f) => {
512 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f16 to f64"))
513 }
514 PValue::F32(f) => {
515 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f32 to f64"))
516 }
517 PValue::F64(f) => Ok(f),
518 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
519 vortex_bail!("Unsupported PValue {value:?} type for f64")
520 }
521 }
522 }
523}
524
525#[cfg(test)]
526mod test {
527 use std::cmp::Ordering;
528
529 use vortex_dtype::half::f16;
530 use vortex_dtype::{FromPrimitiveOrF16, PType, ToBytes};
531 use vortex_utils::aliases::hash_set::HashSet;
532
533 use crate::PValue;
534 use crate::pvalue::CoercePValue;
535
536 #[test]
537 pub fn test_is_instance_of() {
538 assert!(PValue::U8(10).is_instance_of(&PType::U8));
539 assert!(!PValue::U8(10).is_instance_of(&PType::U16));
540 assert!(!PValue::U8(10).is_instance_of(&PType::I8));
541 assert!(!PValue::U8(10).is_instance_of(&PType::F16));
542
543 assert!(PValue::I8(10).is_instance_of(&PType::I8));
544 assert!(!PValue::I8(10).is_instance_of(&PType::I16));
545 assert!(!PValue::I8(10).is_instance_of(&PType::U8));
546 assert!(!PValue::I8(10).is_instance_of(&PType::F16));
547
548 assert!(PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::F16));
549 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::F32));
550 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::U16));
551 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::I16));
552 }
553
554 #[test]
555 fn test_compare_different_types() {
556 assert_eq!(
557 PValue::I8(4).partial_cmp(&PValue::I8(5)),
558 Some(Ordering::Less)
559 );
560 assert_eq!(
561 PValue::I8(4).partial_cmp(&PValue::I64(5)),
562 Some(Ordering::Less)
563 );
564 }
565
566 #[test]
567 fn test_hash() {
568 let set = HashSet::from([
569 PValue::U8(1),
570 PValue::U16(1),
571 PValue::U32(1),
572 PValue::U64(1),
573 PValue::I8(1),
574 PValue::I16(1),
575 PValue::I32(1),
576 PValue::I64(1),
577 PValue::I8(-1),
578 PValue::I16(-1),
579 PValue::I32(-1),
580 PValue::I64(-1),
581 ]);
582 assert_eq!(set.len(), 2);
583 }
584
585 #[test]
586 fn test_zero_values() {
587 assert_eq!(PValue::zero(PType::U8), PValue::U8(0));
588 assert_eq!(PValue::zero(PType::U16), PValue::U16(0));
589 assert_eq!(PValue::zero(PType::U32), PValue::U32(0));
590 assert_eq!(PValue::zero(PType::U64), PValue::U64(0));
591 assert_eq!(PValue::zero(PType::I8), PValue::I8(0));
592 assert_eq!(PValue::zero(PType::I16), PValue::I16(0));
593 assert_eq!(PValue::zero(PType::I32), PValue::I32(0));
594 assert_eq!(PValue::zero(PType::I64), PValue::I64(0));
595 assert_eq!(PValue::zero(PType::F16), PValue::F16(f16::from_f32(0.0)));
596 assert_eq!(PValue::zero(PType::F32), PValue::F32(0.0));
597 assert_eq!(PValue::zero(PType::F64), PValue::F64(0.0));
598 }
599
600 #[test]
601 fn test_ptype() {
602 assert_eq!(PValue::U8(10).ptype(), PType::U8);
603 assert_eq!(PValue::U16(10).ptype(), PType::U16);
604 assert_eq!(PValue::U32(10).ptype(), PType::U32);
605 assert_eq!(PValue::U64(10).ptype(), PType::U64);
606 assert_eq!(PValue::I8(10).ptype(), PType::I8);
607 assert_eq!(PValue::I16(10).ptype(), PType::I16);
608 assert_eq!(PValue::I32(10).ptype(), PType::I32);
609 assert_eq!(PValue::I64(10).ptype(), PType::I64);
610 assert_eq!(PValue::F16(f16::from_f32(10.0)).ptype(), PType::F16);
611 assert_eq!(PValue::F32(10.0).ptype(), PType::F32);
612 assert_eq!(PValue::F64(10.0).ptype(), PType::F64);
613 }
614
615 #[test]
616 fn test_reinterpret_cast_same_type() {
617 let value = PValue::U32(42);
618 assert_eq!(value.reinterpret_cast(PType::U32), value);
619 }
620
621 #[test]
622 fn test_reinterpret_cast_u8_i8() {
623 let value = PValue::U8(255);
624 let casted = value.reinterpret_cast(PType::I8);
625 assert_eq!(casted, PValue::I8(-1));
626 }
627
628 #[test]
629 fn test_reinterpret_cast_u16_types() {
630 let value = PValue::U16(12345);
631
632 let as_i16 = value.reinterpret_cast(PType::I16);
634 assert_eq!(as_i16, PValue::I16(12345));
635
636 let as_f16 = value.reinterpret_cast(PType::F16);
638 assert_eq!(as_f16, PValue::F16(f16::from_bits(12345)));
639 }
640
641 #[test]
642 fn test_reinterpret_cast_u32_types() {
643 let value = PValue::U32(0x3f800000); let as_f32 = value.reinterpret_cast(PType::F32);
647 assert_eq!(as_f32, PValue::F32(1.0));
648
649 let value2 = PValue::U32(0x80000000);
651 let as_i32 = value2.reinterpret_cast(PType::I32);
652 assert_eq!(as_i32, PValue::I32(i32::MIN));
653 }
654
655 #[test]
656 fn test_reinterpret_cast_f32_to_u32() {
657 let value = PValue::F32(1.0);
658 let as_u32 = value.reinterpret_cast(PType::U32);
659 assert_eq!(as_u32, PValue::U32(0x3f800000));
660 }
661
662 #[test]
663 fn test_reinterpret_cast_f64_to_i64() {
664 let value = PValue::F64(1.0);
665 let as_i64 = value.reinterpret_cast(PType::I64);
666 assert_eq!(as_i64, PValue::I64(0x3ff0000000000000_i64));
667 }
668
669 #[test]
670 #[should_panic(expected = "Cannot reinterpret cast between types of different widths")]
671 fn test_reinterpret_cast_different_widths() {
672 let value = PValue::U8(42);
673 let _ = value.reinterpret_cast(PType::U16);
674 }
675
676 #[test]
677 fn test_as_primitive_conversions() {
678 assert_eq!(PValue::U8(42).as_u8(), Some(42));
680 assert_eq!(PValue::I8(42).as_u8(), Some(42));
681 assert_eq!(PValue::U16(255).as_u8(), Some(255));
682 assert_eq!(PValue::U16(256).as_u8(), None); assert_eq!(PValue::I32(42).as_i32(), Some(42));
686 assert_eq!(PValue::U32(42).as_i32(), Some(42));
687 assert_eq!(PValue::I64(42).as_i32(), Some(42));
688 assert_eq!(PValue::U64(u64::MAX).as_i32(), None); assert_eq!(PValue::F64(42.5).as_f64(), Some(42.5));
692 assert_eq!(PValue::F32(42.5).as_f64(), Some(42.5f64));
693 assert_eq!(PValue::I32(42).as_f64(), Some(42.0));
694 }
695
696 #[test]
697 fn test_try_from_pvalue_integers() {
698 assert_eq!(u8::try_from(PValue::U8(42)).unwrap(), 42);
700 assert_eq!(u8::try_from(PValue::I8(42)).unwrap(), 42);
701 assert!(u8::try_from(PValue::I8(-1)).is_err());
702 assert!(u8::try_from(PValue::U16(256)).is_err());
703
704 assert_eq!(i32::try_from(PValue::I32(42)).unwrap(), 42);
706 assert_eq!(i32::try_from(PValue::I16(-100)).unwrap(), -100);
707 assert!(i32::try_from(PValue::U64(u64::MAX)).is_err());
708
709 assert!(i32::try_from(PValue::F32(42.5)).is_err());
711 }
712
713 #[test]
714 fn test_try_from_pvalue_floats() {
715 assert_eq!(f32::try_from(PValue::F32(42.5)).unwrap(), 42.5);
717 assert_eq!(f32::try_from(PValue::I32(42)).unwrap(), 42.0);
718 assert_eq!(f32::try_from(PValue::U8(255)).unwrap(), 255.0);
719
720 assert_eq!(f64::try_from(PValue::F64(42.5)).unwrap(), 42.5);
722 assert_eq!(f64::try_from(PValue::F32(42.5)).unwrap(), 42.5f64);
723 assert_eq!(f64::try_from(PValue::I64(-100)).unwrap(), -100.0);
724 }
725
726 #[test]
727 fn test_from_usize() {
728 let value: PValue = 42usize.into();
729 assert_eq!(value, PValue::U64(42));
730
731 let max_value: PValue = usize::MAX.into();
732 assert_eq!(max_value, PValue::U64(usize::MAX as u64));
733 }
734
735 #[test]
736 fn test_equality_cross_types() {
737 assert_eq!(PValue::U8(42), PValue::U16(42));
739 assert_eq!(PValue::U8(42), PValue::U32(42));
740 assert_eq!(PValue::U8(42), PValue::U64(42));
741 assert_eq!(PValue::I8(42), PValue::I16(42));
742 assert_eq!(PValue::I8(42), PValue::I32(42));
743 assert_eq!(PValue::I8(42), PValue::I64(42));
744
745 assert_eq!(PValue::U8(42), PValue::I8(42));
747 assert_eq!(PValue::U32(42), PValue::I32(42));
748
749 assert_eq!(PValue::F32(42.0), PValue::F32(42.0));
751 assert_eq!(PValue::F64(42.0), PValue::F64(42.0));
752 assert_ne!(PValue::F32(42.0), PValue::F64(42.0)); assert_ne!(PValue::F32(42.0), PValue::I32(42));
756 }
757
758 #[test]
759 fn test_partial_ord_cross_types() {
760 assert_eq!(
762 PValue::U8(10).partial_cmp(&PValue::U16(20)),
763 Some(Ordering::Less)
764 );
765 assert_eq!(
766 PValue::U32(30).partial_cmp(&PValue::U8(20)),
767 Some(Ordering::Greater)
768 );
769
770 assert_eq!(
772 PValue::I8(-10).partial_cmp(&PValue::I64(0)),
773 Some(Ordering::Less)
774 );
775 assert_eq!(
776 PValue::I32(10).partial_cmp(&PValue::I16(10)),
777 Some(Ordering::Equal)
778 );
779
780 assert_eq!(
782 PValue::F32(1.0).partial_cmp(&PValue::F32(2.0)),
783 Some(Ordering::Less)
784 );
785 assert_eq!(
786 PValue::F64(2.0).partial_cmp(&PValue::F64(1.0)),
787 Some(Ordering::Greater)
788 );
789
790 assert_eq!(
792 PValue::U32(42).partial_cmp(&PValue::I32(42)),
793 Some(Ordering::Equal)
794 ); assert_eq!(PValue::F32(42.0).partial_cmp(&PValue::I32(42)), None);
796 assert_eq!(PValue::F32(42.0).partial_cmp(&PValue::F64(42.0)), None);
797 }
798
799 #[test]
800 fn test_to_le_bytes() {
801 assert_eq!(PValue::U8(0x12).to_le_bytes(), &[0x12]);
802 assert_eq!(PValue::U16(0x1234).to_le_bytes(), &[0x34, 0x12]);
803 assert_eq!(
804 PValue::U32(0x12345678).to_le_bytes(),
805 &[0x78, 0x56, 0x34, 0x12]
806 );
807
808 assert_eq!(PValue::I8(-1).to_le_bytes(), &[0xFF]);
809 assert_eq!(PValue::I16(-1).to_le_bytes(), &[0xFF, 0xFF]);
810
811 let f32_bytes = PValue::F32(1.0).to_le_bytes();
812 assert_eq!(f32_bytes.len(), 4);
813
814 let f64_bytes = PValue::F64(1.0).to_le_bytes();
815 assert_eq!(f64_bytes.len(), 8);
816 }
817
818 #[test]
819 fn test_f16_special_values() {
820 let nan = f16::NAN;
822 let nan_value = PValue::F16(nan);
823 assert!(nan_value.as_f16().unwrap().is_nan());
824
825 let inf = f16::INFINITY;
827 let inf_value = PValue::F16(inf);
828 assert!(inf_value.as_f16().unwrap().is_infinite());
829
830 assert_eq!(
832 PValue::F16(nan).partial_cmp(&PValue::F16(nan)),
833 Some(Ordering::Equal)
834 );
835 }
836
837 #[test]
838 fn test_coerce_pvalue() {
839 assert_eq!(u32::coerce(PValue::U16(42)).unwrap(), 42u32);
841 assert_eq!(i64::coerce(PValue::I32(-42)).unwrap(), -42i64);
842
843 assert_eq!(f32::coerce(PValue::U32(0x3f800000)).unwrap(), 1.0f32);
845 assert_eq!(
846 f64::coerce(PValue::U64(0x3ff0000000000000)).unwrap(),
847 1.0f64
848 );
849 }
850
851 #[test]
852 fn test_coerce_f16_beyond_u16_max() {
853 assert!(f16::coerce(PValue::U32(u16::MAX as u32)).is_ok());
855 assert_eq!(
856 f16::coerce(PValue::U32(0x3C00)).unwrap(),
857 f16::from_bits(0x3C00) );
859
860 assert!(f16::coerce(PValue::U32((u16::MAX as u32) + 1)).is_err());
862 assert!(f16::coerce(PValue::U32(u32::MAX)).is_err());
863
864 assert!(f16::coerce(PValue::U64(u16::MAX as u64)).is_ok());
866 assert_eq!(
867 f16::coerce(PValue::U64(0x3C00)).unwrap(),
868 f16::from_bits(0x3C00) );
870
871 assert!(f16::coerce(PValue::U64((u16::MAX as u64) + 1)).is_err());
873 assert!(f16::coerce(PValue::U64(u32::MAX as u64)).is_err());
874 assert!(f16::coerce(PValue::U64(u64::MAX)).is_err());
875 }
876
877 #[test]
878 fn test_coerce_f32_beyond_u32_max() {
879 assert!(f32::coerce(PValue::U64(u32::MAX as u64)).is_ok());
881 assert_eq!(
882 f32::coerce(PValue::U64(0x3f800000)).unwrap(),
883 1.0f32 );
885
886 assert!(f32::coerce(PValue::U64((u32::MAX as u64) + 1)).is_err());
888 assert!(f32::coerce(PValue::U64(u64::MAX)).is_err());
889
890 assert!(f32::coerce(PValue::U8(255)).is_ok());
892 assert!(f32::coerce(PValue::U16(u16::MAX)).is_ok());
893 assert!(f32::coerce(PValue::U32(u32::MAX)).is_ok());
894 }
895
896 #[test]
897 fn test_coerce_f64_all_unsigned() {
898 assert!(f64::coerce(PValue::U8(u8::MAX)).is_ok());
900 assert!(f64::coerce(PValue::U16(u16::MAX)).is_ok());
901 assert!(f64::coerce(PValue::U32(u32::MAX)).is_ok());
902 assert!(f64::coerce(PValue::U64(u64::MAX)).is_ok());
903
904 assert_eq!(
906 f64::coerce(PValue::U64(0x3ff0000000000000)).unwrap(),
907 1.0f64 );
909 }
910
911 #[test]
912 fn test_f16_nans_equal() {
913 let nan1 = f16::from_le_bytes([154, 253]);
914 assert!(nan1.is_nan());
915 let nan3 = f16::from_f16(nan1).unwrap();
916 assert_eq!(nan1.to_bits(), nan3.to_bits(),);
917 }
918}