1use num_traits::ops::overflowing::{OverflowingAdd, OverflowingSub};
16use num_traits::{Bounded, One, PrimInt, ToPrimitive, Zero};
17
18use core::convert::TryFrom;
19use core::fmt::Write;
20
21use crate::machineword::MachineWord;
22
23#[allow(unused_imports)]
24use num_traits::{FromPrimitive, Num};
25
26mod add_sub_impl;
27mod bit_ops_impl;
28mod euclid;
29mod iter_impl;
30mod mul_div_impl;
31mod num_integer_impl;
32mod num_traits_casts;
33mod num_traits_identity;
34mod prim_int_impl;
35mod roots_impl;
36mod string_conversion;
37mod to_from_bytes;
38
39#[derive(Debug, Clone, Copy, core::cmp::PartialEq, core::cmp::Eq)]
41pub struct FixedUInt<T, const N: usize>
42where
43 T: MachineWord,
44{
45 array: [T; N],
47}
48
49const LONGEST_WORD_IN_BITS: usize = 128;
50
51impl<T: MachineWord, const N: usize> FixedUInt<T, N> {
52 const WORD_SIZE: usize = core::mem::size_of::<T>();
53 const WORD_BITS: usize = Self::WORD_SIZE * 8;
54 const BYTE_SIZE: usize = Self::WORD_SIZE * N;
55 const BIT_SIZE: usize = Self::BYTE_SIZE * 8;
56
57 pub fn new() -> FixedUInt<T, N> {
59 FixedUInt {
60 array: [T::zero(); N],
61 }
62 }
63
64 pub fn bit_length(&self) -> u32 {
66 Self::BIT_SIZE as u32 - self.leading_zeros()
67 }
68
69 pub fn div_rem(&self, divisor: &Self) -> (Self, Self) {
71 let quot = *self / *divisor;
72 let tmp = quot * *divisor;
73 let rem = *self - tmp;
74 (quot, rem)
75 }
76
77 pub fn from_le_bytes(bytes: &[u8]) -> Self {
79 let mut ret = Self::new();
80 let total_bytes = core::cmp::min(bytes.len(), N * Self::WORD_SIZE);
81
82 for (byte_index, &byte) in bytes.iter().enumerate().take(total_bytes) {
83 let word_index = byte_index / Self::WORD_SIZE;
84 let byte_in_word = byte_index % Self::WORD_SIZE;
85
86 let byte_value: T = byte.into();
87 let shifted_value = byte_value.shl(byte_in_word * 8);
88 ret.array[word_index] |= shifted_value;
89 }
90 ret
91 }
92
93 pub fn from_be_bytes(bytes: &[u8]) -> Self {
95 let mut ret = Self::new();
96 let capacity_bytes = N * Self::WORD_SIZE;
97 let total_bytes = core::cmp::min(bytes.len(), capacity_bytes);
98
99 let start_offset = if bytes.len() > capacity_bytes {
102 bytes.len() - capacity_bytes
103 } else {
104 0
105 };
106
107 for (byte_index, _) in (0..total_bytes).enumerate() {
108 let be_byte_index = start_offset + total_bytes - 1 - byte_index;
110 let word_index = byte_index / Self::WORD_SIZE;
111 let byte_in_word = byte_index % Self::WORD_SIZE;
112
113 let byte_value: T = bytes[be_byte_index].into();
114 let shifted_value = byte_value.shl(byte_in_word * 8);
115 ret.array[word_index] |= shifted_value;
116 }
117 ret
118 }
119
120 pub fn to_le_bytes<'a>(&self, output_buffer: &'a mut [u8]) -> Result<&'a [u8], bool> {
122 let total_bytes = N * Self::WORD_SIZE;
123 if output_buffer.len() < total_bytes {
124 return Err(false); }
126 for (i, word) in self.array.iter().enumerate() {
127 let start = i * Self::WORD_SIZE;
128 let end = start + Self::WORD_SIZE;
129 let word_bytes = word.to_le_bytes();
130 output_buffer[start..end].copy_from_slice(word_bytes.as_ref());
131 }
132 Ok(&output_buffer[..total_bytes])
133 }
134
135 pub fn to_be_bytes<'a>(&self, output_buffer: &'a mut [u8]) -> Result<&'a [u8], bool> {
137 let total_bytes = N * Self::WORD_SIZE;
138 if output_buffer.len() < total_bytes {
139 return Err(false); }
141 for (i, word) in self.array.iter().rev().enumerate() {
142 let start = i * Self::WORD_SIZE;
143 let end = start + Self::WORD_SIZE;
144 let word_bytes = word.to_be_bytes();
145 output_buffer[start..end].copy_from_slice(word_bytes.as_ref());
146 }
147 Ok(&output_buffer[..total_bytes])
148 }
149
150 pub fn to_hex_str<'a>(&self, result: &'a mut [u8]) -> Result<&'a str, core::fmt::Error> {
152 type Error = core::fmt::Error;
153
154 let word_size = Self::WORD_SIZE;
155 let need_bits = self.bit_length() as usize;
157 let need_chars = if need_bits > 0 { need_bits / 4 } else { 0 };
159
160 if result.len() < need_chars {
161 return Err(Error {});
163 }
164 let offset = result.len() - need_chars;
165 for i in result.iter_mut() {
166 *i = b'0';
167 }
168
169 for iter_words in 0..self.array.len() {
170 let word = self.array[iter_words];
171 let mut encoded = [0u8; LONGEST_WORD_IN_BITS / 4];
172 let encode_slice = &mut encoded[0..word_size * 2];
173 let mut wordbytes = word.to_le_bytes();
174 wordbytes.as_mut().reverse();
175 let wordslice = wordbytes.as_ref();
176 to_slice_hex(wordslice, encode_slice).map_err(|_| Error {})?;
177 for iter_chars in 0..encode_slice.len() {
178 let copy_char_to = (iter_words * word_size * 2) + iter_chars;
179 if copy_char_to <= need_chars {
180 let reverse_index = offset + (need_chars - copy_char_to);
181 if reverse_index <= result.len() && reverse_index > 0 {
182 let current_char = encode_slice[(encode_slice.len() - 1) - iter_chars];
183 result[reverse_index - 1] = current_char;
184 }
185 }
186 }
187 }
188
189 let convert = core::str::from_utf8(result).map_err(|_| Error {})?;
190 let pos = convert.find(|c: char| c != '0');
191 match pos {
192 Some(x) => Ok(&convert[x..convert.len()]),
193 None => {
194 if convert.starts_with('0') {
195 Ok("0")
196 } else {
197 Ok(convert)
198 }
199 }
200 }
201 }
202
203 pub fn to_radix_str<'a>(
205 &self,
206 result: &'a mut [u8],
207 radix: u8,
208 ) -> Result<&'a str, core::fmt::Error> {
209 type Error = core::fmt::Error;
210
211 if !(2..=16).contains(&radix) {
212 return Err(Error {}); }
214 for byte in result.iter_mut() {
215 *byte = b'0';
216 }
217 if self.is_zero() {
218 if !result.is_empty() {
219 result[0] = b'0';
220 return core::str::from_utf8(&result[0..1]).map_err(|_| Error {});
221 } else {
222 return Err(Error {});
223 }
224 }
225
226 let mut number = *self;
227 let mut idx = result.len();
228
229 let radix_t = Self::from(radix);
230
231 while !number.is_zero() {
232 if idx == 0 {
233 return Err(Error {}); }
235
236 idx -= 1;
237 let (quotient, remainder) = number.div_rem(&radix_t);
238
239 let digit = remainder.to_u8().unwrap();
240 result[idx] = match digit {
241 0..=9 => b'0' + digit, 10..=16 => b'a' + (digit - 10), _ => return Err(Error {}),
244 };
245
246 number = quotient;
247 }
248
249 let start = result[idx..].iter().position(|&c| c != b'0').unwrap_or(0);
250 let radix_str = core::str::from_utf8(&result[idx + start..]).map_err(|_| Error {})?;
251 Ok(radix_str)
252 }
253
254 fn hex_fmt(
255 &self,
256 formatter: &mut core::fmt::Formatter<'_>,
257 uppercase: bool,
258 ) -> Result<(), core::fmt::Error>
259 where
260 u8: core::convert::TryFrom<T>,
261 {
262 type Err = core::fmt::Error;
263
264 fn to_casedigit(byte: u8, uppercase: bool) -> Result<char, core::fmt::Error> {
265 let digit = core::char::from_digit(byte as u32, 16).ok_or(Err {})?;
266 if uppercase {
267 digit.to_uppercase().next().ok_or(Err {})
268 } else {
269 digit.to_lowercase().next().ok_or(Err {})
270 }
271 }
272
273 let mut leading_zero: bool = true;
274
275 let mut maybe_write = |nibble: char| -> Result<(), core::fmt::Error> {
276 leading_zero &= nibble == '0';
277 if !leading_zero {
278 formatter.write_char(nibble)?;
279 }
280 Ok(())
281 };
282
283 for index in (0..N).rev() {
284 let val = self.array[index];
285 let mask: T = 0xff.into();
286 for j in (0..Self::WORD_SIZE as u32).rev() {
287 let masked = val & mask.shl((j * 8) as usize);
288
289 let byte = u8::try_from(masked.shr((j * 8) as usize)).map_err(|_| Err {})?;
290
291 maybe_write(to_casedigit((byte & 0xf0) >> 4, uppercase)?)?;
292 maybe_write(to_casedigit(byte & 0x0f, uppercase)?)?;
293 }
294 }
295 Ok(())
296 }
297 fn add_impl(target: &mut Self, other: &Self) -> bool {
300 let mut carry = T::zero();
301 for i in 0..N {
302 let (res, carry1) = target.array[i].overflowing_add(&other.array[i]);
303 let (res, carry2) = res.overflowing_add(&carry);
304 carry = if carry1 || carry2 {
305 T::one()
306 } else {
307 T::zero()
308 };
309 target.array[i] = res
310 }
311 !carry.is_zero()
312 }
313
314 fn saturating_add_impl(self, other: &Self) -> Self {
316 let res = self.overflowing_add(other);
317 if res.1 {
318 Self::max_value()
319 } else {
320 res.0
321 }
322 }
323
324 fn sub_impl(target: &mut Self, other: &Self) -> bool {
327 let mut borrow = T::zero();
328 for i in 0..N {
329 let (res, borrow1) = target.array[i].overflowing_sub(&other.array[i]);
330 let (res, borrow2) = res.overflowing_sub(&borrow);
331 borrow = if borrow1 || borrow2 {
332 T::one()
333 } else {
334 T::zero()
335 };
336 target.array[i] = res;
337 }
338 !borrow.is_zero()
339 }
340
341 fn saturating_sub_impl(self, other: &Self) -> Self {
342 let res = self.overflowing_sub(other);
343 if res.1 {
344 Self::zero()
345 } else {
346 res.0
347 }
348 }
349
350 fn mul_impl<const CHECK_OVERFLOW: bool>(op1: &Self, op2: &Self) -> (Self, bool) {
353 let mut result = Self::zero();
354 let mut overflowed = false;
355 let max_rounds = if CHECK_OVERFLOW { N + 1 } else { N };
357 let t_max = T::max_value().to_double();
358 for i in 0..N {
359 let mut carry = T::DoubleWord::zero();
360 for j in 0..N {
361 let round = i + j;
362 if round < max_rounds {
363 let mul_res = op1.array[i].to_double() * op2.array[j].to_double();
364 let mut accumulator = T::DoubleWord::zero();
365 if round < N {
366 accumulator = result.array[round].to_double();
367 }
368 accumulator = accumulator + mul_res + carry;
369
370 if accumulator > t_max {
371 carry = accumulator >> Self::WORD_BITS;
372 accumulator = accumulator & t_max;
373 } else {
374 carry = T::DoubleWord::zero();
375 }
376 if round < N {
377 result.array[round] = T::from_double(accumulator);
378 } else if CHECK_OVERFLOW {
379 overflowed = overflowed || !accumulator.is_zero();
380 }
381 }
382 }
383 if !carry.is_zero() && CHECK_OVERFLOW {
384 overflowed = true;
385 }
386 }
387 (result, overflowed)
388 }
389
390 fn set_bit(&mut self, pos: usize) {
392 if pos >= Self::BIT_SIZE {
393 return; }
395 let word_idx = pos / Self::WORD_BITS;
396 let bit_idx = pos % Self::WORD_BITS;
397 self.array[word_idx] |= T::one().shl(bit_idx);
398 }
399
400 fn cmp_shifted(&self, other: &Self, shift_bits: usize) -> core::cmp::Ordering {
402 if shift_bits == 0 {
403 return self.cmp(other);
404 }
405
406 if shift_bits >= Self::BIT_SIZE {
407 if self.is_zero() {
409 return core::cmp::Ordering::Equal;
410 } else {
411 return core::cmp::Ordering::Greater;
412 }
413 }
414
415 let word_shift = shift_bits / Self::WORD_BITS;
417 let bit_shift = shift_bits % Self::WORD_BITS;
418
419 for i in (0..N).rev() {
421 let self_word = self.array[i];
422 let other_shifted_word = self.get_shifted_word(other, i, word_shift, bit_shift);
423
424 match self_word.cmp(&other_shifted_word) {
425 core::cmp::Ordering::Equal => continue,
426 other_result => return other_result,
427 }
428 }
429
430 core::cmp::Ordering::Equal
431 }
432
433 fn get_shifted_word(
435 &self,
436 other: &Self,
437 word_idx: usize,
438 word_shift: usize,
439 bit_shift: usize,
440 ) -> T {
441 if word_idx < word_shift {
442 return T::zero();
444 }
445
446 let source_idx = word_idx - word_shift;
447
448 if bit_shift == 0 {
449 if source_idx < N {
451 other.array[source_idx]
452 } else {
453 T::zero()
454 }
455 } else {
456 let mut result = T::zero();
458
459 if source_idx < N {
461 result |= other.array[source_idx].shl(bit_shift);
462 }
463
464 if source_idx > 0 && (source_idx - 1) < N {
466 let high_bits = other.array[source_idx - 1].shr(Self::WORD_BITS - bit_shift);
467 result |= high_bits;
468 }
469
470 result
471 }
472 }
473
474 fn sub_shifted(&mut self, other: &Self, shift_bits: usize) {
476 if shift_bits == 0 {
477 *self -= *other;
478 return;
479 }
480
481 if shift_bits >= Self::BIT_SIZE {
482 return;
484 }
485
486 let word_shift = shift_bits / Self::WORD_BITS;
488 let bit_shift = shift_bits % Self::WORD_BITS;
489
490 let mut borrow = false;
491
492 for i in 0..N {
494 let other_shifted_word = self.get_shifted_word(other, i, word_shift, bit_shift);
495
496 let (result, new_borrow) =
498 Self::sub_with_borrow(self.array[i], other_shifted_word, borrow);
499 self.array[i] = result;
500 borrow = new_borrow;
501 }
502 }
503
504 fn sub_with_borrow(a: T, b: T, borrow: bool) -> (T, bool) {
506 let (temp, borrow1) = if borrow {
508 a.overflowing_sub(&T::one())
509 } else {
510 (a, false)
511 };
512
513 let (result, borrow2) = temp.overflowing_sub(&b);
515 (result, borrow1 || borrow2)
516 }
517
518 fn div_assign_impl(dividend: &mut Self, divisor: &Self) -> Self {
520 if *dividend < *divisor {
521 let remainder = *dividend;
522 *dividend = Self::zero();
523 return remainder;
524 }
525 if *dividend == *divisor {
526 *dividend = Self::one();
527 return Self::zero();
528 }
529
530 let mut quotient = Self::zero();
531
532 let dividend_bits = dividend.bit_length() as usize;
534 let divisor_bits = divisor.bit_length() as usize;
535
536 let mut bit_pos = dividend_bits.saturating_sub(divisor_bits);
537
538 while bit_pos > 0 && dividend.cmp_shifted(divisor, bit_pos) == core::cmp::Ordering::Less {
540 bit_pos -= 1;
541 }
542
543 loop {
545 if dividend.cmp_shifted(divisor, bit_pos) != core::cmp::Ordering::Less {
546 dividend.sub_shifted(divisor, bit_pos);
547 quotient.set_bit(bit_pos);
548 }
549
550 if bit_pos == 0 {
551 break;
552 }
553 bit_pos -= 1;
554 }
555
556 let remainder = *dividend;
557 *dividend = quotient;
558 remainder
559 }
560
561 fn div_impl(dividend: &Self, divisor: &Self) -> Self {
563 let mut dividend_copy = *dividend;
564 Self::div_assign_impl(&mut dividend_copy, divisor);
565 dividend_copy
566 }
567
568 fn shl_impl(target: &mut Self, bits: usize) {
570 let nwords = bits / Self::WORD_BITS;
571 let nbits = bits - nwords * Self::WORD_BITS;
572
573 for i in (nwords..N).rev() {
575 target.array[i] = target.array[i - nwords];
576 }
577 for i in 0..nwords {
579 target.array[i] = T::zero();
580 }
581
582 if nbits != 0 {
583 for i in (1..N).rev() {
585 let right = target.array[i].shl(nbits);
586 let left = target.array[i - 1].shr(Self::WORD_BITS - nbits);
587 target.array[i] = right | left;
588 }
589 target.array[0] = target.array[0].shl(nbits);
590 }
591 }
592
593 fn shr_impl(target: &mut Self, bits: usize) {
595 let nwords = bits / Self::WORD_BITS;
596 let nbits = bits - nwords * Self::WORD_BITS;
597
598 let last_index = N - 1;
599 let last_word = N - nwords;
600
601 for i in 0..last_word {
603 target.array[i] = target.array[i + nwords];
604 }
605
606 for i in last_word..N {
608 target.array[i] = T::zero();
609 }
610
611 if nbits != 0 {
612 for i in 0..last_index {
614 let left = target.array[i].shr(nbits);
615 let right = target.array[i + 1].shl(Self::WORD_BITS - nbits);
616 target.array[i] = left | right;
617 }
618 target.array[last_index] = target.array[last_index].shr(nbits);
619 }
620 }
621
622 fn normalize_shift(bits: u32) -> u32 {
624 bits % (Self::BIT_SIZE as u32)
625 }
626}
627
628impl<T: MachineWord, const N: usize> Default for FixedUInt<T, N> {
629 fn default() -> Self {
630 Self::new()
631 }
632}
633
634impl<T: MachineWord, const N: usize> num_traits::Unsigned for FixedUInt<T, N> {}
635
636impl<T: MachineWord, const N: usize> core::cmp::Ord for FixedUInt<T, N> {
639 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
640 for i in (0..N).rev() {
641 if self.array[i] > other.array[i] {
642 return core::cmp::Ordering::Greater;
643 }
644 if self.array[i] < other.array[i] {
645 return core::cmp::Ordering::Less;
646 }
647 }
648 core::cmp::Ordering::Equal
649 }
650}
651
652impl<T: MachineWord, const N: usize> core::cmp::PartialOrd for FixedUInt<T, N> {
653 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
654 Some(self.cmp(other))
655 }
656}
657
658impl<T: MachineWord, const N: usize> core::convert::From<u8> for FixedUInt<T, N> {
663 fn from(x: u8) -> Self {
664 let mut ret = Self::new();
665 ret.array[0] = x.into();
666 ret
667 }
668}
669
670impl<T: MachineWord, const N: usize> core::convert::From<u16> for FixedUInt<T, N> {
671 fn from(x: u16) -> Self {
672 Self::from_le_bytes(&x.to_le_bytes())
673 }
674}
675
676impl<T: MachineWord, const N: usize> core::convert::From<u32> for FixedUInt<T, N> {
677 fn from(x: u32) -> Self {
678 Self::from_le_bytes(&x.to_le_bytes())
679 }
680}
681
682impl<T: MachineWord, const N: usize> core::convert::From<u64> for FixedUInt<T, N> {
683 fn from(x: u64) -> Self {
684 Self::from_le_bytes(&x.to_le_bytes())
685 }
686}
687
688fn make_parse_int_err() -> core::num::ParseIntError {
695 <u8>::from_str_radix("-", 2).err().unwrap()
696}
697fn make_overflow_err() -> core::num::ParseIntError {
698 <u8>::from_str_radix("101", 16).err().unwrap()
699}
700fn make_empty_error() -> core::num::ParseIntError {
701 <u8>::from_str_radix("", 8).err().unwrap()
702}
703
704fn to_slice_hex<T: AsRef<[u8]>>(
705 input: T,
706 output: &mut [u8],
707) -> Result<(), core::num::ParseIntError> {
708 fn from_digit(byte: u8) -> Option<char> {
709 core::char::from_digit(byte as u32, 16)
710 }
711 let r = input.as_ref();
712 if r.len() * 2 != output.len() {
713 return Err(make_parse_int_err());
714 }
715 for i in 0..r.len() {
716 let byte = r[i];
717 output[i * 2] = from_digit((byte & 0xf0) >> 4).ok_or_else(make_parse_int_err)? as u8;
718 output[i * 2 + 1] = from_digit(byte & 0x0f).ok_or_else(make_parse_int_err)? as u8;
719 }
720
721 Ok(())
722}
723
724enum PanicReason {
725 Add,
726 Sub,
727 Mul,
728 DivByZero,
729 RemByZero,
730}
731
732fn maybe_panic(r: PanicReason) {
733 match r {
734 PanicReason::Add => panic!("attempt to add with overflow"),
735 PanicReason::Sub => panic!("attempt to subtract with overflow"),
736 PanicReason::Mul => panic!("attempt to multiply with overflow"),
737 PanicReason::DivByZero => panic!("attempt to divide by zero"),
738 PanicReason::RemByZero => {
739 panic!("attempt to calculate the remainder with a divisor of zero")
740 }
741 }
742}
743
744#[cfg(test)]
747mod tests {
748 use super::FixedUInt as Bn;
749 use super::*;
750
751 type Bn8 = Bn<u8, 8>;
752 type Bn16 = Bn<u16, 4>;
753 type Bn32 = Bn<u32, 2>;
754
755 #[test]
756 fn test_core_convert_u8() {
757 let f = Bn::<u8, 1>::from(1u8);
758 assert_eq!(f.array, [1]);
759 let f = Bn::<u8, 2>::from(1u8);
760 assert_eq!(f.array, [1, 0]);
761
762 let f = Bn::<u16, 1>::from(1u8);
763 assert_eq!(f.array, [1]);
764 let f = Bn::<u16, 2>::from(1u8);
765 assert_eq!(f.array, [1, 0]);
766 }
767
768 #[test]
769 fn test_core_convert_u16() {
770 let f = Bn::<u8, 1>::from(1u16);
771 assert_eq!(f.array, [1]);
772 let f = Bn::<u8, 2>::from(1u16);
773 assert_eq!(f.array, [1, 0]);
774
775 let f = Bn::<u8, 1>::from(256u16);
776 assert_eq!(f.array, [0]);
777 let f = Bn::<u8, 2>::from(257u16);
778 assert_eq!(f.array, [1, 1]);
779 let f = Bn::<u8, 2>::from(65535u16);
780 assert_eq!(f.array, [255, 255]);
781
782 let f = Bn::<u16, 1>::from(1u16);
783 assert_eq!(f.array, [1]);
784 let f = Bn::<u16, 2>::from(1u16);
785 assert_eq!(f.array, [1, 0]);
786
787 let f = Bn::<u16, 1>::from(65535u16);
788 assert_eq!(f.array, [65535]);
789 }
790
791 #[test]
792 fn test_core_convert_u32() {
793 let f = Bn::<u8, 1>::from(1u32);
794 assert_eq!(f.array, [1]);
795 let f = Bn::<u8, 1>::from(256u32);
796 assert_eq!(f.array, [0]);
797
798 let f = Bn::<u8, 2>::from(1u32);
799 assert_eq!(f.array, [1, 0]);
800 let f = Bn::<u8, 2>::from(257u32);
801 assert_eq!(f.array, [1, 1]);
802 let f = Bn::<u8, 2>::from(65535u32);
803 assert_eq!(f.array, [255, 255]);
804
805 let f = Bn::<u8, 4>::from(1u32);
806 assert_eq!(f.array, [1, 0, 0, 0]);
807 let f = Bn::<u8, 4>::from(257u32);
808 assert_eq!(f.array, [1, 1, 0, 0]);
809 let f = Bn::<u8, 4>::from(u32::max_value());
810 assert_eq!(f.array, [255, 255, 255, 255]);
811
812 let f = Bn::<u8, 1>::from(1u32);
813 assert_eq!(f.array, [1]);
814 let f = Bn::<u8, 1>::from(256u32);
815 assert_eq!(f.array, [0]);
816
817 let f = Bn::<u16, 2>::from(65537u32);
818 assert_eq!(f.array, [1, 1]);
819
820 let f = Bn::<u32, 1>::from(1u32);
821 assert_eq!(f.array, [1]);
822 let f = Bn::<u32, 2>::from(1u32);
823 assert_eq!(f.array, [1, 0]);
824
825 let f = Bn::<u32, 1>::from(65537u32);
826 assert_eq!(f.array, [65537]);
827
828 let f = Bn::<u32, 1>::from(u32::max_value());
829 assert_eq!(f.array, [4294967295]);
830 }
831
832 #[test]
833 fn testsimple() {
834 assert_eq!(Bn::<u8, 8>::new(), Bn::<u8, 8>::new());
835
836 assert_eq!(Bn::<u8, 8>::from_u8(3).unwrap().to_u32(), Some(3));
837 assert_eq!(Bn::<u16, 4>::from_u8(3).unwrap().to_u32(), Some(3));
838 assert_eq!(Bn::<u32, 2>::from_u8(3).unwrap().to_u32(), Some(3));
839 assert_eq!(Bn::<u32, 2>::from_u64(3).unwrap().to_u32(), Some(3));
840 assert_eq!(Bn::<u8, 8>::from_u64(255).unwrap().to_u32(), Some(255));
841 assert_eq!(Bn::<u8, 8>::from_u64(256).unwrap().to_u32(), Some(256));
842 assert_eq!(Bn::<u8, 8>::from_u64(65536).unwrap().to_u32(), Some(65536));
843 }
844 #[test]
845 fn testfrom() {
846 let mut n1 = Bn::<u8, 8>::new();
847 n1.array[0] = 1;
848 assert_eq!(Some(1), n1.to_u32());
849 n1.array[1] = 1;
850 assert_eq!(Some(257), n1.to_u32());
851
852 let mut n2 = Bn::<u16, 8>::new();
853 n2.array[0] = 0xffff;
854 assert_eq!(Some(65535), n2.to_u32());
855 n2.array[0] = 0x0;
856 n2.array[2] = 0x1;
857 assert_eq!(None, n2.to_u32());
859 assert_eq!(Some(0x100000000), n2.to_u64());
860 }
861
862 #[test]
863 fn test_from_str_bitlengths() {
864 let test_s64 = "81906f5e4d3c2c01";
865 let test_u64: u64 = 0x81906f5e4d3c2c01;
866 let bb = Bn8::from_str_radix(test_s64, 16).unwrap();
867 let cc = Bn8::from_u64(test_u64).unwrap();
868 assert_eq!(cc.array, [0x01, 0x2c, 0x3c, 0x4d, 0x5e, 0x6f, 0x90, 0x81]);
869 assert_eq!(bb.array, [0x01, 0x2c, 0x3c, 0x4d, 0x5e, 0x6f, 0x90, 0x81]);
870 let dd = Bn16::from_u64(test_u64).unwrap();
871 let ff = Bn16::from_str_radix(test_s64, 16).unwrap();
872 assert_eq!(dd.array, [0x2c01, 0x4d3c, 0x6f5e, 0x8190]);
873 assert_eq!(ff.array, [0x2c01, 0x4d3c, 0x6f5e, 0x8190]);
874 let ee = Bn32::from_u64(test_u64).unwrap();
875 let gg = Bn32::from_str_radix(test_s64, 16).unwrap();
876 assert_eq!(ee.array, [0x4d3c2c01, 0x81906f5e]);
877 assert_eq!(gg.array, [0x4d3c2c01, 0x81906f5e]);
878 }
879
880 #[test]
881 fn test_from_str_stringlengths() {
882 let ab = Bn::<u8, 9>::from_str_radix("2281906f5e4d3c2c01", 16).unwrap();
883 assert_eq!(
884 ab.array,
885 [0x01, 0x2c, 0x3c, 0x4d, 0x5e, 0x6f, 0x90, 0x81, 0x22]
886 );
887 assert_eq!(
888 [0x2c01, 0x4d3c, 0x6f5e, 0],
889 Bn::<u16, 4>::from_str_radix("6f5e4d3c2c01", 16)
890 .unwrap()
891 .array
892 );
893 assert_eq!(
894 [0x2c01, 0x4d3c, 0x6f5e, 0x190],
895 Bn::<u16, 4>::from_str_radix("1906f5e4d3c2c01", 16)
896 .unwrap()
897 .array
898 );
899 assert_eq!(
900 Err(make_overflow_err()),
901 Bn::<u16, 4>::from_str_radix("f81906f5e4d3c2c01", 16)
902 );
903 assert_eq!(
904 Err(make_overflow_err()),
905 Bn::<u16, 4>::from_str_radix("af81906f5e4d3c2c01", 16)
906 );
907 assert_eq!(
908 Err(make_overflow_err()),
909 Bn::<u16, 4>::from_str_radix("baaf81906f5e4d3c2c01", 16)
910 );
911 let ac = Bn::<u16, 5>::from_str_radix("baaf81906f5e4d3c2c01", 16).unwrap();
912 assert_eq!(ac.array, [0x2c01, 0x4d3c, 0x6f5e, 0x8190, 0xbaaf]);
913 }
914
915 #[test]
916 fn test_bit_length() {
917 assert_eq!(0, Bn8::from_u8(0).unwrap().bit_length());
918 assert_eq!(1, Bn8::from_u8(1).unwrap().bit_length());
919 assert_eq!(2, Bn8::from_u8(2).unwrap().bit_length());
920 assert_eq!(2, Bn8::from_u8(3).unwrap().bit_length());
921 assert_eq!(7, Bn8::from_u8(0x70).unwrap().bit_length());
922 assert_eq!(8, Bn8::from_u8(0xF0).unwrap().bit_length());
923 assert_eq!(9, Bn8::from_u16(0x1F0).unwrap().bit_length());
924
925 assert_eq!(20, Bn8::from_u64(990223).unwrap().bit_length());
926 assert_eq!(32, Bn8::from_u64(0xefffffff).unwrap().bit_length());
927 assert_eq!(32, Bn8::from_u64(0x8fffffff).unwrap().bit_length());
928 assert_eq!(31, Bn8::from_u64(0x7fffffff).unwrap().bit_length());
929 assert_eq!(34, Bn8::from_u64(0x3ffffffff).unwrap().bit_length());
930
931 assert_eq!(0, Bn32::from_u8(0).unwrap().bit_length());
932 assert_eq!(1, Bn32::from_u8(1).unwrap().bit_length());
933 assert_eq!(2, Bn32::from_u8(2).unwrap().bit_length());
934 assert_eq!(2, Bn32::from_u8(3).unwrap().bit_length());
935 assert_eq!(7, Bn32::from_u8(0x70).unwrap().bit_length());
936 assert_eq!(8, Bn32::from_u8(0xF0).unwrap().bit_length());
937 assert_eq!(9, Bn32::from_u16(0x1F0).unwrap().bit_length());
938
939 assert_eq!(20, Bn32::from_u64(990223).unwrap().bit_length());
940 assert_eq!(32, Bn32::from_u64(0xefffffff).unwrap().bit_length());
941 assert_eq!(32, Bn32::from_u64(0x8fffffff).unwrap().bit_length());
942 assert_eq!(31, Bn32::from_u64(0x7fffffff).unwrap().bit_length());
943 assert_eq!(34, Bn32::from_u64(0x3ffffffff).unwrap().bit_length());
944 }
945
946 #[test]
947 fn test_bit_length_1000() {
948 let value = Bn32::from_u16(1000).unwrap();
950
951 assert_eq!(value.to_u32().unwrap(), 1000);
954 assert_eq!(value.bit_length(), 10);
955
956 assert_eq!(Bn32::from_u16(512).unwrap().bit_length(), 10); assert_eq!(Bn32::from_u16(1023).unwrap().bit_length(), 10); assert_eq!(Bn32::from_u16(1024).unwrap().bit_length(), 11); assert_eq!(Bn8::from_u16(1000).unwrap().bit_length(), 10);
963 assert_eq!(Bn16::from_u16(1000).unwrap().bit_length(), 10);
964
965 let value_from_str = Bn32::from_str_radix("1000", 10).unwrap();
967 assert_eq!(value_from_str.bit_length(), 10);
968
969 let value_from_bytes = Bn32::from_le_bytes(&1000u16.to_le_bytes());
971 assert_eq!(
973 value_from_bytes.to_u32().unwrap_or(0),
974 1000,
975 "from_le_bytes didn't create the correct value"
976 );
977 assert_eq!(value_from_bytes.bit_length(), 10);
978 }
979 #[test]
980 fn test_cmp() {
981 let f0 = Bn8::zero();
982 let f1 = Bn8::zero();
983 let f2 = Bn8::one();
984 assert_eq!(f0, f1);
985 assert!(f2 > f0);
986 assert!(f0 < f2);
987 let f3 = Bn32::from_u64(990223).unwrap();
988 assert_eq!(f3, Bn32::from_u64(990223).unwrap());
989 let f4 = Bn32::from_u64(990224).unwrap();
990 assert!(f4 > Bn32::from_u64(990223).unwrap());
991
992 let f3 = Bn8::from_u64(990223).unwrap();
993 assert_eq!(f3, Bn8::from_u64(990223).unwrap());
994 let f4 = Bn8::from_u64(990224).unwrap();
995 assert!(f4 > Bn8::from_u64(990223).unwrap());
996 }
997
998 #[test]
999 fn test_le_be_bytes() {
1000 let le_bytes = [1, 2, 3, 4];
1001 let be_bytes = [4, 3, 2, 1];
1002 let u8_ver = FixedUInt::<u8, 4>::from_le_bytes(&le_bytes);
1003 let u16_ver = FixedUInt::<u16, 2>::from_le_bytes(&le_bytes);
1004 let u32_ver = FixedUInt::<u32, 1>::from_le_bytes(&le_bytes);
1005 let u8_ver_be = FixedUInt::<u8, 4>::from_be_bytes(&be_bytes);
1006 let u16_ver_be = FixedUInt::<u16, 2>::from_be_bytes(&be_bytes);
1007 let u32_ver_be = FixedUInt::<u32, 1>::from_be_bytes(&be_bytes);
1008
1009 assert_eq!(u8_ver.array, [1, 2, 3, 4]);
1010 assert_eq!(u16_ver.array, [0x0201, 0x0403]);
1011 assert_eq!(u32_ver.array, [0x04030201]);
1012 assert_eq!(u8_ver_be.array, [1, 2, 3, 4]);
1013 assert_eq!(u16_ver_be.array, [0x0201, 0x0403]);
1014 assert_eq!(u32_ver_be.array, [0x04030201]);
1015
1016 let mut output_buffer = [0u8; 16];
1017 assert_eq!(u8_ver.to_le_bytes(&mut output_buffer).unwrap(), &le_bytes);
1018 assert_eq!(u8_ver.to_be_bytes(&mut output_buffer).unwrap(), &be_bytes);
1019 assert_eq!(u16_ver.to_le_bytes(&mut output_buffer).unwrap(), &le_bytes);
1020 assert_eq!(u16_ver.to_be_bytes(&mut output_buffer).unwrap(), &be_bytes);
1021 assert_eq!(u32_ver.to_le_bytes(&mut output_buffer).unwrap(), &le_bytes);
1022 assert_eq!(u32_ver.to_be_bytes(&mut output_buffer).unwrap(), &be_bytes);
1023 }
1024
1025 #[test]
1027 fn test_div_impl_equivalence_small() {
1028 type TestInt = FixedUInt<u8, 2>;
1029
1030 let test_cases = [
1032 (20u16, 3u16, 6u16), (100u16, 7u16, 14u16), (255u16, 5u16, 51u16), (65535u16, 256u16, 255u16), ];
1037
1038 for (dividend_val, divisor_val, expected) in test_cases {
1039 let dividend = TestInt::from(dividend_val);
1040 let divisor = TestInt::from(divisor_val);
1041 let expected_result = TestInt::from(expected);
1042
1043 let result = TestInt::div_impl(÷nd, &divisor);
1044
1045 assert_eq!(
1046 result, expected_result,
1047 "Division failed for {} / {} = {}",
1048 dividend_val, divisor_val, expected
1049 );
1050 }
1051 }
1052
1053 #[test]
1054 fn test_div_impl_equivalence_edge_cases() {
1055 type TestInt = FixedUInt<u16, 2>;
1056
1057 let dividend = TestInt::from(1000u16);
1059 let divisor = TestInt::from(1u16);
1060 assert_eq!(
1061 TestInt::div_impl(÷nd, &divisor),
1062 TestInt::from(1000u16)
1063 );
1064
1065 let dividend = TestInt::from(42u16);
1067 let divisor = TestInt::from(42u16);
1068 assert_eq!(TestInt::div_impl(÷nd, &divisor), TestInt::from(1u16));
1069
1070 let dividend = TestInt::from(5u16);
1072 let divisor = TestInt::from(10u16);
1073 assert_eq!(TestInt::div_impl(÷nd, &divisor), TestInt::from(0u16));
1074
1075 let dividend = TestInt::from(1024u16);
1077 let divisor = TestInt::from(4u16);
1078 assert_eq!(
1079 TestInt::div_impl(÷nd, &divisor),
1080 TestInt::from(256u16)
1081 );
1082 }
1083
1084 #[test]
1085 fn test_helper_methods() {
1086 type TestInt = FixedUInt<u8, 2>;
1087
1088 let mut val = TestInt::zero();
1090 val.set_bit(0);
1091 assert_eq!(val, TestInt::from(1u8));
1092
1093 val.set_bit(8);
1094 assert_eq!(val, TestInt::from(257u16)); let a = TestInt::from(8u8); let b = TestInt::from(1u8); assert_eq!(a.cmp_shifted(&b, 3), core::cmp::Ordering::Equal);
1102
1103 assert_eq!(a.cmp_shifted(&b, 2), core::cmp::Ordering::Greater);
1105
1106 assert_eq!(a.cmp_shifted(&b, 4), core::cmp::Ordering::Less);
1108
1109 let mut val = TestInt::from(10u8);
1111 val.sub_shifted(&TestInt::from(1u8), 2); assert_eq!(val, TestInt::from(6u8)); }
1114
1115 #[test]
1116 fn test_shifted_operations_comprehensive() {
1117 type TestInt = FixedUInt<u32, 2>;
1118
1119 let a = TestInt::from(0x12345678u32);
1121 let b = TestInt::from(0x12345678u32);
1122
1123 assert_eq!(a.cmp_shifted(&b, 0), core::cmp::Ordering::Equal);
1125
1126 let c = TestInt::from(0x123u32); let d = TestInt::from(0x48d159e2u32); assert_eq!(d.cmp_shifted(&c, 16), core::cmp::Ordering::Greater);
1132
1133 let e = TestInt::from(1u32);
1135 assert_eq!(
1136 e.cmp_shifted(&TestInt::from(0u32), 100),
1137 core::cmp::Ordering::Greater
1138 );
1139 assert_eq!(
1141 TestInt::from(0u32).cmp_shifted(&e, 100),
1142 core::cmp::Ordering::Equal
1143 );
1144
1145 let mut val = TestInt::from(0x10000u32); val.sub_shifted(&TestInt::from(1u32), 15); assert_eq!(val, TestInt::from(0x8000u32)); let mut big_val = TestInt::from(0x100000000u64); big_val.sub_shifted(&TestInt::from(1u32), 31); assert_eq!(big_val, TestInt::from(0x80000000u64)); }
1155
1156 #[test]
1157 fn test_shifted_operations_edge_cases() {
1158 type TestInt = FixedUInt<u32, 2>;
1159
1160 let a = TestInt::from(42u32);
1162 assert_eq!(
1163 a.cmp_shifted(&TestInt::from(42u32), 0),
1164 core::cmp::Ordering::Equal
1165 );
1166
1167 let mut b = TestInt::from(42u32);
1168 b.sub_shifted(&TestInt::from(10u32), 0);
1169 assert_eq!(b, TestInt::from(32u32));
1170
1171 let c = TestInt::from(123u32);
1173 assert_eq!(
1174 c.cmp_shifted(&TestInt::from(456u32), 200),
1175 core::cmp::Ordering::Greater
1176 );
1177
1178 let mut d = TestInt::from(123u32);
1179 d.sub_shifted(&TestInt::from(456u32), 200); assert_eq!(d, TestInt::from(123u32));
1181
1182 let zero = TestInt::from(0u32);
1184 assert_eq!(zero.cmp_shifted(&zero, 10), core::cmp::Ordering::Equal);
1185 assert_eq!(
1186 TestInt::from(1u32).cmp_shifted(&zero, 10),
1187 core::cmp::Ordering::Greater
1188 );
1189 }
1190
1191 #[test]
1192 fn test_shifted_operations_equivalence() {
1193 type TestInt = FixedUInt<u32, 2>;
1194
1195 let test_cases = [
1197 (0x12345u32, 0x678u32, 4),
1198 (0x1000u32, 0x10u32, 8),
1199 (0xABCDu32, 0x1u32, 16),
1200 (0x80000000u32, 0x1u32, 1),
1201 ];
1202
1203 for (a_val, b_val, shift) in test_cases {
1204 let a = TestInt::from(a_val);
1205 let b = TestInt::from(b_val);
1206
1207 let optimized_cmp = a.cmp_shifted(&b, shift);
1209 let naive_cmp = a.cmp(&(b << shift));
1210 assert_eq!(
1211 optimized_cmp, naive_cmp,
1212 "cmp_shifted mismatch: {} vs ({} << {})",
1213 a_val, b_val, shift
1214 );
1215
1216 if a >= (b << shift) {
1218 let mut optimized_result = a;
1219 optimized_result.sub_shifted(&b, shift);
1220
1221 let naive_result = a - (b << shift);
1222 assert_eq!(
1223 optimized_result, naive_result,
1224 "sub_shifted mismatch: {} - ({} << {})",
1225 a_val, b_val, shift
1226 );
1227 }
1228 }
1229 }
1230
1231 #[test]
1232 fn test_div_assign_in_place_optimization() {
1233 type TestInt = FixedUInt<u32, 2>;
1234
1235 let test_cases = [
1237 (100u32, 10u32, 10u32, 0u32), (123u32, 7u32, 17u32, 4u32), (1000u32, 13u32, 76u32, 12u32), (65535u32, 255u32, 257u32, 0u32), ];
1242
1243 for (dividend_val, divisor_val, expected_quotient, expected_remainder) in test_cases {
1244 let mut dividend = TestInt::from(dividend_val);
1246 let divisor = TestInt::from(divisor_val);
1247
1248 dividend /= divisor;
1249 assert_eq!(
1250 dividend,
1251 TestInt::from(expected_quotient),
1252 "div_assign: {} / {} should be {}",
1253 dividend_val,
1254 divisor_val,
1255 expected_quotient
1256 );
1257
1258 let mut dividend2 = TestInt::from(dividend_val);
1260 let remainder = TestInt::div_assign_impl(&mut dividend2, &divisor);
1261 assert_eq!(
1262 dividend2,
1263 TestInt::from(expected_quotient),
1264 "div_assign_impl quotient: {} / {} should be {}",
1265 dividend_val,
1266 divisor_val,
1267 expected_quotient
1268 );
1269 assert_eq!(
1270 remainder,
1271 TestInt::from(expected_remainder),
1272 "div_assign_impl remainder: {} % {} should be {}",
1273 dividend_val,
1274 divisor_val,
1275 expected_remainder
1276 );
1277
1278 assert_eq!(
1280 dividend2 * divisor + remainder,
1281 TestInt::from(dividend_val),
1282 "Property check failed for {}",
1283 dividend_val
1284 );
1285 }
1286 }
1287
1288 #[test]
1289 fn test_div_assign_stack_efficiency() {
1290 type TestInt = FixedUInt<u32, 4>; let mut dividend = TestInt::from(0x123456789ABCDEFu64);
1294 let divisor = TestInt::from(0x12345u32);
1295 let original_dividend = dividend;
1296
1297 dividend /= divisor;
1299
1300 let remainder = original_dividend % divisor;
1302 assert_eq!(dividend * divisor + remainder, original_dividend);
1303 }
1304
1305 #[test]
1306 fn test_rem_assign_optimization() {
1307 type TestInt = FixedUInt<u32, 2>;
1308
1309 let test_cases = [
1310 (100u32, 10u32, 0u32), (123u32, 7u32, 4u32), (1000u32, 13u32, 12u32), (65535u32, 255u32, 0u32), ];
1315
1316 for (dividend_val, divisor_val, expected_remainder) in test_cases {
1317 let mut dividend = TestInt::from(dividend_val);
1318 let divisor = TestInt::from(divisor_val);
1319
1320 dividend %= divisor;
1321 assert_eq!(
1322 dividend,
1323 TestInt::from(expected_remainder),
1324 "rem_assign: {} % {} should be {}",
1325 dividend_val,
1326 divisor_val,
1327 expected_remainder
1328 );
1329 }
1330 }
1331
1332 #[test]
1333 fn test_div_impl_forwarding() {
1334 type TestInt = FixedUInt<u32, 2>;
1335
1336 let test_cases = [
1338 (100u32, 10u32, 10u32), (123u32, 7u32, 17u32), (1000u32, 13u32, 76u32), (65535u32, 255u32, 257u32), ];
1343
1344 for (dividend_val, divisor_val, expected_quotient) in test_cases {
1345 let dividend = TestInt::from(dividend_val);
1346 let divisor = TestInt::from(divisor_val);
1347
1348 let quotient = dividend / divisor;
1350 assert_eq!(
1351 quotient,
1352 TestInt::from(expected_quotient),
1353 "div_impl forwarding: {} / {} should be {}",
1354 dividend_val,
1355 divisor_val,
1356 expected_quotient
1357 );
1358
1359 let remainder = dividend % divisor;
1361 assert_eq!(
1362 quotient * divisor + remainder,
1363 dividend,
1364 "Division property check failed for {}",
1365 dividend_val
1366 );
1367 }
1368 }
1369
1370 #[test]
1371 fn test_code_simplification_benefits() {
1372 type TestInt = FixedUInt<u32, 2>;
1373
1374 let dividend = TestInt::from(12345u32);
1376 let divisor = TestInt::from(67u32);
1377 let quotient = dividend / divisor;
1378 let remainder = dividend % divisor;
1379
1380 assert_eq!(quotient * divisor + remainder, dividend);
1382 }
1383
1384 #[test]
1385 fn test_rem_assign_correctness_after_fix() {
1386 type TestInt = FixedUInt<u32, 2>;
1387
1388 let mut a = TestInt::from(17u32);
1390 let b = TestInt::from(5u32);
1391
1392 a %= b;
1395 assert_eq!(a, TestInt::from(2u32), "17 % 5 should be 2");
1396
1397 let mut test_val = TestInt::from(100u32);
1399 test_val %= TestInt::from(7u32);
1400 assert_eq!(
1401 test_val,
1402 TestInt::from(2u32),
1403 "100 % 7 should be 2 (not 14, the quotient)"
1404 );
1405 }
1406
1407 #[test]
1408 fn test_div_property_based() {
1409 type TestInt = FixedUInt<u16, 2>;
1410
1411 let test_pairs = [
1413 (12345u16, 67u16),
1414 (1000u16, 13u16),
1415 (65535u16, 255u16),
1416 (5000u16, 7u16),
1417 ];
1418
1419 for (dividend_val, divisor_val) in test_pairs {
1420 let dividend = TestInt::from(dividend_val);
1421 let divisor = TestInt::from(divisor_val);
1422
1423 let quotient = TestInt::div_impl(÷nd, &divisor);
1424
1425 let remainder = dividend - (quotient * divisor);
1427 let reconstructed = quotient * divisor + remainder;
1428
1429 assert_eq!(
1430 reconstructed,
1431 dividend,
1432 "Property failed for {} / {}: {} * {} + {} != {}",
1433 dividend_val,
1434 divisor_val,
1435 quotient.to_u32().unwrap_or(0),
1436 divisor_val,
1437 remainder.to_u32().unwrap_or(0),
1438 dividend_val
1439 );
1440
1441 assert!(
1443 remainder < divisor,
1444 "Remainder {} >= divisor {} for {} / {}",
1445 remainder.to_u32().unwrap_or(0),
1446 divisor_val,
1447 dividend_val,
1448 divisor_val
1449 );
1450 }
1451 }
1452}