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::{
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 match self {
126 PValue::U8(v) => <$T as NumCast>::from(v),
127 PValue::U16(v) => <$T as NumCast>::from(v),
128 PValue::U32(v) => <$T as NumCast>::from(v),
129 PValue::U64(v) => <$T as NumCast>::from(v),
130 PValue::I8(v) => <$T as NumCast>::from(v),
131 PValue::I16(v) => <$T as NumCast>::from(v),
132 PValue::I32(v) => <$T as NumCast>::from(v),
133 PValue::I64(v) => <$T as NumCast>::from(v),
134 PValue::F16(v) => <$T as NumCast>::from(v),
135 PValue::F32(v) => <$T as NumCast>::from(v),
136 PValue::F64(v) => <$T as NumCast>::from(v),
137 }
138 }
139 }
140 };
141}
142
143impl PValue {
144 pub fn zero(ptype: PType) -> PValue {
146 match ptype {
147 PType::U8 => PValue::U8(0),
148 PType::U16 => PValue::U16(0),
149 PType::U32 => PValue::U32(0),
150 PType::U64 => PValue::U64(0),
151 PType::I8 => PValue::I8(0),
152 PType::I16 => PValue::I16(0),
153 PType::I32 => PValue::I32(0),
154 PType::I64 => PValue::I64(0),
155 PType::F16 => PValue::F16(f16::from_f32(0.0)),
156 PType::F32 => PValue::F32(0.0),
157 PType::F64 => PValue::F64(0.0),
158 }
159 }
160
161 pub fn ptype(&self) -> PType {
163 match self {
164 Self::U8(_) => PType::U8,
165 Self::U16(_) => PType::U16,
166 Self::U32(_) => PType::U32,
167 Self::U64(_) => PType::U64,
168 Self::I8(_) => PType::I8,
169 Self::I16(_) => PType::I16,
170 Self::I32(_) => PType::I32,
171 Self::I64(_) => PType::I64,
172 Self::F16(_) => PType::F16,
173 Self::F32(_) => PType::F32,
174 Self::F64(_) => PType::F64,
175 }
176 }
177
178 pub fn is_instance_of(&self, ptype: &PType) -> bool {
180 &self.ptype() == ptype
181 }
182
183 #[inline]
187 pub fn as_primitive<T: NativePType>(&self) -> T {
188 self.as_primitive_opt::<T>().vortex_expect("as_primitive")
189 }
190
191 #[inline]
195 pub fn as_primitive_opt<T: NativePType>(&self) -> Option<T> {
196 match *self {
197 PValue::U8(u) => T::from_u8(u),
198 PValue::U16(u) => T::from_u16(u),
199 PValue::U32(u) => T::from_u32(u),
200 PValue::U64(u) => T::from_u64(u),
201 PValue::I8(i) => T::from_i8(i),
202 PValue::I16(i) => T::from_i16(i),
203 PValue::I32(i) => T::from_i32(i),
204 PValue::I64(i) => T::from_i64(i),
205 PValue::F16(f) => <T as NumCast>::from(f),
206 PValue::F32(f) => T::from_f32(f),
207 PValue::F64(f) => T::from_f64(f),
208 }
209 }
210
211 pub fn reinterpret_cast(&self, ptype: PType) -> Self {
219 if ptype == self.ptype() {
220 return *self;
221 }
222
223 assert_eq!(
224 ptype.byte_width(),
225 self.ptype().byte_width(),
226 "Cannot reinterpret cast between types of different widths"
227 );
228
229 match self {
230 PValue::U8(v) => u8::cast_signed(*v).into(),
231 PValue::U16(v) => match ptype {
232 PType::I16 => u16::cast_signed(*v).into(),
233 PType::F16 => f16::from_bits(*v).into(),
234 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
235 },
236 PValue::U32(v) => match ptype {
237 PType::I32 => u32::cast_signed(*v).into(),
238 PType::F32 => f32::from_bits(*v).into(),
239 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
240 },
241 PValue::U64(v) => match ptype {
242 PType::I64 => u64::cast_signed(*v).into(),
243 PType::F64 => f64::from_bits(*v).into(),
244 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
245 },
246 PValue::I8(v) => i8::cast_unsigned(*v).into(),
247 PValue::I16(v) => match ptype {
248 PType::U16 => i16::cast_unsigned(*v).into(),
249 PType::F16 => f16::from_bits(v.cast_unsigned()).into(),
250 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
251 },
252 PValue::I32(v) => match ptype {
253 PType::U32 => i32::cast_unsigned(*v).into(),
254 PType::F32 => f32::from_bits(i32::cast_unsigned(*v)).into(),
255 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
256 },
257 PValue::I64(v) => match ptype {
258 PType::U64 => i64::cast_unsigned(*v).into(),
259 PType::F64 => f64::from_bits(i64::cast_unsigned(*v)).into(),
260 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
261 },
262 PValue::F16(v) => match ptype {
263 PType::U16 => v.to_bits().into(),
264 PType::I16 => v.to_bits().cast_signed().into(),
265 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
266 },
267 PValue::F32(v) => match ptype {
268 PType::U32 => f32::to_bits(*v).into(),
269 PType::I32 => f32::to_bits(*v).cast_signed().into(),
270 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
271 },
272 PValue::F64(v) => match ptype {
273 PType::U64 => f64::to_bits(*v).into(),
274 PType::I64 => f64::to_bits(*v).cast_signed().into(),
275 _ => unreachable!("Only same width type are allowed to be reinterpreted"),
276 },
277 }
278 }
279
280 as_primitive!(i8, I8);
281 as_primitive!(i16, I16);
282 as_primitive!(i32, I32);
283 as_primitive!(i64, I64);
284 as_primitive!(u8, U8);
285 as_primitive!(u16, U16);
286 as_primitive!(u32, U32);
287 as_primitive!(u64, U64);
288 as_primitive!(f16, F16);
289 as_primitive!(f32, F32);
290 as_primitive!(f64, F64);
291}
292
293macro_rules! int_pvalue {
294 ($T:ty, $PT:tt) => {
295 impl TryFrom<PValue> for $T {
296 type Error = VortexError;
297
298 fn try_from(value: PValue) -> Result<Self, Self::Error> {
299 match value {
300 PValue::U8(v) => <$T as NumCast>::from(v),
301 PValue::U16(v) => <$T as NumCast>::from(v),
302 PValue::U32(v) => <$T as NumCast>::from(v),
303 PValue::U64(v) => <$T as NumCast>::from(v),
304 PValue::I8(v) => <$T as NumCast>::from(v),
305 PValue::I16(v) => <$T as NumCast>::from(v),
306 PValue::I32(v) => <$T as NumCast>::from(v),
307 PValue::I64(v) => <$T as NumCast>::from(v),
308 _ => None,
309 }
310 .ok_or_else(|| {
311 vortex_err!("Cannot read primitive value {:?} as {}", value, PType::$PT)
312 })
313 }
314 }
315 };
316}
317
318macro_rules! float_pvalue {
319 ($T:ty, $PT:tt) => {
320 impl TryFrom<PValue> for $T {
321 type Error = VortexError;
322
323 fn try_from(value: PValue) -> Result<Self, Self::Error> {
324 match value {
325 PValue::U8(u) => <Self as NumCast>::from(u),
326 PValue::U16(u) => <Self as NumCast>::from(u),
327 PValue::U32(u) => <Self as NumCast>::from(u),
328 PValue::U64(u) => <Self as NumCast>::from(u),
329 PValue::I8(i) => <Self as NumCast>::from(i),
330 PValue::I16(i) => <Self as NumCast>::from(i),
331 PValue::I32(i) => <Self as NumCast>::from(i),
332 PValue::I64(i) => <Self as NumCast>::from(i),
333 PValue::F16(f) => <Self as NumCast>::from(f),
334 PValue::F32(f) => <Self as NumCast>::from(f),
335 PValue::F64(f) => <Self as NumCast>::from(f),
336 }
337 .ok_or_else(|| {
338 vortex_err!("Cannot read primitive value {:?} as {}", value, PType::$PT)
339 })
340 }
341 }
342 };
343}
344
345int_pvalue!(u8, U8);
346int_pvalue!(u16, U16);
347int_pvalue!(u32, U32);
348int_pvalue!(u64, U64);
349int_pvalue!(usize, U64);
350int_pvalue!(i8, I8);
351int_pvalue!(i16, I16);
352int_pvalue!(i32, I32);
353int_pvalue!(i64, I64);
354
355float_pvalue!(f16, F16);
356float_pvalue!(f32, F32);
357float_pvalue!(f64, F64);
358
359macro_rules! impl_pvalue {
360 ($T:ty, $PT:tt) => {
361 impl From<$T> for PValue {
362 fn from(value: $T) -> Self {
363 PValue::$PT(value)
364 }
365 }
366 };
367}
368
369impl_pvalue!(u8, U8);
370impl_pvalue!(u16, U16);
371impl_pvalue!(u32, U32);
372impl_pvalue!(u64, U64);
373impl_pvalue!(i8, I8);
374impl_pvalue!(i16, I16);
375impl_pvalue!(i32, I32);
376impl_pvalue!(i64, I64);
377impl_pvalue!(f16, F16);
378impl_pvalue!(f32, F32);
379impl_pvalue!(f64, F64);
380
381impl From<usize> for PValue {
382 #[inline]
383 fn from(value: usize) -> PValue {
384 PValue::U64(value as u64)
385 }
386}
387
388impl Display for PValue {
389 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
390 match self {
391 Self::U8(v) => write!(f, "{v}u8"),
392 Self::U16(v) => write!(f, "{v}u16"),
393 Self::U32(v) => write!(f, "{v}u32"),
394 Self::U64(v) => write!(f, "{v}u64"),
395 Self::I8(v) => write!(f, "{v}i8"),
396 Self::I16(v) => write!(f, "{v}i16"),
397 Self::I32(v) => write!(f, "{v}i32"),
398 Self::I64(v) => write!(f, "{v}i64"),
399 Self::F16(v) => write!(f, "{v}f16"),
400 Self::F32(v) => write!(f, "{v}f32"),
401 Self::F64(v) => write!(f, "{v}f64"),
402 }
403 }
404}
405
406pub(super) trait CoercePValue: Sized {
407 fn coerce(value: PValue) -> VortexResult<Self>;
412}
413
414macro_rules! int_coerce {
415 ($T:ty) => {
416 impl CoercePValue for $T {
417 fn coerce(value: PValue) -> VortexResult<Self> {
418 Self::try_from(value)
419 }
420 }
421 };
422}
423
424int_coerce!(u8);
425int_coerce!(u16);
426int_coerce!(u32);
427int_coerce!(u64);
428int_coerce!(i8);
429int_coerce!(i16);
430int_coerce!(i32);
431int_coerce!(i64);
432
433impl CoercePValue for f16 {
434 #[allow(clippy::cast_possible_truncation)]
435 fn coerce(value: PValue) -> VortexResult<Self> {
436 match value {
447 PValue::U8(u) => Ok(Self::from_bits(u as u16)),
448 PValue::U16(u) => Ok(Self::from_bits(u)),
449 PValue::U32(u) => {
450 vortex_ensure!(
451 u <= u16::MAX as u32,
452 "Cannot coerce U32 value to f16: value out of range"
453 );
454 Ok(Self::from_bits(u as u16))
455 }
456 PValue::U64(u) => {
457 vortex_ensure!(
458 u <= u16::MAX as u64,
459 "Cannot coerce U64 value to f16: value out of range"
460 );
461 Ok(Self::from_bits(u as u16))
462 }
463 PValue::F16(u) => Ok(u),
464 PValue::F32(f) => {
465 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f32 to f16"))
466 }
467 PValue::F64(f) => {
468 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f64 to f16"))
469 }
470 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
471 vortex_bail!("Cannot coerce {value:?} to f16: type not supported for coercion")
472 }
473 }
474 }
475}
476
477impl CoercePValue for f32 {
478 #[allow(clippy::cast_possible_truncation)]
479 fn coerce(value: PValue) -> VortexResult<Self> {
480 match value {
482 PValue::U8(u) => Ok(Self::from_bits(u as u32)),
483 PValue::U16(u) => Ok(Self::from_bits(u as u32)),
484 PValue::U32(u) => Ok(Self::from_bits(u)),
485 PValue::U64(u) => {
486 vortex_ensure!(
487 u <= u32::MAX as u64,
488 "Cannot coerce U64 value to f32: value out of range"
489 );
490 Ok(Self::from_bits(u as u32))
491 }
492 PValue::F16(f) => {
493 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f16 to f32"))
494 }
495 PValue::F32(f) => Ok(f),
496 PValue::F64(f) => {
497 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f64 to f32"))
498 }
499 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
500 vortex_bail!("Unsupported PValue {value:?} type for f32")
501 }
502 }
503 }
504}
505
506impl CoercePValue for f64 {
507 fn coerce(value: PValue) -> VortexResult<Self> {
508 match value {
510 PValue::U8(u) => Ok(Self::from_bits(u as u64)),
511 PValue::U16(u) => Ok(Self::from_bits(u as u64)),
512 PValue::U32(u) => Ok(Self::from_bits(u as u64)),
513 PValue::U64(u) => Ok(Self::from_bits(u)),
514 PValue::F16(f) => {
515 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f16 to f64"))
516 }
517 PValue::F32(f) => {
518 <Self as NumCast>::from(f).ok_or_else(|| vortex_err!("Cannot convert f32 to f64"))
519 }
520 PValue::F64(f) => Ok(f),
521 PValue::I8(_) | PValue::I16(_) | PValue::I32(_) | PValue::I64(_) => {
522 vortex_bail!("Unsupported PValue {value:?} type for f64")
523 }
524 }
525 }
526}
527
528#[cfg(test)]
529#[allow(clippy::disallowed_types)]
530mod test {
531 use std::cmp::Ordering;
532 use std::collections::HashSet;
533
534 use vortex_dtype::half::f16;
535 use vortex_dtype::{PType, ToBytes};
536
537 use crate::PValue;
538 use crate::pvalue::CoercePValue;
539
540 #[test]
541 pub fn test_is_instance_of() {
542 assert!(PValue::U8(10).is_instance_of(&PType::U8));
543 assert!(!PValue::U8(10).is_instance_of(&PType::U16));
544 assert!(!PValue::U8(10).is_instance_of(&PType::I8));
545 assert!(!PValue::U8(10).is_instance_of(&PType::F16));
546
547 assert!(PValue::I8(10).is_instance_of(&PType::I8));
548 assert!(!PValue::I8(10).is_instance_of(&PType::I16));
549 assert!(!PValue::I8(10).is_instance_of(&PType::U8));
550 assert!(!PValue::I8(10).is_instance_of(&PType::F16));
551
552 assert!(PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::F16));
553 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::F32));
554 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::U16));
555 assert!(!PValue::F16(f16::from_f32(10.0)).is_instance_of(&PType::I16));
556 }
557
558 #[test]
559 fn test_compare_different_types() {
560 assert_eq!(
561 PValue::I8(4).partial_cmp(&PValue::I8(5)),
562 Some(Ordering::Less)
563 );
564 assert_eq!(
565 PValue::I8(4).partial_cmp(&PValue::I64(5)),
566 Some(Ordering::Less)
567 );
568 }
569
570 #[test]
571 fn test_hash() {
572 let set = HashSet::from([
573 PValue::U8(1),
574 PValue::U16(1),
575 PValue::U32(1),
576 PValue::U64(1),
577 PValue::I8(1),
578 PValue::I16(1),
579 PValue::I32(1),
580 PValue::I64(1),
581 PValue::I8(-1),
582 PValue::I16(-1),
583 PValue::I32(-1),
584 PValue::I64(-1),
585 ]);
586 assert_eq!(set.len(), 2);
587 }
588
589 #[test]
590 fn test_zero_values() {
591 assert_eq!(PValue::zero(PType::U8), PValue::U8(0));
592 assert_eq!(PValue::zero(PType::U16), PValue::U16(0));
593 assert_eq!(PValue::zero(PType::U32), PValue::U32(0));
594 assert_eq!(PValue::zero(PType::U64), PValue::U64(0));
595 assert_eq!(PValue::zero(PType::I8), PValue::I8(0));
596 assert_eq!(PValue::zero(PType::I16), PValue::I16(0));
597 assert_eq!(PValue::zero(PType::I32), PValue::I32(0));
598 assert_eq!(PValue::zero(PType::I64), PValue::I64(0));
599 assert_eq!(PValue::zero(PType::F16), PValue::F16(f16::from_f32(0.0)));
600 assert_eq!(PValue::zero(PType::F32), PValue::F32(0.0));
601 assert_eq!(PValue::zero(PType::F64), PValue::F64(0.0));
602 }
603
604 #[test]
605 fn test_ptype() {
606 assert_eq!(PValue::U8(10).ptype(), PType::U8);
607 assert_eq!(PValue::U16(10).ptype(), PType::U16);
608 assert_eq!(PValue::U32(10).ptype(), PType::U32);
609 assert_eq!(PValue::U64(10).ptype(), PType::U64);
610 assert_eq!(PValue::I8(10).ptype(), PType::I8);
611 assert_eq!(PValue::I16(10).ptype(), PType::I16);
612 assert_eq!(PValue::I32(10).ptype(), PType::I32);
613 assert_eq!(PValue::I64(10).ptype(), PType::I64);
614 assert_eq!(PValue::F16(f16::from_f32(10.0)).ptype(), PType::F16);
615 assert_eq!(PValue::F32(10.0).ptype(), PType::F32);
616 assert_eq!(PValue::F64(10.0).ptype(), PType::F64);
617 }
618
619 #[test]
620 fn test_reinterpret_cast_same_type() {
621 let value = PValue::U32(42);
622 assert_eq!(value.reinterpret_cast(PType::U32), value);
623 }
624
625 #[test]
626 fn test_reinterpret_cast_u8_i8() {
627 let value = PValue::U8(255);
628 let casted = value.reinterpret_cast(PType::I8);
629 assert_eq!(casted, PValue::I8(-1));
630 }
631
632 #[test]
633 fn test_reinterpret_cast_u16_types() {
634 let value = PValue::U16(12345);
635
636 let as_i16 = value.reinterpret_cast(PType::I16);
638 assert_eq!(as_i16, PValue::I16(12345));
639
640 let as_f16 = value.reinterpret_cast(PType::F16);
642 assert_eq!(as_f16, PValue::F16(f16::from_bits(12345)));
643 }
644
645 #[test]
646 fn test_reinterpret_cast_u32_types() {
647 let value = PValue::U32(0x3f800000); let as_f32 = value.reinterpret_cast(PType::F32);
651 assert_eq!(as_f32, PValue::F32(1.0));
652
653 let value2 = PValue::U32(0x80000000);
655 let as_i32 = value2.reinterpret_cast(PType::I32);
656 assert_eq!(as_i32, PValue::I32(i32::MIN));
657 }
658
659 #[test]
660 fn test_reinterpret_cast_f32_to_u32() {
661 let value = PValue::F32(1.0);
662 let as_u32 = value.reinterpret_cast(PType::U32);
663 assert_eq!(as_u32, PValue::U32(0x3f800000));
664 }
665
666 #[test]
667 fn test_reinterpret_cast_f64_to_i64() {
668 let value = PValue::F64(1.0);
669 let as_i64 = value.reinterpret_cast(PType::I64);
670 assert_eq!(as_i64, PValue::I64(0x3ff0000000000000_i64));
671 }
672
673 #[test]
674 #[should_panic(expected = "Cannot reinterpret cast between types of different widths")]
675 fn test_reinterpret_cast_different_widths() {
676 let value = PValue::U8(42);
677 let _ = value.reinterpret_cast(PType::U16);
678 }
679
680 #[test]
681 fn test_as_primitive_conversions() {
682 assert_eq!(PValue::U8(42).as_u8(), Some(42));
684 assert_eq!(PValue::I8(42).as_u8(), Some(42));
685 assert_eq!(PValue::U16(255).as_u8(), Some(255));
686 assert_eq!(PValue::U16(256).as_u8(), None); assert_eq!(PValue::I32(42).as_i32(), Some(42));
690 assert_eq!(PValue::U32(42).as_i32(), Some(42));
691 assert_eq!(PValue::I64(42).as_i32(), Some(42));
692 assert_eq!(PValue::U64(u64::MAX).as_i32(), None); assert_eq!(PValue::F64(42.5).as_f64(), Some(42.5));
696 assert_eq!(PValue::F32(42.5).as_f64(), Some(42.5f64));
697 assert_eq!(PValue::I32(42).as_f64(), Some(42.0));
698 }
699
700 #[test]
701 fn test_try_from_pvalue_integers() {
702 assert_eq!(u8::try_from(PValue::U8(42)).unwrap(), 42);
704 assert_eq!(u8::try_from(PValue::I8(42)).unwrap(), 42);
705 assert!(u8::try_from(PValue::I8(-1)).is_err());
706 assert!(u8::try_from(PValue::U16(256)).is_err());
707
708 assert_eq!(i32::try_from(PValue::I32(42)).unwrap(), 42);
710 assert_eq!(i32::try_from(PValue::I16(-100)).unwrap(), -100);
711 assert!(i32::try_from(PValue::U64(u64::MAX)).is_err());
712
713 assert!(i32::try_from(PValue::F32(42.5)).is_err());
715 }
716
717 #[test]
718 fn test_try_from_pvalue_floats() {
719 assert_eq!(f32::try_from(PValue::F32(42.5)).unwrap(), 42.5);
721 assert_eq!(f32::try_from(PValue::I32(42)).unwrap(), 42.0);
722 assert_eq!(f32::try_from(PValue::U8(255)).unwrap(), 255.0);
723
724 assert_eq!(f64::try_from(PValue::F64(42.5)).unwrap(), 42.5);
726 assert_eq!(f64::try_from(PValue::F32(42.5)).unwrap(), 42.5f64);
727 assert_eq!(f64::try_from(PValue::I64(-100)).unwrap(), -100.0);
728 }
729
730 #[test]
731 fn test_from_usize() {
732 let value: PValue = 42usize.into();
733 assert_eq!(value, PValue::U64(42));
734
735 let max_value: PValue = usize::MAX.into();
736 assert_eq!(max_value, PValue::U64(usize::MAX as u64));
737 }
738
739 #[test]
740 fn test_equality_cross_types() {
741 assert_eq!(PValue::U8(42), PValue::U16(42));
743 assert_eq!(PValue::U8(42), PValue::U32(42));
744 assert_eq!(PValue::U8(42), PValue::U64(42));
745 assert_eq!(PValue::I8(42), PValue::I16(42));
746 assert_eq!(PValue::I8(42), PValue::I32(42));
747 assert_eq!(PValue::I8(42), PValue::I64(42));
748
749 assert_eq!(PValue::U8(42), PValue::I8(42));
751 assert_eq!(PValue::U32(42), PValue::I32(42));
752
753 assert_eq!(PValue::F32(42.0), PValue::F32(42.0));
755 assert_eq!(PValue::F64(42.0), PValue::F64(42.0));
756 assert_ne!(PValue::F32(42.0), PValue::F64(42.0)); assert_ne!(PValue::F32(42.0), PValue::I32(42));
760 }
761
762 #[test]
763 fn test_partial_ord_cross_types() {
764 assert_eq!(
766 PValue::U8(10).partial_cmp(&PValue::U16(20)),
767 Some(Ordering::Less)
768 );
769 assert_eq!(
770 PValue::U32(30).partial_cmp(&PValue::U8(20)),
771 Some(Ordering::Greater)
772 );
773
774 assert_eq!(
776 PValue::I8(-10).partial_cmp(&PValue::I64(0)),
777 Some(Ordering::Less)
778 );
779 assert_eq!(
780 PValue::I32(10).partial_cmp(&PValue::I16(10)),
781 Some(Ordering::Equal)
782 );
783
784 assert_eq!(
786 PValue::F32(1.0).partial_cmp(&PValue::F32(2.0)),
787 Some(Ordering::Less)
788 );
789 assert_eq!(
790 PValue::F64(2.0).partial_cmp(&PValue::F64(1.0)),
791 Some(Ordering::Greater)
792 );
793
794 assert_eq!(
796 PValue::U32(42).partial_cmp(&PValue::I32(42)),
797 Some(Ordering::Equal)
798 ); assert_eq!(PValue::F32(42.0).partial_cmp(&PValue::I32(42)), None);
800 assert_eq!(PValue::F32(42.0).partial_cmp(&PValue::F64(42.0)), None);
801 }
802
803 #[test]
804 fn test_to_le_bytes() {
805 assert_eq!(PValue::U8(0x12).to_le_bytes(), &[0x12]);
806 assert_eq!(PValue::U16(0x1234).to_le_bytes(), &[0x34, 0x12]);
807 assert_eq!(
808 PValue::U32(0x12345678).to_le_bytes(),
809 &[0x78, 0x56, 0x34, 0x12]
810 );
811
812 assert_eq!(PValue::I8(-1).to_le_bytes(), &[0xFF]);
813 assert_eq!(PValue::I16(-1).to_le_bytes(), &[0xFF, 0xFF]);
814
815 let f32_bytes = PValue::F32(1.0).to_le_bytes();
816 assert_eq!(f32_bytes.len(), 4);
817
818 let f64_bytes = PValue::F64(1.0).to_le_bytes();
819 assert_eq!(f64_bytes.len(), 8);
820 }
821
822 #[test]
823 fn test_f16_special_values() {
824 let nan = f16::NAN;
826 let nan_value = PValue::F16(nan);
827 assert!(nan_value.as_f16().unwrap().is_nan());
828
829 let inf = f16::INFINITY;
831 let inf_value = PValue::F16(inf);
832 assert!(inf_value.as_f16().unwrap().is_infinite());
833
834 assert_eq!(
836 PValue::F16(nan).partial_cmp(&PValue::F16(nan)),
837 Some(Ordering::Equal)
838 );
839 }
840
841 #[test]
842 fn test_coerce_pvalue() {
843 assert_eq!(u32::coerce(PValue::U16(42)).unwrap(), 42u32);
845 assert_eq!(i64::coerce(PValue::I32(-42)).unwrap(), -42i64);
846
847 assert_eq!(f32::coerce(PValue::U32(0x3f800000)).unwrap(), 1.0f32);
849 assert_eq!(
850 f64::coerce(PValue::U64(0x3ff0000000000000)).unwrap(),
851 1.0f64
852 );
853 }
854
855 #[test]
856 fn test_coerce_f16_beyond_u16_max() {
857 assert!(f16::coerce(PValue::U32(u16::MAX as u32)).is_ok());
859 assert_eq!(
860 f16::coerce(PValue::U32(0x3C00)).unwrap(),
861 f16::from_bits(0x3C00) );
863
864 assert!(f16::coerce(PValue::U32((u16::MAX as u32) + 1)).is_err());
866 assert!(f16::coerce(PValue::U32(u32::MAX)).is_err());
867
868 assert!(f16::coerce(PValue::U64(u16::MAX as u64)).is_ok());
870 assert_eq!(
871 f16::coerce(PValue::U64(0x3C00)).unwrap(),
872 f16::from_bits(0x3C00) );
874
875 assert!(f16::coerce(PValue::U64((u16::MAX as u64) + 1)).is_err());
877 assert!(f16::coerce(PValue::U64(u32::MAX as u64)).is_err());
878 assert!(f16::coerce(PValue::U64(u64::MAX)).is_err());
879 }
880
881 #[test]
882 fn test_coerce_f32_beyond_u32_max() {
883 assert!(f32::coerce(PValue::U64(u32::MAX as u64)).is_ok());
885 assert_eq!(
886 f32::coerce(PValue::U64(0x3f800000)).unwrap(),
887 1.0f32 );
889
890 assert!(f32::coerce(PValue::U64((u32::MAX as u64) + 1)).is_err());
892 assert!(f32::coerce(PValue::U64(u64::MAX)).is_err());
893
894 assert!(f32::coerce(PValue::U8(255)).is_ok());
896 assert!(f32::coerce(PValue::U16(u16::MAX)).is_ok());
897 assert!(f32::coerce(PValue::U32(u32::MAX)).is_ok());
898 }
899
900 #[test]
901 fn test_coerce_f64_all_unsigned() {
902 assert!(f64::coerce(PValue::U8(u8::MAX)).is_ok());
904 assert!(f64::coerce(PValue::U16(u16::MAX)).is_ok());
905 assert!(f64::coerce(PValue::U32(u32::MAX)).is_ok());
906 assert!(f64::coerce(PValue::U64(u64::MAX)).is_ok());
907
908 assert_eq!(
910 f64::coerce(PValue::U64(0x3ff0000000000000)).unwrap(),
911 1.0f64 );
913 }
914}