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