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 = if rotate_mod == 0 {
652 val
653 } else {
654 (val >> rotate_mod) | (val << (64 - rotate_mod))
655 };
656 assert_eq!(result.0, expected);
657
658 assert_eq!(w.rotr(0), w);
660 assert_eq!(w.rotr(64), w);
661
662 let r1 = rotate % 64;
664 let r2 = (64 - r1) % 64;
665 if r1 != 0 {
666 assert_eq!(w.rotr(r1).rotr(r2), w);
667 }
668 }
669
670 #[test]
671 fn prop_imul(a in any::<u64>(), b in any::<u64>()) {
672 let wa = Word(a);
673 let wb = Word(b);
674 let (hi, lo) = wa.imul(wb);
675
676 let result = (a as u128) * (b as u128);
678 assert_eq!(hi.0, (result >> 64) as u64);
679 assert_eq!(lo.0, result as u64);
680
681 let (hi0, lo0) = wa.imul(Word::ZERO);
683 assert_eq!(hi0, Word::ZERO);
684 assert_eq!(lo0, Word::ZERO);
685
686 let (hi1, lo1) = wa.imul(Word::ONE);
688 assert_eq!(hi1, Word::ZERO);
689 assert_eq!(lo1, wa);
690
691 let (hi_ab, lo_ab) = wa.imul(wb);
693 let (hi_reversed, lo_reversed) = wb.imul(wa);
694 assert_eq!(hi_ab, hi_reversed);
695 assert_eq!(lo_ab, lo_reversed);
696 }
697
698 #[test]
699 fn prop_sll32(val in any::<u64>(), shift in 0u32..32) {
700 let w = Word(val);
701 let result = w.sll32(shift);
702
703 let lo = val as u32;
705 let hi = (val >> 32) as u32;
706
707 let expected_lo = ((lo << shift) as u64) & 0xFFFFFFFF;
709 let expected_hi = ((hi << shift) as u64) << 32;
710 let expected = expected_lo | expected_hi;
711
712 assert_eq!(result.0, expected);
713
714 assert_eq!(w.sll32(0), w);
716
717 let w_test = Word(0x40000001_40000001);
719 let result_31 = w_test.sll32(31);
720 assert_eq!(result_31.0, 0x80000000_80000000);
721
722 assert_eq!(w.sll32(shift), w.sll32(shift | 0x20));
724 }
725
726 #[test]
727 fn prop_srl32(val in any::<u64>(), shift in 0u32..32) {
728 let w = Word(val);
729 let result = w.srl32(shift);
730
731 let lo = val as u32;
733 let hi = (val >> 32) as u32;
734
735 let expected_lo = (lo >> shift) as u64;
737 let expected_hi = ((hi >> shift) as u64) << 32;
738 let expected = expected_lo | expected_hi;
739
740 assert_eq!(result.0, expected);
741
742 assert_eq!(w.srl32(0), w);
744
745 let w_test = Word(0x80000000_80000000);
747 let result_31 = w_test.srl32(31);
748 assert_eq!(result_31.0, 0x00000001_00000001);
749
750 assert_eq!(w.srl32(shift), w.srl32(shift | 0x20));
752 }
753
754 #[test]
755 fn prop_sra32(val in any::<u64>(), shift in 0u32..32) {
756 let w = Word(val);
757 let result = w.sra32(shift);
758
759 let lo = val as u32 as i32;
761 let hi = (val >> 32) as u32 as i32;
762
763 let expected_lo = ((lo >> shift) as u32) as u64;
765 let expected_hi = (((hi >> shift) as u32) as u64) << 32;
766 let expected = expected_lo | expected_hi;
767
768 assert_eq!(result.0, expected);
769
770 assert_eq!(w.sra32(0), w);
772
773 let w_neg = Word(0x80000000_80000000);
775 let result_1 = w_neg.sra32(1);
776 assert_eq!(result_1.0, 0xC0000000_C0000000);
777
778 let w_pos = Word(0x40000000_40000000);
780 let result_1_pos = w_pos.sra32(1);
781 assert_eq!(result_1_pos.0, 0x20000000_20000000);
782
783 let result_31 = w.sra32(31);
785 let expected_lo_31 = if lo < 0 { 0xFFFFFFFF } else { 0 };
786 let expected_hi_31 = if hi < 0 { 0xFFFFFFFF00000000 } else { 0 };
787 assert_eq!(result_31.0, expected_lo_31 | expected_hi_31);
788
789 assert_eq!(w.sra32(shift), w.sra32(shift | 0x20));
791 }
792
793 #[test]
794 fn prop_rotr32(val in any::<u64>(), rotate in 0u32..32) {
795 let w = Word(val);
796 let result = w.rotr32(rotate);
797
798 let lo = val as u32;
800 let hi = (val >> 32) as u32;
801
802 let expected_lo = lo.rotate_right(rotate) as u64;
804 let expected_hi = ((hi.rotate_right(rotate)) as u64) << 32;
805 let expected = expected_lo | expected_hi;
806
807 assert_eq!(result.0, expected);
808
809 assert_eq!(w.rotr32(0), w);
811
812 assert_eq!(w.rotr32(32), w.rotr32(0));
814
815 assert_eq!(w.rotr32(rotate), w.rotr32(rotate | 0x20));
817
818 if rotate > 0 && rotate < 32 {
820 let w_test = Word(0x12345678_9ABCDEF0);
821 let rotated = w_test.rotr32(rotate);
822 let back = rotated.rotr32(32 - rotate);
823 assert_eq!(back, w_test);
824 }
825 }
826
827 #[test]
828 fn prop_smul(a in any::<u64>(), b in any::<u64>()) {
829 let wa = Word(a);
830 let wb = Word(b);
831 let (hi, lo) = wa.smul(wb);
832
833 let result = (a as i64 as i128) * (b as i64 as i128);
835 assert_eq!(hi.0, (result >> 64) as u64);
836 assert_eq!(lo.0, result as u64);
837
838 let (hi0, lo0) = wa.smul(Word::ZERO);
840 assert_eq!(hi0, Word::ZERO);
841 assert_eq!(lo0, Word::ZERO);
842
843 let (hi1, lo1) = wa.smul(Word::ONE);
845 let expected_hi = if (a as i64) < 0 { Word(0xFFFFFFFFFFFFFFFF) } else { Word::ZERO };
846 assert_eq!(hi1, expected_hi);
847 assert_eq!(lo1, wa);
848
849 let (hi_neg, lo_neg) = wa.smul(Word(0xFFFFFFFFFFFFFFFF));
851 let neg_result = -(a as i64 as i128);
852 assert_eq!(hi_neg.0, (neg_result >> 64) as u64);
853 assert_eq!(lo_neg.0, neg_result as u64);
854
855 let (hi_ab, lo_ab) = wa.smul(wb);
857 let (hi_reversed, lo_reversed) = wb.smul(wa);
858 assert_eq!(hi_ab, hi_reversed);
859 assert_eq!(lo_ab, lo_reversed);
860 }
861
862 #[test]
863 fn prop_wrapping_sub(a in any::<u64>(), b in any::<u64>()) {
864 let wa = Word(a);
865 let wb = Word(b);
866 let result = wa.wrapping_sub(wb);
867
868 assert_eq!(result.0, a.wrapping_sub(b));
869
870 assert_eq!(wa.wrapping_sub(Word::ZERO), wa);
872
873 assert_eq!(wa.wrapping_sub(wa), Word::ZERO);
875
876 let sum = Word(a.wrapping_add(b));
878 assert_eq!(sum.wrapping_sub(wb), wa);
879 }
880
881 #[test]
882 fn prop_conversions(val in any::<u64>()) {
883 let word = Word::from_u64(val);
884 assert_eq!(word.as_u64(), val);
885 assert_eq!(word, Word(val));
886
887 assert_eq!(Word::from_u64(word.as_u64()), word);
889 }
890
891 #[test]
892 fn prop_debug_format(val in any::<u64>()) {
893 let word = Word(val);
894 let debug_str = format!("{:?}", word);
895 assert!(debug_str.starts_with("Word(0x"));
896 assert!(debug_str.ends_with(")"));
897 let expected = format!("Word({:#018x})", val);
899 assert_eq!(debug_str, expected);
900 }
901 }
902
903 #[test]
904 fn test_32bit_shift_edge_cases() {
905 let w1 = Word(0x12345678_9ABCDEF0);
907 assert_eq!(w1.sll32(4).0, 0x23456780_ABCDEF00);
908 assert_eq!(w1.sll32(16).0, 0x56780000_DEF00000);
909
910 let w2 = Word(0xFFFFFFFF_00000000);
912 assert_eq!(w2.sll32(1).0, 0xFFFFFFFE_00000000);
913 let w3 = Word(0x00000000_FFFFFFFF);
914 assert_eq!(w3.sll32(1).0, 0x00000000_FFFFFFFE);
915
916 assert_eq!(w1.srl32(4).0, 0x01234567_09ABCDEF);
918 assert_eq!(w1.srl32(16).0, 0x00001234_00009ABC);
919
920 let w4 = Word(0x80000000_7FFFFFFF); assert_eq!(w4.sra32(1).0, 0xC0000000_3FFFFFFF);
923 assert_eq!(w4.sra32(31).0, 0xFFFFFFFF_00000000);
924
925 let w5 = Word(0x7FFFFFFF_80000000); assert_eq!(w5.sra32(1).0, 0x3FFFFFFF_C0000000);
927 assert_eq!(w5.sra32(31).0, 0x00000000_FFFFFFFF);
928
929 let all_ones = Word(0xFFFFFFFF_FFFFFFFF);
931 assert_eq!(all_ones.sll32(1).0, 0xFFFFFFFE_FFFFFFFE);
932 assert_eq!(all_ones.srl32(1).0, 0x7FFFFFFF_7FFFFFFF);
933 assert_eq!(all_ones.sra32(1).0, 0xFFFFFFFF_FFFFFFFF);
934
935 let alternating = Word(0xAAAAAAAA_55555555);
936 assert_eq!(alternating.sll32(1).0, 0x55555554_AAAAAAAA);
937 assert_eq!(alternating.srl32(1).0, 0x55555555_2AAAAAAA);
938 assert_eq!(alternating.sra32(1).0, 0xD5555555_2AAAAAAA);
939
940 assert_eq!(w1.sll32(0), w1);
942 assert_eq!(w1.srl32(0), w1);
943 assert_eq!(w1.sra32(0), w1);
944
945 let w6 = Word(0x00000001_00000000);
947 assert_eq!(w6.sll32(31).0, 0x80000000_00000000);
948 assert_eq!(w6.srl32(1).0, 0x00000000_00000000);
949
950 let w7 = Word(0x80000001_80000001);
952 assert_eq!(w7.rotr32(1).0, 0xC0000000_C0000000);
953 assert_eq!(w7.rotr32(31).0, 0x00000003_00000003);
954
955 let w8 = Word(0x12345678_9ABCDEF0);
957 assert_eq!(w8.rotr32(4).0, 0x81234567_09ABCDEF);
958 assert_eq!(w8.rotr32(16).0, 0x56781234_DEF09ABC);
959
960 let w9 = Word(0xFFFF0000_0000FFFF);
962 assert_eq!(w9.rotr32(16).0, 0x0000FFFF_FFFF0000);
963
964 assert_eq!(w8.rotr32(0), w8);
966 }
967}