1#![no_std]
2
3use core::fmt;
22use core::mem::align_of;
23use core::mem::size_of;
24
25use bytemuck::Pod;
26use bytemuck::Zeroable;
27
28#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)]
30#[repr(transparent)]
31pub struct PodBool(pub u8);
32
33impl PodBool {
34 pub const fn from_bool(b: bool) -> Self {
35 Self(if b { 1 } else { 0 })
36 }
37
38 pub const fn is_canonical(&self) -> bool {
46 self.0 == 0 || self.0 == 1
47 }
48}
49
50impl From<bool> for PodBool {
51 fn from(b: bool) -> Self {
52 Self::from_bool(b)
53 }
54}
55
56impl From<&bool> for PodBool {
57 fn from(b: &bool) -> Self {
58 Self(u8::from(*b))
59 }
60}
61
62impl From<&PodBool> for bool {
63 fn from(b: &PodBool) -> Self {
64 b.0 != 0
65 }
66}
67
68impl From<PodBool> for bool {
69 fn from(b: PodBool) -> Self {
70 b.0 != 0
71 }
72}
73
74impl core::ops::Not for PodBool {
75 type Output = Self;
76
77 #[inline]
78 fn not(self) -> Self {
79 Self::from_bool(!bool::from(self))
80 }
81}
82
83impl fmt::Display for PodBool {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 bool::from(*self).fmt(f)
86 }
87}
88
89#[macro_export]
97macro_rules! impl_int_conversion {
98 ($P:ty, $I:ty) => {
99 impl $P {
100 pub const fn from_primitive(n: $I) -> Self {
101 Self(n.to_le_bytes())
102 }
103
104 #[inline]
107 pub const fn get(&self) -> $I {
108 <$I>::from_le_bytes(self.0)
109 }
110 }
111
112 impl From<$I> for $P {
113 fn from(n: $I) -> Self {
114 Self::from_primitive(n)
115 }
116 }
117
118 impl From<$P> for $I {
119 fn from(pod: $P) -> Self {
120 pod.get()
121 }
122 }
123 };
124}
125
126macro_rules! impl_pod_common {
129 ($name:ident, $native:ty, $size:expr) => {
130 impl $name {
131 pub const MAX: Self = Self(<$native>::MAX.to_le_bytes());
133 pub const MIN: Self = Self(<$native>::MIN.to_le_bytes());
135 pub const ZERO: Self = Self([0u8; $size]);
137
138 #[inline]
140 #[must_use]
141 pub fn is_zero(&self) -> bool {
142 self.0 == [0u8; $size]
143 }
144
145 #[inline]
147 #[must_use]
148 pub fn checked_add(self, rhs: impl Into<$name>) -> Option<Self> {
149 self.get().checked_add(rhs.into().get()).map(Self::from)
150 }
151
152 #[inline]
154 #[must_use]
155 pub fn checked_sub(self, rhs: impl Into<$name>) -> Option<Self> {
156 self.get().checked_sub(rhs.into().get()).map(Self::from)
157 }
158
159 #[inline]
161 #[must_use]
162 pub fn checked_mul(self, rhs: impl Into<$name>) -> Option<Self> {
163 self.get().checked_mul(rhs.into().get()).map(Self::from)
164 }
165
166 #[inline]
168 #[must_use]
169 pub fn checked_div(self, rhs: impl Into<$name>) -> Option<Self> {
170 self.get().checked_div(rhs.into().get()).map(Self::from)
171 }
172
173 #[inline]
176 #[must_use]
177 pub fn saturating_add(self, rhs: impl Into<$name>) -> Self {
178 Self::from(self.get().saturating_add(rhs.into().get()))
179 }
180
181 #[inline]
184 #[must_use]
185 pub fn saturating_sub(self, rhs: impl Into<$name>) -> Self {
186 Self::from(self.get().saturating_sub(rhs.into().get()))
187 }
188
189 #[inline]
192 #[must_use]
193 pub fn saturating_mul(self, rhs: impl Into<$name>) -> Self {
194 Self::from(self.get().saturating_mul(rhs.into().get()))
195 }
196 }
197
198 impl PartialOrd for $name {
199 #[inline]
200 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
201 Some(self.cmp(other))
202 }
203 }
204
205 impl Ord for $name {
206 #[inline]
207 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
208 self.get().cmp(&other.get())
209 }
210 }
211
212 impl PartialEq<$native> for $name {
213 #[inline]
214 fn eq(&self, other: &$native) -> bool {
215 self.get() == *other
216 }
217 }
218
219 impl PartialOrd<$native> for $name {
220 #[inline]
221 fn partial_cmp(&self, other: &$native) -> Option<core::cmp::Ordering> {
222 self.get().partial_cmp(other)
223 }
224 }
225
226 impl fmt::Display for $name {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 self.get().fmt(f)
229 }
230 }
231 };
232}
233
234macro_rules! impl_pod_arithmetic {
239 ($name:ident, $native:ty) => {
240 impl core::ops::Add<$native> for $name {
243 type Output = Self;
244
245 #[inline]
246 fn add(self, rhs: $native) -> Self {
247 #[cfg(debug_assertions)]
248 {
249 Self::from(
250 self.get()
251 .checked_add(rhs)
252 .unwrap_or_else(|| panic!("attempt to add with overflow")),
253 )
254 }
255 #[cfg(not(debug_assertions))]
256 {
257 Self::from(self.get().wrapping_add(rhs))
258 }
259 }
260 }
261
262 impl core::ops::Sub<$native> for $name {
263 type Output = Self;
264
265 #[inline]
266 fn sub(self, rhs: $native) -> Self {
267 #[cfg(debug_assertions)]
268 {
269 Self::from(
270 self.get()
271 .checked_sub(rhs)
272 .unwrap_or_else(|| panic!("attempt to subtract with overflow")),
273 )
274 }
275 #[cfg(not(debug_assertions))]
276 {
277 Self::from(self.get().wrapping_sub(rhs))
278 }
279 }
280 }
281
282 impl core::ops::Mul<$native> for $name {
283 type Output = Self;
284
285 #[inline]
286 fn mul(self, rhs: $native) -> Self {
287 #[cfg(debug_assertions)]
288 {
289 Self::from(
290 self.get()
291 .checked_mul(rhs)
292 .unwrap_or_else(|| panic!("attempt to multiply with overflow")),
293 )
294 }
295 #[cfg(not(debug_assertions))]
296 {
297 Self::from(self.get().wrapping_mul(rhs))
298 }
299 }
300 }
301
302 impl core::ops::Div<$native> for $name {
303 type Output = Self;
304
305 #[inline]
306 fn div(self, rhs: $native) -> Self {
307 Self::from(self.get() / rhs)
308 }
309 }
310
311 impl core::ops::Rem<$native> for $name {
312 type Output = Self;
313
314 #[inline]
315 fn rem(self, rhs: $native) -> Self {
316 Self::from(self.get() % rhs)
317 }
318 }
319
320 impl core::ops::Add for $name {
323 type Output = Self;
324
325 #[inline]
326 fn add(self, rhs: Self) -> Self {
327 self + rhs.get()
328 }
329 }
330
331 impl core::ops::Sub for $name {
332 type Output = Self;
333
334 #[inline]
335 fn sub(self, rhs: Self) -> Self {
336 self - rhs.get()
337 }
338 }
339
340 impl core::ops::Mul for $name {
341 type Output = Self;
342
343 #[inline]
344 fn mul(self, rhs: Self) -> Self {
345 self * rhs.get()
346 }
347 }
348
349 impl core::ops::Div for $name {
350 type Output = Self;
351
352 #[inline]
353 fn div(self, rhs: Self) -> Self {
354 self / rhs.get()
355 }
356 }
357
358 impl core::ops::Rem for $name {
359 type Output = Self;
360
361 #[inline]
362 fn rem(self, rhs: Self) -> Self {
363 self % rhs.get()
364 }
365 }
366
367 impl core::ops::AddAssign<$native> for $name {
370 #[inline]
371 fn add_assign(&mut self, rhs: $native) {
372 *self = *self + rhs;
373 }
374 }
375
376 impl core::ops::SubAssign<$native> for $name {
377 #[inline]
378 fn sub_assign(&mut self, rhs: $native) {
379 *self = *self - rhs;
380 }
381 }
382
383 impl core::ops::MulAssign<$native> for $name {
384 #[inline]
385 fn mul_assign(&mut self, rhs: $native) {
386 *self = *self * rhs;
387 }
388 }
389
390 impl core::ops::DivAssign<$native> for $name {
391 #[inline]
392 fn div_assign(&mut self, rhs: $native) {
393 *self = *self / rhs;
394 }
395 }
396
397 impl core::ops::RemAssign<$native> for $name {
398 #[inline]
399 fn rem_assign(&mut self, rhs: $native) {
400 *self = *self % rhs;
401 }
402 }
403
404 impl core::ops::AddAssign for $name {
407 #[inline]
408 fn add_assign(&mut self, rhs: Self) {
409 *self = *self + rhs;
410 }
411 }
412
413 impl core::ops::SubAssign for $name {
414 #[inline]
415 fn sub_assign(&mut self, rhs: Self) {
416 *self = *self - rhs;
417 }
418 }
419
420 impl core::ops::MulAssign for $name {
421 #[inline]
422 fn mul_assign(&mut self, rhs: Self) {
423 *self = *self * rhs;
424 }
425 }
426
427 impl core::ops::DivAssign for $name {
428 #[inline]
429 fn div_assign(&mut self, rhs: Self) {
430 *self = *self / rhs;
431 }
432 }
433
434 impl core::ops::RemAssign for $name {
435 #[inline]
436 fn rem_assign(&mut self, rhs: Self) {
437 *self = *self % rhs;
438 }
439 }
440
441 impl core::ops::BitAnd<$native> for $name {
444 type Output = Self;
445
446 #[inline]
447 fn bitand(self, rhs: $native) -> Self {
448 Self::from(self.get() & rhs)
449 }
450 }
451
452 impl core::ops::BitOr<$native> for $name {
453 type Output = Self;
454
455 #[inline]
456 fn bitor(self, rhs: $native) -> Self {
457 Self::from(self.get() | rhs)
458 }
459 }
460
461 impl core::ops::BitXor<$native> for $name {
462 type Output = Self;
463
464 #[inline]
465 fn bitxor(self, rhs: $native) -> Self {
466 Self::from(self.get() ^ rhs)
467 }
468 }
469
470 impl core::ops::BitAnd for $name {
471 type Output = Self;
472
473 #[inline]
474 fn bitand(self, rhs: Self) -> Self {
475 self & rhs.get()
476 }
477 }
478
479 impl core::ops::BitOr for $name {
480 type Output = Self;
481
482 #[inline]
483 fn bitor(self, rhs: Self) -> Self {
484 self | rhs.get()
485 }
486 }
487
488 impl core::ops::BitXor for $name {
489 type Output = Self;
490
491 #[inline]
492 fn bitxor(self, rhs: Self) -> Self {
493 self ^ rhs.get()
494 }
495 }
496
497 impl core::ops::Shl<u32> for $name {
498 type Output = Self;
499
500 #[inline]
501 fn shl(self, rhs: u32) -> Self {
502 Self::from(self.get() << rhs)
503 }
504 }
505
506 impl core::ops::Shr<u32> for $name {
507 type Output = Self;
508
509 #[inline]
510 fn shr(self, rhs: u32) -> Self {
511 Self::from(self.get() >> rhs)
512 }
513 }
514
515 impl core::ops::Not for $name {
516 type Output = Self;
517
518 #[inline]
519 fn not(self) -> Self {
520 Self::from(!self.get())
521 }
522 }
523
524 impl core::ops::BitAndAssign<$native> for $name {
527 #[inline]
528 fn bitand_assign(&mut self, rhs: $native) {
529 *self = *self & rhs;
530 }
531 }
532
533 impl core::ops::BitOrAssign<$native> for $name {
534 #[inline]
535 fn bitor_assign(&mut self, rhs: $native) {
536 *self = *self | rhs;
537 }
538 }
539
540 impl core::ops::BitXorAssign<$native> for $name {
541 #[inline]
542 fn bitxor_assign(&mut self, rhs: $native) {
543 *self = *self ^ rhs;
544 }
545 }
546
547 impl core::ops::BitAndAssign for $name {
550 #[inline]
551 fn bitand_assign(&mut self, rhs: Self) {
552 *self = *self & rhs;
553 }
554 }
555
556 impl core::ops::BitOrAssign for $name {
557 #[inline]
558 fn bitor_assign(&mut self, rhs: Self) {
559 *self = *self | rhs;
560 }
561 }
562
563 impl core::ops::BitXorAssign for $name {
564 #[inline]
565 fn bitxor_assign(&mut self, rhs: Self) {
566 *self = *self ^ rhs;
567 }
568 }
569
570 impl core::ops::ShlAssign<u32> for $name {
571 #[inline]
572 fn shl_assign(&mut self, rhs: u32) {
573 *self = *self << rhs;
574 }
575 }
576
577 impl core::ops::ShrAssign<u32> for $name {
578 #[inline]
579 fn shr_assign(&mut self, rhs: u32) {
580 *self = *self >> rhs;
581 }
582 }
583 };
584}
585
586macro_rules! impl_pod_neg {
588 ($name:ident, $native:ty) => {
589 impl core::ops::Neg for $name {
590 type Output = Self;
591
592 #[inline]
593 fn neg(self) -> Self {
594 #[cfg(debug_assertions)]
595 {
596 Self::from(
597 self.get()
598 .checked_neg()
599 .unwrap_or_else(|| panic!("attempt to negate with overflow")),
600 )
601 }
602 #[cfg(not(debug_assertions))]
603 {
604 Self::from(self.get().wrapping_neg())
605 }
606 }
607 }
608 };
609}
610
611macro_rules! define_pod_unsigned {
613 ($name:ident, $native:ty, $size:expr, $doc:expr) => {
614 #[doc = $doc]
615 #[derive(Clone, Copy, Default, PartialEq, Eq, Pod, Zeroable)]
616 #[repr(transparent)]
617 pub struct $name(pub [u8; $size]);
618
619 impl_int_conversion!($name, $native);
620 impl_pod_common!($name, $native, $size);
621 impl_pod_arithmetic!($name, $native);
622
623 impl fmt::Debug for $name {
624 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625 write!(f, "{}({})", stringify!($name), self.get())
626 }
627 }
628 };
629}
630
631macro_rules! define_pod_signed {
633 ($name:ident, $native:ty, $size:expr, $doc:expr) => {
634 #[doc = $doc]
635 #[derive(Clone, Copy, Default, PartialEq, Eq, Pod, Zeroable)]
636 #[repr(transparent)]
637 pub struct $name(pub [u8; $size]);
638
639 impl_int_conversion!($name, $native);
640 impl_pod_common!($name, $native, $size);
641 impl_pod_arithmetic!($name, $native);
642 impl_pod_neg!($name, $native);
643
644 impl fmt::Debug for $name {
645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
646 write!(f, "{}({})", stringify!($name), self.get())
647 }
648 }
649 };
650}
651
652define_pod_unsigned!(
653 PodU16,
654 u16,
655 2,
656 "An alignment-1 wrapper around `u16` stored as `[u8; 2]`.\n\nEnables safe zero-copy access \
657 inside `#[repr(C)]` account structs."
658);
659
660define_pod_signed!(
661 PodI16,
662 i16,
663 2,
664 "An alignment-1 wrapper around `i16` stored as `[u8; 2]`.\n\nEnables safe zero-copy access \
665 inside `#[repr(C)]` account structs."
666);
667
668define_pod_unsigned!(
669 PodU32,
670 u32,
671 4,
672 "An alignment-1 wrapper around `u32` stored as `[u8; 4]`.\n\nEnables safe zero-copy access \
673 inside `#[repr(C)]` account structs."
674);
675
676define_pod_signed!(
677 PodI32,
678 i32,
679 4,
680 "An alignment-1 wrapper around `i32` stored as `[u8; 4]`.\n\nEnables safe zero-copy access \
681 inside `#[repr(C)]` account structs."
682);
683
684define_pod_unsigned!(
685 PodU64,
686 u64,
687 8,
688 "An alignment-1 wrapper around `u64` stored as `[u8; 8]`.\n\nEnables safe zero-copy access \
689 inside `#[repr(C)]` account structs."
690);
691
692define_pod_signed!(
693 PodI64,
694 i64,
695 8,
696 "An alignment-1 wrapper around `i64` stored as `[u8; 8]`.\n\nEnables safe zero-copy access \
697 inside `#[repr(C)]` account structs."
698);
699
700define_pod_unsigned!(
701 PodU128,
702 u128,
703 16,
704 "An alignment-1 wrapper around `u128` stored as `[u8; 16]`.\n\nEnables safe zero-copy access \
705 inside `#[repr(C)]` account structs."
706);
707
708define_pod_signed!(
709 PodI128,
710 i128,
711 16,
712 "An alignment-1 wrapper around `i128` stored as `[u8; 16]`.\n\nEnables safe zero-copy access \
713 inside `#[repr(C)]` account structs."
714);
715
716const _: () = assert!(align_of::<PodU16>() == 1);
720const _: () = assert!(size_of::<PodU16>() == 2);
721const _: () = assert!(align_of::<PodI16>() == 1);
722const _: () = assert!(size_of::<PodI16>() == 2);
723const _: () = assert!(align_of::<PodU32>() == 1);
724const _: () = assert!(size_of::<PodU32>() == 4);
725const _: () = assert!(align_of::<PodI32>() == 1);
726const _: () = assert!(size_of::<PodI32>() == 4);
727const _: () = assert!(align_of::<PodU64>() == 1);
728const _: () = assert!(size_of::<PodU64>() == 8);
729const _: () = assert!(align_of::<PodI64>() == 1);
730const _: () = assert!(size_of::<PodI64>() == 8);
731const _: () = assert!(align_of::<PodU128>() == 1);
732const _: () = assert!(size_of::<PodU128>() == 16);
733const _: () = assert!(align_of::<PodI128>() == 1);
734const _: () = assert!(size_of::<PodI128>() == 16);
735const _: () = assert!(align_of::<PodBool>() == 1);
736const _: () = assert!(size_of::<PodBool>() == 1);
737
738#[cfg(test)]
739extern crate std;
740
741#[cfg(test)]
742mod tests {
743 use bytemuck::try_from_bytes;
744
745 use super::*;
746
747 #[test]
752 fn pod_bool_roundtrip() {
753 for i in 0..=u8::MAX {
754 let value = *try_from_bytes::<PodBool>(&[i]).unwrap();
755 assert_eq!(i != 0, bool::from(value));
756 }
757 }
758
759 #[test]
763 fn pod_bool_non_canonical_equality_mismatch() {
764 let canonical_true = PodBool::from_bool(true);
765 let non_canonical_true = *try_from_bytes::<PodBool>(&[2]).unwrap();
766
767 assert!(bool::from(canonical_true));
769 assert!(bool::from(non_canonical_true));
770
771 assert_ne!(canonical_true, non_canonical_true);
773
774 assert!(canonical_true.is_canonical());
776 assert!(!non_canonical_true.is_canonical());
777 }
778
779 #[test]
780 fn pod_bool_is_canonical_boundary_values() {
781 assert!(PodBool(0).is_canonical());
782 assert!(PodBool(1).is_canonical());
783 assert!(!PodBool(2).is_canonical());
784 assert!(!PodBool(127).is_canonical());
785 assert!(!PodBool(255).is_canonical());
786 }
787
788 #[test]
789 fn pod_bool_from_bool_produces_canonical() {
790 assert!(PodBool::from_bool(false).is_canonical());
791 assert!(PodBool::from_bool(true).is_canonical());
792 assert!(PodBool::from(false).is_canonical());
793 assert!(PodBool::from(true).is_canonical());
794 }
795
796 #[test]
797 fn pod_bool_from_ref() {
798 let t = true;
799 let f = false;
800 assert_eq!(PodBool::from(&t), PodBool(1));
801 assert_eq!(PodBool::from(&f), PodBool(0));
802 }
803
804 #[test]
805 fn pod_bool_from_ref_roundtrip() {
806 let pod = PodBool(1);
807 assert!(bool::from(&pod));
808 let pod = PodBool(0);
809 assert!(!bool::from(&pod));
810 }
811
812 #[test]
813 fn pod_bool_default_is_false() {
814 let default = PodBool::default();
815 assert_eq!(default.0, 0);
816 assert!(!bool::from(default));
817 assert!(default.is_canonical());
818 }
819
820 #[test]
821 fn pod_bool_not() {
822 assert_eq!(!PodBool::from_bool(true), PodBool::from_bool(false));
823 assert_eq!(!PodBool::from_bool(false), PodBool::from_bool(true));
824 assert_eq!(!PodBool(42), PodBool::from_bool(false));
826 }
827
828 #[test]
829 fn pod_bool_display() {
830 assert_eq!(std::format!("{}", PodBool::from_bool(true)), "true");
831 assert_eq!(std::format!("{}", PodBool::from_bool(false)), "false");
832 }
833
834 #[test]
839 fn pod_u16_roundtrip() {
840 assert_eq!(1u16, u16::from(PodU16::from_primitive(1)));
841 }
842
843 #[test]
844 fn pod_i16_roundtrip() {
845 assert_eq!(-1i16, i16::from(PodI16::from_primitive(-1)));
846 }
847
848 #[test]
849 fn pod_u32_roundtrip() {
850 assert_eq!(7u32, u32::from(PodU32::from_primitive(7)));
851 }
852
853 #[test]
854 fn pod_i32_roundtrip() {
855 assert_eq!(-7i32, i32::from(PodI32::from_primitive(-7)));
856 }
857
858 #[test]
859 fn pod_u64_roundtrip() {
860 assert_eq!(9u64, u64::from(PodU64::from_primitive(9)));
861 }
862
863 #[test]
864 fn pod_i64_roundtrip() {
865 assert_eq!(-9i64, i64::from(PodI64::from_primitive(-9)));
866 }
867
868 #[test]
869 fn pod_u128_roundtrip() {
870 assert_eq!(11u128, u128::from(PodU128::from_primitive(11)));
871 }
872
873 #[test]
874 fn pod_i128_roundtrip() {
875 assert_eq!(-11i128, i128::from(PodI128::from_primitive(-11)));
876 }
877
878 #[test]
883 fn pod_u16_boundary_values() {
884 assert_eq!(0u16, u16::from(PodU16::from_primitive(0)));
885 assert_eq!(u16::MAX, u16::from(PodU16::from_primitive(u16::MAX)));
886 }
887
888 #[test]
889 fn pod_i16_boundary_values() {
890 assert_eq!(i16::MIN, i16::from(PodI16::from_primitive(i16::MIN)));
891 assert_eq!(i16::MAX, i16::from(PodI16::from_primitive(i16::MAX)));
892 assert_eq!(0i16, i16::from(PodI16::from_primitive(0)));
893 }
894
895 #[test]
896 fn pod_u32_boundary_values() {
897 assert_eq!(0u32, u32::from(PodU32::from_primitive(0)));
898 assert_eq!(u32::MAX, u32::from(PodU32::from_primitive(u32::MAX)));
899 }
900
901 #[test]
902 fn pod_i32_boundary_values() {
903 assert_eq!(i32::MIN, i32::from(PodI32::from_primitive(i32::MIN)));
904 assert_eq!(i32::MAX, i32::from(PodI32::from_primitive(i32::MAX)));
905 }
906
907 #[test]
908 fn pod_u64_boundary_values() {
909 assert_eq!(0u64, u64::from(PodU64::from_primitive(0)));
910 assert_eq!(u64::MAX, u64::from(PodU64::from_primitive(u64::MAX)));
911 }
912
913 #[test]
914 fn pod_i64_boundary_values() {
915 assert_eq!(i64::MIN, i64::from(PodI64::from_primitive(i64::MIN)));
916 assert_eq!(i64::MAX, i64::from(PodI64::from_primitive(i64::MAX)));
917 }
918
919 #[test]
920 fn pod_u128_boundary_values() {
921 assert_eq!(0u128, u128::from(PodU128::from_primitive(0)));
922 assert_eq!(u128::MAX, u128::from(PodU128::from_primitive(u128::MAX)));
923 }
924
925 #[test]
926 fn pod_i128_boundary_values() {
927 assert_eq!(i128::MIN, i128::from(PodI128::from_primitive(i128::MIN)));
928 assert_eq!(i128::MAX, i128::from(PodI128::from_primitive(i128::MAX)));
929 }
930
931 #[test]
934 fn pod_types_use_little_endian_byte_order() {
935 let u16_val = PodU16::from_primitive(0x0102);
936 assert_eq!(u16_val.0, [0x02, 0x01]);
937
938 let u32_val = PodU32::from_primitive(0x01020304);
939 assert_eq!(u32_val.0, [0x04, 0x03, 0x02, 0x01]);
940
941 let u64_val = PodU64::from_primitive(0x0102030405060708);
942 assert_eq!(u64_val.0, [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]);
943 }
944
945 #[test]
948 fn pod_types_bytemuck_from_bytes() {
949 let bytes_u16 = [0x39, 0x05]; let val = try_from_bytes::<PodU16>(&bytes_u16).unwrap();
951 assert_eq!(u16::from(*val), 1337);
952
953 let bytes_u32 = [0xEF, 0xBE, 0xAD, 0xDE]; let val = try_from_bytes::<PodU32>(&bytes_u32).unwrap();
955 assert_eq!(u32::from(*val), 0xDEAD_BEEF);
956
957 let bytes_i16 = [0xFF, 0xFF]; let val = try_from_bytes::<PodI16>(&bytes_i16).unwrap();
959 assert_eq!(i16::from(*val), -1);
960 }
961
962 #[test]
963 fn pod_default_is_zero() {
964 assert_eq!(u16::from(PodU16::default()), 0);
965 assert_eq!(i16::from(PodI16::default()), 0);
966 assert_eq!(u32::from(PodU32::default()), 0);
967 assert_eq!(i32::from(PodI32::default()), 0);
968 assert_eq!(u64::from(PodU64::default()), 0);
969 assert_eq!(i64::from(PodI64::default()), 0);
970 assert_eq!(u128::from(PodU128::default()), 0);
971 assert_eq!(i128::from(PodI128::default()), 0);
972 }
973
974 #[test]
979 fn pod_constants_zero() {
980 assert!(PodU16::ZERO.is_zero());
981 assert!(PodU32::ZERO.is_zero());
982 assert!(PodU64::ZERO.is_zero());
983 assert!(PodU128::ZERO.is_zero());
984 assert!(PodI16::ZERO.is_zero());
985 assert!(PodI32::ZERO.is_zero());
986 assert!(PodI64::ZERO.is_zero());
987 assert!(PodI128::ZERO.is_zero());
988 }
989
990 #[test]
991 fn pod_constants_min_max() {
992 assert_eq!(PodU16::MIN.get(), u16::MIN);
993 assert_eq!(PodU16::MAX.get(), u16::MAX);
994 assert_eq!(PodU32::MIN.get(), u32::MIN);
995 assert_eq!(PodU32::MAX.get(), u32::MAX);
996 assert_eq!(PodU64::MIN.get(), u64::MIN);
997 assert_eq!(PodU64::MAX.get(), u64::MAX);
998 assert_eq!(PodU128::MIN.get(), u128::MIN);
999 assert_eq!(PodU128::MAX.get(), u128::MAX);
1000 assert_eq!(PodI16::MIN.get(), i16::MIN);
1001 assert_eq!(PodI16::MAX.get(), i16::MAX);
1002 assert_eq!(PodI32::MIN.get(), i32::MIN);
1003 assert_eq!(PodI32::MAX.get(), i32::MAX);
1004 assert_eq!(PodI64::MIN.get(), i64::MIN);
1005 assert_eq!(PodI64::MAX.get(), i64::MAX);
1006 assert_eq!(PodI128::MIN.get(), i128::MIN);
1007 assert_eq!(PodI128::MAX.get(), i128::MAX);
1008 }
1009
1010 #[test]
1011 fn pod_is_zero_false_for_nonzero() {
1012 assert!(!PodU64::from_primitive(1).is_zero());
1013 assert!(!PodI64::from_primitive(-1).is_zero());
1014 assert!(!PodU128::MAX.is_zero());
1015 }
1016
1017 #[test]
1022 fn pod_add_native() {
1023 assert_eq!((PodU64::from(10u64) + 5u64).get(), 15);
1024 assert_eq!((PodI32::from(10i32) + 5i32).get(), 15);
1025 assert_eq!((PodI32::from(-10i32) + 5i32).get(), -5);
1026 }
1027
1028 #[test]
1029 fn pod_add_pod() {
1030 let a = PodU64::from(10u64);
1031 let b = PodU64::from(20u64);
1032 assert_eq!((a + b).get(), 30);
1033 }
1034
1035 #[test]
1036 fn pod_sub_native() {
1037 assert_eq!((PodU64::from(10u64) - 5u64).get(), 5);
1038 assert_eq!((PodI32::from(-10i32) - 5i32).get(), -15);
1039 }
1040
1041 #[test]
1042 fn pod_sub_pod() {
1043 let a = PodU64::from(20u64);
1044 let b = PodU64::from(5u64);
1045 assert_eq!((a - b).get(), 15);
1046 }
1047
1048 #[test]
1049 fn pod_mul_native() {
1050 assert_eq!((PodU64::from(6u64) * 7u64).get(), 42);
1051 assert_eq!((PodI32::from(-3i32) * 4i32).get(), -12);
1052 }
1053
1054 #[test]
1055 fn pod_mul_pod() {
1056 let a = PodU32::from(6u32);
1057 let b = PodU32::from(7u32);
1058 assert_eq!((a * b).get(), 42);
1059 }
1060
1061 #[test]
1062 fn pod_div_native() {
1063 assert_eq!((PodU64::from(42u64) / 7u64).get(), 6);
1064 assert_eq!((PodI32::from(-12i32) / 4i32).get(), -3);
1065 }
1066
1067 #[test]
1068 fn pod_div_pod() {
1069 let a = PodU64::from(42u64);
1070 let b = PodU64::from(7u64);
1071 assert_eq!((a / b).get(), 6);
1072 }
1073
1074 #[test]
1075 fn pod_rem_native() {
1076 assert_eq!((PodU64::from(10u64) % 3u64).get(), 1);
1077 assert_eq!((PodI32::from(-10i32) % 3i32).get(), -1);
1078 }
1079
1080 #[test]
1081 fn pod_rem_pod() {
1082 let a = PodU64::from(10u64);
1083 let b = PodU64::from(3u64);
1084 assert_eq!((a % b).get(), 1);
1085 }
1086
1087 #[test]
1092 fn pod_add_assign_native() {
1093 let mut v = PodU64::from(10u64);
1094 v += 5u64;
1095 assert_eq!(v.get(), 15);
1096 }
1097
1098 #[test]
1099 fn pod_add_assign_pod() {
1100 let mut v = PodU64::from(10u64);
1101 v += PodU64::from(5u64);
1102 assert_eq!(v.get(), 15);
1103 }
1104
1105 #[test]
1106 fn pod_sub_assign_native() {
1107 let mut v = PodU64::from(10u64);
1108 v -= 3u64;
1109 assert_eq!(v.get(), 7);
1110 }
1111
1112 #[test]
1113 fn pod_sub_assign_pod() {
1114 let mut v = PodU64::from(10u64);
1115 v -= PodU64::from(3u64);
1116 assert_eq!(v.get(), 7);
1117 }
1118
1119 #[test]
1120 fn pod_mul_assign_native() {
1121 let mut v = PodU32::from(5u32);
1122 v *= 4u32;
1123 assert_eq!(v.get(), 20);
1124 }
1125
1126 #[test]
1127 fn pod_mul_assign_pod() {
1128 let mut v = PodU32::from(5u32);
1129 v *= PodU32::from(4u32);
1130 assert_eq!(v.get(), 20);
1131 }
1132
1133 #[test]
1134 fn pod_div_assign_native() {
1135 let mut v = PodU64::from(20u64);
1136 v /= 5u64;
1137 assert_eq!(v.get(), 4);
1138 }
1139
1140 #[test]
1141 fn pod_div_assign_pod() {
1142 let mut v = PodU64::from(20u64);
1143 v /= PodU64::from(5u64);
1144 assert_eq!(v.get(), 4);
1145 }
1146
1147 #[test]
1148 fn pod_rem_assign_native() {
1149 let mut v = PodU64::from(10u64);
1150 v %= 3u64;
1151 assert_eq!(v.get(), 1);
1152 }
1153
1154 #[test]
1155 fn pod_rem_assign_pod() {
1156 let mut v = PodU64::from(10u64);
1157 v %= PodU64::from(3u64);
1158 assert_eq!(v.get(), 1);
1159 }
1160
1161 #[test]
1166 fn pod_bitand_native() {
1167 assert_eq!((PodU32::from(0xFF00u32) & 0x0FF0u32).get(), 0x0F00);
1168 }
1169
1170 #[test]
1171 fn pod_bitand_pod() {
1172 let a = PodU32::from(0xFF00u32);
1173 let b = PodU32::from(0x0FF0u32);
1174 assert_eq!((a & b).get(), 0x0F00);
1175 }
1176
1177 #[test]
1178 fn pod_bitor_native() {
1179 assert_eq!((PodU32::from(0xFF00u32) | 0x00FFu32).get(), 0xFFFF);
1180 }
1181
1182 #[test]
1183 fn pod_bitor_pod() {
1184 let a = PodU32::from(0xFF00u32);
1185 let b = PodU32::from(0x00FFu32);
1186 assert_eq!((a | b).get(), 0xFFFF);
1187 }
1188
1189 #[test]
1190 fn pod_bitxor_native() {
1191 assert_eq!((PodU32::from(0xFFFFu32) ^ 0xFF00u32).get(), 0x00FF);
1192 }
1193
1194 #[test]
1195 fn pod_bitxor_pod() {
1196 let a = PodU32::from(0xFFFFu32);
1197 let b = PodU32::from(0xFF00u32);
1198 assert_eq!((a ^ b).get(), 0x00FF);
1199 }
1200
1201 #[test]
1202 fn pod_shl() {
1203 assert_eq!((PodU32::from(1u32) << 4).get(), 16);
1204 }
1205
1206 #[test]
1207 fn pod_shr() {
1208 assert_eq!((PodU32::from(16u32) >> 4).get(), 1);
1209 }
1210
1211 #[test]
1212 fn pod_not() {
1213 assert_eq!((!PodU16::from(0u16)).get(), u16::MAX);
1214 assert_eq!((!PodI16::from(0i16)).get(), -1i16);
1215 }
1216
1217 #[test]
1220 fn pod_bitand_assign_native() {
1221 let mut v = PodU32::from(0xFF00u32);
1222 v &= 0x0FF0u32;
1223 assert_eq!(v.get(), 0x0F00);
1224 }
1225
1226 #[test]
1227 fn pod_bitand_assign_pod() {
1228 let mut v = PodU32::from(0xFF00u32);
1229 v &= PodU32::from(0x0FF0u32);
1230 assert_eq!(v.get(), 0x0F00);
1231 }
1232
1233 #[test]
1234 fn pod_bitor_assign_native() {
1235 let mut v = PodU32::from(0xFF00u32);
1236 v |= 0x00FFu32;
1237 assert_eq!(v.get(), 0xFFFF);
1238 }
1239
1240 #[test]
1241 fn pod_bitor_assign_pod() {
1242 let mut v = PodU32::from(0xFF00u32);
1243 v |= PodU32::from(0x00FFu32);
1244 assert_eq!(v.get(), 0xFFFF);
1245 }
1246
1247 #[test]
1248 fn pod_bitxor_assign_native() {
1249 let mut v = PodU32::from(0xFFFFu32);
1250 v ^= 0xFF00u32;
1251 assert_eq!(v.get(), 0x00FF);
1252 }
1253
1254 #[test]
1255 fn pod_bitxor_assign_pod() {
1256 let mut v = PodU32::from(0xFFFFu32);
1257 v ^= PodU32::from(0xFF00u32);
1258 assert_eq!(v.get(), 0x00FF);
1259 }
1260
1261 #[test]
1262 fn pod_shl_assign() {
1263 let mut v = PodU32::from(1u32);
1264 v <<= 4;
1265 assert_eq!(v.get(), 16);
1266 }
1267
1268 #[test]
1269 fn pod_shr_assign() {
1270 let mut v = PodU32::from(16u32);
1271 v >>= 4;
1272 assert_eq!(v.get(), 1);
1273 }
1274
1275 #[test]
1280 fn pod_neg_i16() {
1281 assert_eq!((-PodI16::from(5i16)).get(), -5);
1282 assert_eq!((-PodI16::from(-5i16)).get(), 5);
1283 assert_eq!((-PodI16::from(0i16)).get(), 0);
1284 }
1285
1286 #[test]
1287 fn pod_neg_i32() {
1288 assert_eq!((-PodI32::from(42i32)).get(), -42);
1289 }
1290
1291 #[test]
1292 fn pod_neg_i64() {
1293 assert_eq!((-PodI64::from(100i64)).get(), -100);
1294 }
1295
1296 #[test]
1297 fn pod_neg_i128() {
1298 assert_eq!((-PodI128::from(999i128)).get(), -999);
1299 }
1300
1301 #[test]
1306 fn pod_checked_add_ok() {
1307 assert_eq!(
1308 PodU64::from(10u64).checked_add(5u64),
1309 Some(PodU64::from(15u64))
1310 );
1311 }
1312
1313 #[test]
1314 fn pod_checked_add_overflow() {
1315 assert_eq!(PodU64::MAX.checked_add(1u64), None);
1316 }
1317
1318 #[test]
1319 fn pod_checked_add_pod() {
1320 assert_eq!(
1321 PodU32::from(10u32).checked_add(PodU32::from(5u32)),
1322 Some(PodU32::from(15u32))
1323 );
1324 }
1325
1326 #[test]
1327 fn pod_checked_sub_ok() {
1328 assert_eq!(
1329 PodU64::from(10u64).checked_sub(5u64),
1330 Some(PodU64::from(5u64))
1331 );
1332 }
1333
1334 #[test]
1335 fn pod_checked_sub_underflow() {
1336 assert_eq!(PodU64::from(5u64).checked_sub(10u64), None);
1337 }
1338
1339 #[test]
1340 fn pod_checked_mul_ok() {
1341 assert_eq!(
1342 PodU64::from(6u64).checked_mul(7u64),
1343 Some(PodU64::from(42u64))
1344 );
1345 }
1346
1347 #[test]
1348 fn pod_checked_mul_overflow() {
1349 assert_eq!(PodU64::MAX.checked_mul(2u64), None);
1350 }
1351
1352 #[test]
1353 fn pod_checked_div_ok() {
1354 assert_eq!(
1355 PodU64::from(42u64).checked_div(7u64),
1356 Some(PodU64::from(6u64))
1357 );
1358 }
1359
1360 #[test]
1361 fn pod_checked_div_by_zero() {
1362 assert_eq!(PodU64::from(42u64).checked_div(0u64), None);
1363 }
1364
1365 #[test]
1366 fn pod_checked_signed_overflow() {
1367 assert_eq!(PodI64::MIN.checked_sub(1i64), None);
1368 assert_eq!(PodI64::MAX.checked_add(1i64), None);
1369 }
1370
1371 #[test]
1376 fn pod_saturating_add() {
1377 assert_eq!(PodU64::MAX.saturating_add(100u64), PodU64::MAX);
1378 assert_eq!(
1379 PodU64::from(10u64).saturating_add(5u64),
1380 PodU64::from(15u64)
1381 );
1382 }
1383
1384 #[test]
1385 fn pod_saturating_sub() {
1386 assert_eq!(PodU64::from(5u64).saturating_sub(10u64), PodU64::ZERO);
1387 assert_eq!(PodU64::from(10u64).saturating_sub(5u64), PodU64::from(5u64));
1388 }
1389
1390 #[test]
1391 fn pod_saturating_mul() {
1392 assert_eq!(PodU64::MAX.saturating_mul(2u64), PodU64::MAX);
1393 assert_eq!(PodU64::from(6u64).saturating_mul(7u64), PodU64::from(42u64));
1394 }
1395
1396 #[test]
1397 fn pod_saturating_signed() {
1398 assert_eq!(PodI64::MAX.saturating_add(100i64), PodI64::MAX);
1399 assert_eq!(PodI64::MIN.saturating_sub(100i64), PodI64::MIN);
1400 assert_eq!(PodI64::MAX.saturating_mul(2i64), PodI64::MAX);
1401 assert_eq!(PodI64::MIN.saturating_mul(2i64), PodI64::MIN);
1402 }
1403
1404 #[test]
1409 fn pod_ordering() {
1410 assert!(PodU64::from(10u64) > PodU64::from(5u64));
1411 assert!(PodU64::from(5u64) < PodU64::from(10u64));
1412 assert!(PodU64::from(5u64) == PodU64::from(5u64));
1413
1414 assert!(PodI64::from(-10i64) < PodI64::from(5i64));
1415 assert!(PodI64::from(5i64) > PodI64::from(-10i64));
1416 }
1417
1418 #[test]
1419 fn pod_partial_eq_native() {
1420 assert!(PodU64::from(42u64) == 42u64);
1421 assert!(PodI32::from(-5i32) == -5i32);
1422 assert!(PodU64::from(42u64) != 43u64);
1423 }
1424
1425 #[test]
1426 fn pod_partial_ord_native() {
1427 assert!(PodU64::from(10u64) > 5u64);
1428 assert!(PodU64::from(5u64) < 10u64);
1429 assert!(PodI32::from(-10i32) < 0i32);
1430 }
1431
1432 #[test]
1437 fn pod_display() {
1438 assert_eq!(std::format!("{}", PodU64::from(42u64)), "42");
1439 assert_eq!(std::format!("{}", PodI32::from(-7i32)), "-7");
1440 assert_eq!(std::format!("{}", PodU128::from(0u128)), "0");
1441 }
1442
1443 #[test]
1444 fn pod_debug() {
1445 assert_eq!(std::format!("{:?}", PodU64::from(42u64)), "PodU64(42)");
1446 assert_eq!(std::format!("{:?}", PodI32::from(-7i32)), "PodI32(-7)");
1447 }
1448
1449 #[test]
1454 fn pod_get_method() {
1455 assert_eq!(PodU16::from(1337u16).get(), 1337);
1456 assert_eq!(PodI16::from(-42i16).get(), -42);
1457 assert_eq!(PodU32::from(0xDEAD_BEEFu32).get(), 0xDEAD_BEEF);
1458 assert_eq!(PodI32::from(i32::MIN).get(), i32::MIN);
1459 assert_eq!(PodU64::from(u64::MAX).get(), u64::MAX);
1460 assert_eq!(PodI64::from(i64::MAX).get(), i64::MAX);
1461 assert_eq!(PodU128::from(u128::MAX).get(), u128::MAX);
1462 assert_eq!(PodI128::from(i128::MIN).get(), i128::MIN);
1463 }
1464
1465 #[test]
1470 fn ergonomic_counter_increment() {
1471 let mut count = PodU64::from(0u64);
1473 count += 1u64;
1474 assert_eq!(count.get(), 1);
1475 count += 1u64;
1476 assert_eq!(count.get(), 2);
1477 }
1478
1479 #[test]
1480 fn ergonomic_balance_arithmetic() {
1481 let mut balance = PodU64::from(1000u64);
1482 let fee = PodU64::from(25u64);
1483 balance -= fee;
1484 assert_eq!(balance.get(), 975);
1485 }
1486}