1use std::{
5 fmt,
6 ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr},
7};
8
9use binius_utils::serialization::{DeserializeBytes, SerializationError, SerializeBytes};
10use bytes::{Buf, BufMut};
11
12#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
15pub struct Word(pub u64);
16
17impl Word {
18 pub const ZERO: Word = Word(0);
20 pub const ONE: Word = Word(1);
22 pub const ALL_ONE: Word = Word(u64::MAX);
24 pub const MASK_32: Word = Word(0x00000000FFFFFFFF);
26 pub const MSB_ONE: Word = Word(0x8000000000000000);
30}
31
32impl fmt::Debug for Word {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 write!(f, "Word({:#018x})", self.0)
35 }
36}
37
38impl BitAnd for Word {
39 type Output = Self;
40
41 fn bitand(self, rhs: Self) -> Self::Output {
42 Word(self.0 & rhs.0)
43 }
44}
45
46impl BitOr for Word {
47 type Output = Self;
48
49 fn bitor(self, rhs: Self) -> Self::Output {
50 Word(self.0 | rhs.0)
51 }
52}
53
54impl BitXor for Word {
55 type Output = Self;
56
57 fn bitxor(self, rhs: Self) -> Self::Output {
58 Word(self.0 ^ rhs.0)
59 }
60}
61
62impl Shl<u32> for Word {
63 type Output = Self;
64
65 fn shl(self, rhs: u32) -> Self::Output {
66 Word(self.0 << rhs)
67 }
68}
69
70impl Shr<u32> for Word {
71 type Output = Self;
72
73 fn shr(self, rhs: u32) -> Self::Output {
74 Word(self.0 >> rhs)
75 }
76}
77
78impl Not for Word {
79 type Output = Self;
80
81 fn not(self) -> Self::Output {
82 Word(!self.0)
83 }
84}
85
86impl Word {
87 pub fn from_u64(value: u64) -> Word {
89 Word(value)
90 }
91
92 pub fn iadd_cout_32(self, rhs: Word) -> (Word, Word) {
97 let Word(lhs) = self;
98 let Word(rhs) = rhs;
99 let full_sum = lhs.wrapping_add(rhs);
100 let sum = full_sum & 0x00000000_FFFFFFFF;
101 let cout = (lhs & rhs) | ((lhs ^ rhs) & !full_sum);
102 (Word(sum), Word(cout))
103 }
104
105 pub fn iadd_cin_cout(self, rhs: Word, cin: Word) -> (Word, Word) {
113 debug_assert!(cin == Word::ZERO || cin == Word::ONE, "cin must be 0 or 1");
114 let Word(lhs) = self;
115 let Word(rhs) = rhs;
116 let Word(cin) = cin;
117 let sum = lhs.wrapping_add(rhs).wrapping_add(cin);
118 let cout = (lhs & rhs) | ((lhs ^ rhs) & !sum);
119 (Word(sum), Word(cout))
120 }
121
122 pub fn isub_bin_bout(self, rhs: Word, bin: Word) -> (Word, Word) {
130 debug_assert!(bin == Word::ZERO || bin == Word::ONE, "bin must be 0 or 1");
131 let Word(lhs) = self;
132 let Word(rhs) = rhs;
133 let Word(bin) = bin;
134 let diff = lhs.wrapping_sub(rhs).wrapping_sub(bin);
135 let bout = (!lhs & rhs) | (!(lhs ^ rhs) & diff);
136 (Word(diff), Word(bout))
137 }
138
139 pub fn shr_32(self, n: u32) -> Word {
141 let Word(value) = self;
142 let result = (value >> n) & 0x00000000_FFFFFFFF;
144 Word(result)
145 }
146
147 pub fn sar(&self, n: u32) -> Word {
151 let Word(value) = self;
152 let value = *value as i64;
153 let result = value >> n;
154 Word(result as u64)
155 }
156
157 pub fn rotr_32(self, n: u32) -> Word {
159 let Word(value) = self;
160 let value_32 = (value as u32).rotate_right(n);
161 Word(value_32 as u64)
162 }
163
164 pub fn rotr(self, n: u32) -> Word {
166 let Word(value) = self;
167 Word(value.rotate_right(n))
168 }
169
170 pub fn sll32(self, n: u32) -> Word {
175 let Word(value) = self;
176 let n = n & 0x1F; let lo = value as u32;
180 let hi = (value >> 32) as u32;
181
182 let lo_shifted = (lo << n) as u64;
184 let hi_shifted = ((hi << n) as u64) << 32;
185
186 Word(lo_shifted | hi_shifted)
187 }
188
189 pub fn srl32(self, n: u32) -> Word {
194 let Word(value) = self;
195 let n = n & 0x1F; let lo = value as u32;
199 let hi = (value >> 32) as u32;
200
201 let lo_shifted = (lo >> n) as u64;
203 let hi_shifted = ((hi >> n) as u64) << 32;
204
205 Word(lo_shifted | hi_shifted)
206 }
207
208 pub fn sra32(self, n: u32) -> Word {
214 let Word(value) = self;
215 let n = n & 0x1F; let lo = value as u32 as i32;
219 let hi = (value >> 32) as u32 as i32;
220
221 let lo_shifted = ((lo >> n) as u32) as u64;
223 let hi_shifted = (((hi >> n) as u32) as u64) << 32;
224
225 Word(lo_shifted | hi_shifted)
226 }
227
228 pub fn rotr32(self, n: u32) -> Word {
234 let Word(value) = self;
235 let n = n & 0x1F; let lo = value as u32;
239 let hi = (value >> 32) as u32;
240
241 let lo_rotated = lo.rotate_right(n) as u64;
243 let hi_rotated = (hi.rotate_right(n) as u64) << 32;
244
245 Word(lo_rotated | hi_rotated)
246 }
247
248 pub fn imul(self, rhs: Word) -> (Word, Word) {
253 let Word(lhs) = self;
254 let Word(rhs) = rhs;
255 let result = (lhs as u128) * (rhs as u128);
256
257 let hi = (result >> 64) as u64;
258 let lo = result as u64;
259 (Word(hi), Word(lo))
260 }
261
262 pub fn smul(self, rhs: Word) -> (Word, Word) {
267 let Word(lhs) = self;
268 let Word(rhs) = rhs;
269 let a = lhs as i64;
271 let b = rhs as i64;
272 let result = (a as i128) * (b as i128);
274 let hi = (result >> 64) as u64;
276 let lo = result as u64;
277 (Word(hi), Word(lo))
278 }
279
280 pub fn wrapping_add(self, rhs: Word) -> Word {
284 Word(self.0.wrapping_add(rhs.0))
285 }
286
287 pub fn wrapping_sub(self, rhs: Word) -> Word {
291 Word(self.0.wrapping_sub(rhs.0))
292 }
293
294 pub fn as_u64(self) -> u64 {
296 self.0
297 }
298
299 pub fn is_msb_true(self) -> bool {
306 (self.0 & 0x8000000000000000) != 0
307 }
308
309 pub fn is_msb_false(self) -> bool {
316 (self.0 & 0x8000000000000000) == 0
317 }
318}
319
320impl SerializeBytes for Word {
321 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
322 self.0.serialize(write_buf)
323 }
324}
325
326impl DeserializeBytes for Word {
327 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
328 where
329 Self: Sized,
330 {
331 Ok(Word(u64::deserialize(read_buf)?))
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use proptest::prelude::*;
338
339 use super::*;
340
341 #[test]
342 fn test_constants() {
343 assert_eq!(Word::ZERO, Word(0));
344 assert_eq!(Word::ONE, Word(1));
345 assert_eq!(Word::ALL_ONE, Word(0xFFFFFFFFFFFFFFFF));
346 assert_eq!(Word::MASK_32, Word(0x00000000FFFFFFFF));
347 assert_eq!(Word::MSB_ONE, Word(0x8000000000000000));
348 }
349
350 #[test]
351 fn test_msb_bool() {
352 assert!(Word::MSB_ONE.is_msb_true());
354 assert!(!Word::MSB_ONE.is_msb_false());
355
356 assert!(!Word::ZERO.is_msb_true());
358 assert!(Word::ZERO.is_msb_false());
359
360 assert!(Word(0x8000000000000000).is_msb_true());
362 assert!(Word(0x8000000000000001).is_msb_true());
363 assert!(Word(0x80000000FFFFFFFF).is_msb_true());
364 assert!(Word(0xFFFFFFFFFFFFFFFF).is_msb_true());
365
366 assert!(Word(0x7FFFFFFFFFFFFFFF).is_msb_false());
368 assert!(Word(0x0000000000000001).is_msb_false());
369 assert!(Word(0x00000000FFFFFFFF).is_msb_false());
370 assert!(Word(0x7000000000000000).is_msb_false());
371
372 let test_word = Word(0x8123456789ABCDEF);
374 assert!(test_word.is_msb_true());
375 assert!(!test_word.is_msb_false());
376
377 let test_word2 = Word(0x7123456789ABCDEF);
378 assert!(!test_word2.is_msb_true());
379 assert!(test_word2.is_msb_false());
380 }
381
382 proptest! {
383 #[test]
384 fn prop_msb_bool(val in any::<u64>()) {
385 let word = Word(val);
386
387 assert_eq!(word.is_msb_true(), !word.is_msb_false());
389 assert_eq!(word.is_msb_false(), !word.is_msb_true());
390
391 let msb_set = (val & 0x8000000000000000) != 0;
393 assert_eq!(word.is_msb_true(), msb_set);
394 assert_eq!(word.is_msb_false(), !msb_set);
395
396 let word_with_msb = Word(val | 0x8000000000000000);
398 let word_without_msb = Word(val & 0x7FFFFFFFFFFFFFFF);
399 assert!(word_with_msb.is_msb_true());
400 assert!(word_without_msb.is_msb_false());
401 }
402
403 #[test]
404 fn prop_bitwise_and(a in any::<u64>(), b in any::<u64>()) {
405 let wa = Word(a);
406 let wb = Word(b);
407
408 assert_eq!((wa & wb).0, a & b);
410 assert_eq!(wa & Word::ALL_ONE, wa);
411 assert_eq!(wa & Word::ZERO, Word::ZERO);
412 assert_eq!(wa & wa, wa); assert_eq!(wa & wb, wb & wa);
416 }
417
418 #[test]
419 fn prop_bitwise_or(a in any::<u64>(), b in any::<u64>()) {
420 let wa = Word(a);
421 let wb = Word(b);
422
423 assert_eq!((wa | wb).0, a | b);
425 assert_eq!(wa | Word::ZERO, wa);
426 assert_eq!(wa | Word::ALL_ONE, Word::ALL_ONE);
427 assert_eq!(wa | wa, wa); assert_eq!(wa | wb, wb | wa);
431 }
432
433 #[test]
434 fn prop_bitwise_xor(a in any::<u64>(), b in any::<u64>()) {
435 let wa = Word(a);
436 let wb = Word(b);
437
438 assert_eq!((wa ^ wb).0, a ^ b);
440 assert_eq!(wa ^ Word::ZERO, wa);
441 assert_eq!(wa ^ wa, Word::ZERO);
442 assert_eq!(wa ^ Word::ALL_ONE, !wa);
443
444 assert_eq!(wa ^ wb, wb ^ wa);
446
447 assert_eq!(wa ^ wb ^ wb, wa);
449 }
450
451 #[test]
452 fn prop_bitwise_not(a in any::<u64>()) {
453 let wa = Word(a);
454
455 assert_eq!((!wa).0, !a);
457 assert_eq!(!(!wa), wa); assert_eq!(!Word::ZERO, Word::ALL_ONE);
459 assert_eq!(!Word::ALL_ONE, Word::ZERO);
460
461 let wb = Word(a.wrapping_add(1));
463 assert_eq!(!(wa & wb), !wa | !wb);
464 assert_eq!(!(wa | wb), !wa & !wb);
465 }
466
467 #[test]
468 fn prop_shift_left(val in any::<u64>(), shift in 0u32..64) {
469 let w = Word(val);
470 assert_eq!((w << shift).0, val << shift);
471
472 assert_eq!(w << 0, w);
474
475 if shift >= 64 {
477 assert_eq!((w << shift).0, 0);
478 }
479 }
480
481 #[test]
482 fn prop_shift_right(val in any::<u64>(), shift in 0u32..64) {
483 let w = Word(val);
484 assert_eq!((w >> shift).0, val >> shift);
485
486 assert_eq!(w >> 0, w);
488
489 if shift >= 64 {
491 assert_eq!((w >> shift).0, 0);
492 }
493 }
494
495 #[test]
496 fn prop_shift_inverse(val in any::<u64>(), shift in 1u32..64) {
497 let w = Word(val);
498 let mask = (1u64 << (64 - shift)) - 1;
500 assert_eq!(((w << shift) >> shift).0, val & mask);
501
502 let high_mask = !((1u64 << shift) - 1);
504 assert_eq!(((w >> shift) << shift).0, val & high_mask);
505 }
506
507 #[test]
508 fn prop_sar(val in any::<u64>(), shift in 0u32..64) {
509 let w = Word(val);
510 let expected = ((val as i64) >> shift) as u64;
511 assert_eq!(w.sar(shift).0, expected);
512
513 assert_eq!(w.sar(0), w);
515
516 let sign_extended = if (val as i64) < 0 {
518 Word(0xFFFFFFFFFFFFFFFF)
519 } else {
520 Word(0)
521 };
522 assert_eq!(w.sar(63), sign_extended);
523 }
524
525 #[test]
526 fn prop_sar_sign_extension(val in any::<u64>(), shift in 1u32..64) {
527 let w = Word(val);
528 let result = w.sar(shift);
529
530 let is_negative = (val as i64) < 0;
532 if is_negative {
533 let mask = !((1u64 << (64 - shift)) - 1);
535 assert_eq!(result.0 & mask, mask);
536 } else {
537 let mask = !((1u64 << (64 - shift)) - 1);
539 assert_eq!(result.0 & mask, 0);
540 }
541 }
542
543 #[test]
544 fn prop_iadd_cout_32(a in any::<u32>(), b in any::<u32>()) {
545 let wa = Word(a as u64);
546 let wb = Word(b as u64);
547 let (sum, cout) = wa.iadd_cout_32(wb);
548
549 assert_eq!(sum.0, (a as u64 + b as u64) & 0xFFFFFFFF);
551
552 let expected_cout = (a as u64 & b as u64) | ((a as u64 ^ b as u64) & !sum.0);
554 assert_eq!(cout.0, expected_cout);
555
556 let (sum0, cout0) = wa.iadd_cout_32(Word::ZERO);
558 assert_eq!(sum0.0, a as u64);
559 assert_eq!(cout0, Word::ZERO);
560 }
561
562 #[test]
563 fn prop_iadd_cin_cout(a in any::<u64>(), b in any::<u64>(), cin in 0u64..=1) {
564 let wa = Word(a);
565 let wb = Word(b);
566 let wcin = Word(cin);
567 let (sum, cout) = wa.iadd_cin_cout(wb, wcin);
568
569 let expected_sum = a.wrapping_add(b).wrapping_add(cin);
571 assert_eq!(sum.0, expected_sum);
572
573 let expected_cout = (a & b) | ((a ^ b) & !expected_sum);
575 assert_eq!(cout.0, expected_cout);
576
577 let (sum0, cout0) = wa.iadd_cin_cout(wb, Word::ZERO);
579 let full_sum = a.wrapping_add(b);
580 assert_eq!(sum0.0, full_sum);
581 assert_eq!(cout0.0, (a & b) | ((a ^ b) & !full_sum));
582 }
583
584 #[test]
585 fn prop_isub_bin_bout(a in any::<u64>(), b in any::<u64>(), bin in 0u64..=1) {
586 let wa = Word(a);
587 let wb = Word(b);
588 let wbin = Word(bin);
589 let (diff, bout) = wa.isub_bin_bout(wb, wbin);
590
591 let expected_diff = a.wrapping_sub(b).wrapping_sub(bin);
593 assert_eq!(diff.0, expected_diff);
594
595 let expected_bout = (!a & b) | (!(a ^ b) & expected_diff);
597 assert_eq!(bout.0, expected_bout);
598
599 let (diff0, bout0) = wa.isub_bin_bout(wb, Word::ZERO);
601 let expected = a.wrapping_sub(b);
602 assert_eq!(diff0.0, expected);
603 assert_eq!(bout0.0, (!a & b) | (!(a ^ b) & expected));
604 }
605
606 #[test]
607 fn prop_shr_32(val in any::<u64>(), shift in 0u32..64) {
608 let w = Word(val);
609 let result = w.shr_32(shift);
610
611 let expected = (val >> shift) & 0xFFFFFFFF;
613 assert_eq!(result.0, expected);
614
615 assert_eq!(w.shr_32(0).0, val & 0xFFFFFFFF);
617
618 if shift >= 32 {
620 assert_eq!(result.0, (val >> shift) & 0xFFFFFFFF);
621 }
622 }
623
624 #[test]
625 fn prop_rotr_32(val in any::<u32>(), rotate in 0u32..64) {
626 let w = Word(val as u64);
627 let result = w.rotr_32(rotate);
628
629 let rotate_mod = rotate % 32;
631 let val32 = val as u64;
632 let expected = if rotate_mod == 0 {
633 val32
634 } else {
635 ((val32 >> rotate_mod) | (val32 << (32 - rotate_mod))) & 0xFFFFFFFF
636 };
637 assert_eq!(result.0, expected);
638
639 assert_eq!(w.rotr_32(0).0, val32);
641 assert_eq!(w.rotr_32(32).0, val32);
642 }
643
644 #[test]
645 fn prop_rotr(val in any::<u64>(), rotate in 0u32..128) {
646 let w = Word(val);
647 let result = w.rotr(rotate);
648
649 let rotate_mod = rotate % 64;
651 let expected = val.rotate_right(rotate_mod);
652 assert_eq!(result.0, expected);
653
654 assert_eq!(w.rotr(0), w);
656 assert_eq!(w.rotr(64), w);
657
658 let r1 = rotate % 64;
660 let r2 = (64 - r1) % 64;
661 if r1 != 0 {
662 assert_eq!(w.rotr(r1).rotr(r2), w);
663 }
664 }
665
666 #[test]
667 fn prop_imul(a in any::<u64>(), b in any::<u64>()) {
668 let wa = Word(a);
669 let wb = Word(b);
670 let (hi, lo) = wa.imul(wb);
671
672 let result = (a as u128) * (b as u128);
674 assert_eq!(hi.0, (result >> 64) as u64);
675 assert_eq!(lo.0, result as u64);
676
677 let (hi0, lo0) = wa.imul(Word::ZERO);
679 assert_eq!(hi0, Word::ZERO);
680 assert_eq!(lo0, Word::ZERO);
681
682 let (hi1, lo1) = wa.imul(Word::ONE);
684 assert_eq!(hi1, Word::ZERO);
685 assert_eq!(lo1, wa);
686
687 let (hi_ab, lo_ab) = wa.imul(wb);
689 let (hi_reversed, lo_reversed) = wb.imul(wa);
690 assert_eq!(hi_ab, hi_reversed);
691 assert_eq!(lo_ab, lo_reversed);
692 }
693
694 #[test]
695 fn prop_sll32(val in any::<u64>(), shift in 0u32..32) {
696 let w = Word(val);
697 let result = w.sll32(shift);
698
699 let lo = val as u32;
701 let hi = (val >> 32) as u32;
702
703 let expected_lo = ((lo << shift) as u64) & 0xFFFFFFFF;
705 let expected_hi = ((hi << shift) as u64) << 32;
706 let expected = expected_lo | expected_hi;
707
708 assert_eq!(result.0, expected);
709
710 assert_eq!(w.sll32(0), w);
712
713 let w_test = Word(0x40000001_40000001);
715 let result_31 = w_test.sll32(31);
716 assert_eq!(result_31.0, 0x80000000_80000000);
717
718 assert_eq!(w.sll32(shift), w.sll32(shift | 0x20));
720 }
721
722 #[test]
723 fn prop_srl32(val in any::<u64>(), shift in 0u32..32) {
724 let w = Word(val);
725 let result = w.srl32(shift);
726
727 let lo = val as u32;
729 let hi = (val >> 32) as u32;
730
731 let expected_lo = (lo >> shift) as u64;
733 let expected_hi = ((hi >> shift) as u64) << 32;
734 let expected = expected_lo | expected_hi;
735
736 assert_eq!(result.0, expected);
737
738 assert_eq!(w.srl32(0), w);
740
741 let w_test = Word(0x80000000_80000000);
743 let result_31 = w_test.srl32(31);
744 assert_eq!(result_31.0, 0x00000001_00000001);
745
746 assert_eq!(w.srl32(shift), w.srl32(shift | 0x20));
748 }
749
750 #[test]
751 fn prop_sra32(val in any::<u64>(), shift in 0u32..32) {
752 let w = Word(val);
753 let result = w.sra32(shift);
754
755 let lo = val as u32 as i32;
757 let hi = (val >> 32) as u32 as i32;
758
759 let expected_lo = ((lo >> shift) as u32) as u64;
761 let expected_hi = (((hi >> shift) as u32) as u64) << 32;
762 let expected = expected_lo | expected_hi;
763
764 assert_eq!(result.0, expected);
765
766 assert_eq!(w.sra32(0), w);
768
769 let w_neg = Word(0x80000000_80000000);
771 let result_1 = w_neg.sra32(1);
772 assert_eq!(result_1.0, 0xC0000000_C0000000);
773
774 let w_pos = Word(0x40000000_40000000);
776 let result_1_pos = w_pos.sra32(1);
777 assert_eq!(result_1_pos.0, 0x20000000_20000000);
778
779 let result_31 = w.sra32(31);
781 let expected_lo_31 = if lo < 0 { 0xFFFFFFFF } else { 0 };
782 let expected_hi_31 = if hi < 0 { 0xFFFFFFFF00000000 } else { 0 };
783 assert_eq!(result_31.0, expected_lo_31 | expected_hi_31);
784
785 assert_eq!(w.sra32(shift), w.sra32(shift | 0x20));
787 }
788
789 #[test]
790 fn prop_rotr32(val in any::<u64>(), rotate in 0u32..32) {
791 let w = Word(val);
792 let result = w.rotr32(rotate);
793
794 let lo = val as u32;
796 let hi = (val >> 32) as u32;
797
798 let expected_lo = lo.rotate_right(rotate) as u64;
800 let expected_hi = ((hi.rotate_right(rotate)) as u64) << 32;
801 let expected = expected_lo | expected_hi;
802
803 assert_eq!(result.0, expected);
804
805 assert_eq!(w.rotr32(0), w);
807
808 assert_eq!(w.rotr32(32), w.rotr32(0));
810
811 assert_eq!(w.rotr32(rotate), w.rotr32(rotate | 0x20));
813
814 if rotate > 0 && rotate < 32 {
816 let w_test = Word(0x12345678_9ABCDEF0);
817 let rotated = w_test.rotr32(rotate);
818 let back = rotated.rotr32(32 - rotate);
819 assert_eq!(back, w_test);
820 }
821 }
822
823 #[test]
824 fn prop_smul(a in any::<u64>(), b in any::<u64>()) {
825 let wa = Word(a);
826 let wb = Word(b);
827 let (hi, lo) = wa.smul(wb);
828
829 let result = (a as i64 as i128) * (b as i64 as i128);
831 assert_eq!(hi.0, (result >> 64) as u64);
832 assert_eq!(lo.0, result as u64);
833
834 let (hi0, lo0) = wa.smul(Word::ZERO);
836 assert_eq!(hi0, Word::ZERO);
837 assert_eq!(lo0, Word::ZERO);
838
839 let (hi1, lo1) = wa.smul(Word::ONE);
841 let expected_hi = if (a as i64) < 0 { Word(0xFFFFFFFFFFFFFFFF) } else { Word::ZERO };
842 assert_eq!(hi1, expected_hi);
843 assert_eq!(lo1, wa);
844
845 let (hi_neg, lo_neg) = wa.smul(Word(0xFFFFFFFFFFFFFFFF));
847 let neg_result = -(a as i64 as i128);
848 assert_eq!(hi_neg.0, (neg_result >> 64) as u64);
849 assert_eq!(lo_neg.0, neg_result as u64);
850
851 let (hi_ab, lo_ab) = wa.smul(wb);
853 let (hi_reversed, lo_reversed) = wb.smul(wa);
854 assert_eq!(hi_ab, hi_reversed);
855 assert_eq!(lo_ab, lo_reversed);
856 }
857
858 #[test]
859 fn prop_wrapping_sub(a in any::<u64>(), b in any::<u64>()) {
860 let wa = Word(a);
861 let wb = Word(b);
862 let result = wa.wrapping_sub(wb);
863
864 assert_eq!(result.0, a.wrapping_sub(b));
865
866 assert_eq!(wa.wrapping_sub(Word::ZERO), wa);
868
869 assert_eq!(wa.wrapping_sub(wa), Word::ZERO);
871
872 let sum = Word(a.wrapping_add(b));
874 assert_eq!(sum.wrapping_sub(wb), wa);
875 }
876
877 #[test]
878 fn prop_conversions(val in any::<u64>()) {
879 let word = Word::from_u64(val);
880 assert_eq!(word.as_u64(), val);
881 assert_eq!(word, Word(val));
882
883 assert_eq!(Word::from_u64(word.as_u64()), word);
885 }
886
887 #[test]
888 fn prop_debug_format(val in any::<u64>()) {
889 let word = Word(val);
890 let debug_str = format!("{:?}", word);
891 assert!(debug_str.starts_with("Word(0x"));
892 assert!(debug_str.ends_with(")"));
893 let expected = format!("Word({:#018x})", val);
895 assert_eq!(debug_str, expected);
896 }
897 }
898
899 #[test]
900 fn test_32bit_shift_edge_cases() {
901 let w1 = Word(0x12345678_9ABCDEF0);
903 assert_eq!(w1.sll32(4).0, 0x23456780_ABCDEF00);
904 assert_eq!(w1.sll32(16).0, 0x56780000_DEF00000);
905
906 let w2 = Word(0xFFFFFFFF_00000000);
908 assert_eq!(w2.sll32(1).0, 0xFFFFFFFE_00000000);
909 let w3 = Word(0x00000000_FFFFFFFF);
910 assert_eq!(w3.sll32(1).0, 0x00000000_FFFFFFFE);
911
912 assert_eq!(w1.srl32(4).0, 0x01234567_09ABCDEF);
914 assert_eq!(w1.srl32(16).0, 0x00001234_00009ABC);
915
916 let w4 = Word(0x80000000_7FFFFFFF); assert_eq!(w4.sra32(1).0, 0xC0000000_3FFFFFFF);
919 assert_eq!(w4.sra32(31).0, 0xFFFFFFFF_00000000);
920
921 let w5 = Word(0x7FFFFFFF_80000000); assert_eq!(w5.sra32(1).0, 0x3FFFFFFF_C0000000);
923 assert_eq!(w5.sra32(31).0, 0x00000000_FFFFFFFF);
924
925 let all_ones = Word(0xFFFFFFFF_FFFFFFFF);
927 assert_eq!(all_ones.sll32(1).0, 0xFFFFFFFE_FFFFFFFE);
928 assert_eq!(all_ones.srl32(1).0, 0x7FFFFFFF_7FFFFFFF);
929 assert_eq!(all_ones.sra32(1).0, 0xFFFFFFFF_FFFFFFFF);
930
931 let alternating = Word(0xAAAAAAAA_55555555);
932 assert_eq!(alternating.sll32(1).0, 0x55555554_AAAAAAAA);
933 assert_eq!(alternating.srl32(1).0, 0x55555555_2AAAAAAA);
934 assert_eq!(alternating.sra32(1).0, 0xD5555555_2AAAAAAA);
935
936 assert_eq!(w1.sll32(0), w1);
938 assert_eq!(w1.srl32(0), w1);
939 assert_eq!(w1.sra32(0), w1);
940
941 let w6 = Word(0x00000001_00000000);
943 assert_eq!(w6.sll32(31).0, 0x80000000_00000000);
944 assert_eq!(w6.srl32(1).0, 0x00000000_00000000);
945
946 let w7 = Word(0x80000001_80000001);
948 assert_eq!(w7.rotr32(1).0, 0xC0000000_C0000000);
949 assert_eq!(w7.rotr32(31).0, 0x00000003_00000003);
950
951 let w8 = Word(0x12345678_9ABCDEF0);
953 assert_eq!(w8.rotr32(4).0, 0x81234567_09ABCDEF);
954 assert_eq!(w8.rotr32(16).0, 0x56781234_DEF09ABC);
955
956 let w9 = Word(0xFFFF0000_0000FFFF);
958 assert_eq!(w9.rotr32(16).0, 0x0000FFFF_FFFF0000);
959
960 assert_eq!(w8.rotr32(0), w8);
962 }
963}