safe_bigmath/
integer.rs

1extern crate alloc;
2
3#[cfg(not(feature = "std"))]
4use alloc::vec;
5use core::{cmp::Ordering, fmt::Display, ops::*, str::FromStr};
6use num_bigint::{BigInt, BigUint, Sign};
7use num_integer::Integer;
8use num_traits::{One, Signed, ToPrimitive, Zero};
9use quoth::Parsable;
10
11#[cfg(test)]
12use alloc::format;
13use alloc::vec::Vec;
14use lencode::dedupe::{DedupeDecoder, DedupeEncoder};
15#[cfg(test)]
16use lencode::io::Cursor;
17use lencode::io::{Error, Read, Write};
18use lencode::{Decode, Encode};
19#[cfg(test)]
20use std::time::{Duration, Instant};
21
22use crate::parsing::ParsedSafeInt;
23
24/// Arbitrary-precision integer wrapper that exposes safe, non-panicking operations.
25///
26/// # Examples
27/// Create values from primitives and perform safe division (returns `Option` to avoid panics):
28/// ```
29/// use safe_bigmath::SafeInt;
30///
31/// let a = SafeInt::from(10);
32/// let b = SafeInt::from(3);
33/// assert_eq!((&a / &b).unwrap(), SafeInt::from(3));
34/// assert_eq!(&a + &b, SafeInt::from(13));
35/// assert_eq!(SafeInt::from(5) / SafeInt::from(0), None);
36/// ```
37#[derive(Clone, Debug, Eq, Ord, Hash, Default, PartialEq, PartialOrd)]
38#[repr(transparent)]
39pub struct SafeInt(BigInt);
40
41/// Default iteration cap for the fixed-point approximation used by `pow_ratio_scaled` when
42/// large exponents require the fallback path.
43pub const DEFAULT_MAX_ITERS: usize = 4_096;
44const MAX_EXACT_EXPONENT: u32 = 1_024;
45
46impl FromStr for SafeInt {
47    type Err = quoth::Error;
48
49    fn from_str(s: &str) -> Result<Self, Self::Err> {
50        let mut stream = quoth::ParseStream::from(s);
51        let parsed = ParsedSafeInt::parse(&mut stream)?;
52        Ok(parsed.value)
53    }
54}
55
56impl Display for SafeInt {
57    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58        write!(f, "{}", self.0)
59    }
60}
61
62impl SafeInt {
63    /// Zero value.
64    pub fn zero() -> SafeInt {
65        SafeInt(BigInt::zero())
66    }
67    /// One value.
68    pub fn one() -> SafeInt {
69        SafeInt(BigInt::one())
70    }
71    /// Negative one value.
72    pub fn neg_one() -> SafeInt {
73        -SafeInt::one()
74    }
75    /// Constant one value as a compile-time byte representation.
76    pub const ONE: ConstSafeInt<2> = ConstSafeInt::from_bytes([0, 1]);
77    /// Constant negative one value as a compile-time byte representation.
78    pub const NEG_ONE: ConstSafeInt<2> = ConstSafeInt::from_bytes([1, 1]);
79
80    /// Returns the underlying `BigInt` reference.
81    #[inline(always)]
82    pub const fn raw(&self) -> &BigInt {
83        &self.0
84    }
85
86    /// Constructs a `SafeInt` from a raw `BigInt`.
87    #[inline(always)]
88    pub const fn from_raw(value: BigInt) -> SafeInt {
89        SafeInt(value)
90    }
91
92    /// Returns `true` if the value is negative.
93    #[inline(always)]
94    pub fn is_negative(&self) -> bool {
95        self.0.sign() == Sign::Minus
96    }
97
98    /// Returns `true` if the value is evenly divisible by 2.
99    #[inline(always)]
100    pub fn is_even(&self) -> bool {
101        self.0.is_even()
102    }
103
104    /// Returns `true` if the value is not evenly divisible by 2.
105    #[inline(always)]
106    pub fn is_odd(&self) -> bool {
107        self.0.is_odd()
108    }
109
110    /// Returns `true` if the value is exactly zero.
111    #[inline(always)]
112    pub fn is_zero(&self) -> bool {
113        self.0.is_zero()
114    }
115
116    /// Returns the absolute value.
117    #[inline(always)]
118    pub fn abs(self) -> SafeInt {
119        SafeInt(self.0.abs())
120    }
121
122    /// Raises the number to an unsigned integer power.
123    #[inline(always)]
124    pub fn pow(self, exp: u32) -> SafeInt {
125        SafeInt(self.0.pow(exp))
126    }
127
128    /// Computes quotient and remainder simultaneously.
129    /// Returns `None` if `other` is zero.
130    #[inline(always)]
131    pub fn div_rem(self, other: SafeInt) -> Option<(SafeInt, SafeInt)> {
132        if other.0.is_zero() {
133            None
134        } else {
135            let (div, rem) = self.0.div_rem(&other.0);
136            Some((SafeInt(div), SafeInt(rem)))
137        }
138    }
139
140    /// Converts to `u8` if the value fits.
141    #[inline(always)]
142    pub fn to_u8(&self) -> Option<u8> {
143        self.0.to_u8()
144    }
145
146    /// Converts to `u16` if the value fits.
147    #[inline(always)]
148    pub fn to_u16(&self) -> Option<u16> {
149        self.0.to_u16()
150    }
151
152    /// Converts to `u32` if the value fits.
153    #[inline(always)]
154    pub fn to_u32(&self) -> Option<u32> {
155        self.0.to_u32()
156    }
157
158    /// Converts to `u64` if the value fits.
159    #[inline(always)]
160    pub fn to_u64(&self) -> Option<u64> {
161        self.0.to_u64()
162    }
163
164    /// Converts to `u128` if the value fits.
165    #[inline(always)]
166    pub fn to_u128(&self) -> Option<u128> {
167        self.0.to_u128()
168    }
169
170    /// Converts to `i8` if the value fits.
171    #[inline(always)]
172    pub fn to_i8(&self) -> Option<i8> {
173        self.0.to_i8()
174    }
175
176    /// Converts to `i16` if the value fits.
177    #[inline(always)]
178    pub fn to_i16(&self) -> Option<i16> {
179        self.0.to_i16()
180    }
181
182    /// Converts to `i32` if the value fits.
183    #[inline(always)]
184    pub fn to_i32(&self) -> Option<i32> {
185        self.0.to_i32()
186    }
187
188    /// Converts to `i64` if the value fits.
189    #[inline(always)]
190    pub fn to_i64(&self) -> Option<i64> {
191        self.0.to_i64()
192    }
193
194    /// Converts to `i128` if the value fits.
195    #[inline(always)]
196    pub fn to_i128(&self) -> Option<i128> {
197        self.0.to_i128()
198    }
199
200    /// Converts to `usize` if the value fits.
201    #[inline(always)]
202    pub fn to_usize(&self) -> Option<usize> {
203        self.0.to_usize()
204    }
205
206    /// Converts to `isize` if the value fits.
207    #[inline(always)]
208    pub fn to_isize(&self) -> Option<isize> {
209        self.0.to_isize()
210    }
211
212    /// Performs integer ceiling division (`self / b`, rounded up).
213    #[inline(always)]
214    pub fn ceil_div(&self, b: SafeInt) -> Option<SafeInt> {
215        let one = SafeInt::from(1);
216        Some(((self - one.clone()) / b)? + one)
217    }
218
219    /// Computes `(base_numerator / base_denominator)^(exponent_numerator / exponent_denominator)`
220    /// scaled by the provided factor. Returns `None` if the base or exponent denominator is zero
221    /// or if the base is non-positive. Uses an exact integer path when the exponent fits in 32
222    /// bits and is below `MAX_EXACT_EXPONENT`, and falls back to a fixed-point approximation with
223    /// the requested precision otherwise.
224    /// The fallback uses `DEFAULT_MAX_ITERS` as its iteration cap and stops earlier once rounded
225    /// digits converge.
226    ///
227    /// # Examples
228    /// ```rust
229    /// use safe_bigmath::SafeInt;
230    ///
231    /// // (2 / 3) ^ (1 / 2) * 1000 (approx) => 816 when floored
232    /// let result = SafeInt::pow_ratio_scaled(
233    ///     &SafeInt::from(2),
234    ///     &SafeInt::from(3),
235    ///     &SafeInt::from(1),
236    ///     &SafeInt::from(2),
237    ///     0,
238    ///     &SafeInt::from(1_000),
239    /// )
240    /// .unwrap();
241    /// assert_eq!(result, SafeInt::from(816));
242    /// ```
243    pub fn pow_ratio_scaled(
244        base_numerator: &SafeInt,
245        base_denominator: &SafeInt,
246        exponent_numerator: &SafeInt,
247        exponent_denominator: &SafeInt,
248        precision: u32,
249        scale: &SafeInt,
250    ) -> Option<SafeInt> {
251        Self::pow_ratio_scaled_with_max_iters(
252            base_numerator,
253            base_denominator,
254            exponent_numerator,
255            exponent_denominator,
256            precision,
257            scale,
258            None,
259        )
260    }
261
262    /// Same as [`pow_ratio_scaled`] but allows specifying a maximum iteration cap for the
263    /// fixed-point approximation path. When `None`, `DEFAULT_MAX_ITERS` is used. The approximation
264    /// still exits early when rounded digits converge.
265    pub fn pow_ratio_scaled_with_max_iters(
266        base_numerator: &SafeInt,
267        base_denominator: &SafeInt,
268        exponent_numerator: &SafeInt,
269        exponent_denominator: &SafeInt,
270        precision: u32,
271        scale: &SafeInt,
272        max_iters: Option<usize>,
273    ) -> Option<SafeInt> {
274        if base_denominator.is_zero() || exponent_denominator.is_zero() {
275            return None;
276        }
277        if base_numerator.is_zero() {
278            return Some(SafeInt::zero());
279        }
280        if scale.is_negative() {
281            return None;
282        }
283        // Restrict to positive base
284        if base_numerator.is_negative() || base_denominator.is_negative() {
285            return None;
286        }
287
288        let base_num = base_numerator.0.to_biguint()?;
289        let base_den = base_denominator.0.to_biguint()?;
290        let mut exp_num = exponent_numerator.0.to_biguint()?;
291        let mut exp_den = exponent_denominator.0.to_biguint()?;
292
293        if exp_num.is_zero() {
294            return Some(scale.clone());
295        }
296
297        let g = gcd_biguint(exp_num.clone(), exp_den.clone());
298        if g > BigUint::one() {
299            exp_num /= g.clone();
300            exp_den /= g;
301        }
302
303        let scale_abs = scale.0.to_biguint()?;
304        let scale_bits = u32::try_from(scale_abs.bits()).unwrap_or(u32::MAX);
305
306        let exp_num_bits = exp_num.bits();
307        let exp_den_bits = exp_den.bits();
308        if exp_num_bits <= 32 && exp_den_bits <= 32 {
309            let exp_num_u32 = exp_num.to_u32()?;
310            let exp_den_u32 = exp_den.to_u32()?;
311            if exp_den_u32 == 0 {
312                return None;
313            }
314
315            if exp_num_u32 <= MAX_EXACT_EXPONENT && exp_den_u32 <= MAX_EXACT_EXPONENT {
316                let base_num_pow = base_num.pow(exp_num_u32);
317                let base_den_pow = base_den.pow(exp_num_u32);
318                let scale_pow = scale_abs.pow(exp_den_u32);
319
320                let target_num = base_num_pow * scale_pow;
321                let target_den = base_den_pow;
322
323                let root = nth_root_ratio_floor(&target_num, &target_den, exp_den_u32);
324                return Some(SafeInt(BigInt::from_biguint(Sign::Plus, root)));
325            }
326        }
327
328        // Fallback path for large exponents: approximate using fixed-point log/exp with guard bits.
329        // Allow arbitrarily high requested precision (callers can cap via `max_iters`); enforce
330        // only a reasonable floor to keep the series stable.
331        // Increase the minimum precision based on the magnitude of `scale` so that even when
332        // callers request coarse precision, we retain enough fractional bits to keep the final
333        // scaled integer accurate.
334        let requested_precision = precision.max(32).max(scale_bits.saturating_add(8));
335        let guard_bits: u32 = 24;
336        let internal_precision = requested_precision.saturating_add(guard_bits);
337        let default_max_iters = DEFAULT_MAX_ITERS.min(internal_precision as usize + 128);
338        let max_iters = max_iters.unwrap_or(default_max_iters).max(1);
339
340        let target_scale_uint = BigUint::one() << requested_precision;
341        let guard_factor_uint = BigUint::one() << guard_bits;
342        let internal_scale_uint = &target_scale_uint << guard_bits;
343
344        let target_scale = BigInt::from_biguint(Sign::Plus, target_scale_uint.clone());
345        let guard_factor = BigInt::from_biguint(Sign::Plus, guard_factor_uint.clone());
346        let internal_scale = BigInt::from_biguint(Sign::Plus, internal_scale_uint.clone());
347
348        let ln_half = ln1p_fixed(
349            &(-(&internal_scale >> 1usize)),
350            &internal_scale,
351            &guard_factor,
352            max_iters,
353        );
354        let ln_two = -ln_half;
355
356        // Compute ln(base_num) - ln(base_den) using normalized mantissas near 1.0 for better
357        // convergence, regardless of how small or large the ratio is.
358        let ln_num = ln_biguint(
359            &base_num,
360            internal_precision,
361            &internal_scale_uint,
362            &internal_scale,
363            &guard_factor,
364            &ln_two,
365            max_iters,
366        );
367        let ln_den = ln_biguint(
368            &base_den,
369            internal_precision,
370            &internal_scale_uint,
371            &internal_scale,
372            &guard_factor,
373            &ln_two,
374            max_iters,
375        );
376        let ln_base = ln_num - ln_den;
377
378        let ln_scaled = (ln_base * BigInt::from_biguint(Sign::Plus, exp_num))
379            .div_floor(&BigInt::from_biguint(Sign::Plus, exp_den));
380        let exp_fp = exp_fixed(&ln_scaled, &internal_scale, &guard_factor, max_iters);
381        let exp_requested = round_to_precision(&exp_fp, &guard_factor);
382        let result =
383            (exp_requested * BigInt::from_biguint(Sign::Plus, scale_abs)).div_floor(&target_scale);
384
385        Some(SafeInt(result))
386    }
387
388    /// Exponentiate base to exponent. Base can be large integer number betwen 0 and u64::MAX
389    /// Optimal exponent values are between 0.1 and 0.9
390    pub fn pow_bigint_base(
391        base: &SafeInt,
392        exponent_numerator: &SafeInt,
393        exponent_denominator: &SafeInt,
394        precision: u32,
395        scale: &SafeInt,
396    ) -> Option<SafeInt> {
397        Self::pow_bigint_base_scaled_with_max_iters(
398            base,
399            exponent_numerator,
400            exponent_denominator,
401            precision,
402            scale,
403            None,
404        )
405    }
406
407    fn pow_bigint_base_scaled_with_max_iters(
408        base: &SafeInt,
409        exponent_numerator: &SafeInt,
410        exponent_denominator: &SafeInt,
411        precision: u32,
412        scale: &SafeInt,
413        max_iters: Option<usize>,
414    ) -> Option<SafeInt> {
415        use num_bigint::{BigInt, BigUint, Sign};
416        use num_integer::Integer;
417        use num_traits::{One, ToPrimitive, Zero};
418
419        // Guard rails
420        if exponent_denominator.is_zero() {
421            return None;
422        }
423        if base.is_zero() {
424            // Keep the same semantics as pow_ratio_scaled_with_max_iters:
425            // 0^anything -> 0 (including 0^0).
426            return Some(SafeInt::zero());
427        }
428        if scale.is_negative() {
429            return None;
430        }
431        // Restrict to positive base
432        if base.is_negative() {
433            return None;
434        }
435
436        // base is an integer; convert to BigUint
437        let base_uint = base.0.to_biguint()?;
438
439        let mut exp_num = exponent_numerator.0.to_biguint()?;
440        let mut exp_den = exponent_denominator.0.to_biguint()?;
441
442        if exp_num.is_zero() {
443            // base^0 ~= 1, scaled by `scale`
444            return Some(scale.clone());
445        }
446
447        // Reduce exponent fraction exp_num/exp_den
448        let g = gcd_biguint(exp_num.clone(), exp_den.clone());
449        if g > BigUint::one() {
450            exp_num /= g.clone();
451            exp_den /= g;
452        }
453
454        let scale_abs = scale.0.to_biguint()?;
455        let scale_bits = u32::try_from(scale_abs.bits()).unwrap_or(u32::MAX);
456
457        // ---- Fast path: small rational exponent, exact pow/root on integers ----
458        let exp_num_bits = exp_num.bits();
459        let exp_den_bits = exp_den.bits();
460        if exp_num_bits <= 32 && exp_den_bits <= 32 {
461            let exp_num_u32 = exp_num.to_u32()?;
462            let exp_den_u32 = exp_den.to_u32()?;
463            if exp_den_u32 == 0 {
464                return None;
465            }
466
467            if exp_num_u32 <= MAX_EXACT_EXPONENT && exp_den_u32 <= MAX_EXACT_EXPONENT {
468                // base^(exp_num/exp_den) * scale
469                //
470                // Compute:
471                //   (base^exp_num * scale^exp_den)^(1/exp_den)
472                // via nth_root_ratio_floor, same as in ratio version but with
473                // denominator fixed to 1.
474                let base_pow = base_uint.pow(exp_num_u32);
475                let scale_pow = scale_abs.pow(exp_den_u32);
476
477                let target_num = base_pow * scale_pow;
478                let target_den = BigUint::one();
479
480                let root = nth_root_ratio_floor(&target_num, &target_den, exp_den_u32);
481                return Some(SafeInt(BigInt::from_biguint(Sign::Plus, root)));
482            }
483        }
484
485        // ---- Fallback path: fixed-point log/exp with guard bits ----
486
487        // Same heuristic as in pow_ratio_scaled_with_max_iters:
488        let requested_precision = precision.max(32).max(scale_bits.saturating_add(8));
489        let guard_bits: u32 = 24;
490        let internal_precision = requested_precision.saturating_add(guard_bits);
491        let default_max_iters = DEFAULT_MAX_ITERS.min(internal_precision as usize + 128);
492        let max_iters = max_iters.unwrap_or(default_max_iters).max(1);
493
494        let target_scale_uint = BigUint::one() << requested_precision;
495        let guard_factor_uint = BigUint::one() << guard_bits;
496        let internal_scale_uint = &target_scale_uint << guard_bits;
497
498        let target_scale = BigInt::from_biguint(Sign::Plus, target_scale_uint.clone());
499        let guard_factor = BigInt::from_biguint(Sign::Plus, guard_factor_uint.clone());
500        let internal_scale = BigInt::from_biguint(Sign::Plus, internal_scale_uint.clone());
501
502        // ln(2) via ln1p_fixed(-1/2)
503        let ln_half = ln1p_fixed(
504            &(-(&internal_scale >> 1usize)),
505            &internal_scale,
506            &guard_factor,
507            max_iters,
508        );
509        let ln_two = -ln_half;
510
511        // ln(base) using normalized mantissa (same helper as ratio version)
512        let ln_base = ln_biguint(
513            &base_uint,
514            internal_precision,
515            &internal_scale_uint,
516            &internal_scale,
517            &guard_factor,
518            &ln_two,
519            max_iters,
520        );
521
522        // ln(base) * exp_num / exp_den
523        let ln_scaled = (ln_base * BigInt::from_biguint(Sign::Plus, exp_num))
524            .div_floor(&BigInt::from_biguint(Sign::Plus, exp_den));
525
526        // exp(ln_scaled) in fixed-point
527        let exp_fp = exp_fixed(&ln_scaled, &internal_scale, &guard_factor, max_iters);
528
529        // Drop guard bits
530        let exp_requested = round_to_precision(&exp_fp, &guard_factor);
531
532        // Scale by `scale_abs` and rescale to integer
533        let result =
534            (exp_requested * BigInt::from_biguint(Sign::Plus, scale_abs)).div_floor(&target_scale);
535
536        Some(SafeInt(result))
537    }
538
539    /// Calculates integer part of log10 of this SafeInt
540    #[inline(always)]
541    pub fn log10(
542        &self,
543        scale: &SafeInt,
544        precision: u32,
545        max_iters: Option<usize>,
546    ) -> Option<SafeInt> {
547        if self.is_negative() || self.is_zero() {
548            None
549        } else if *self < 10 {
550            Some(SafeInt::from(0))
551        } else {
552            let scale_abs = scale.0.to_biguint()?;
553            let scale_bits = u32::try_from(scale_abs.bits()).unwrap_or(u32::MAX);
554            let requested_precision = precision.max(32).max(scale_bits.saturating_add(8));
555            let guard_bits: u32 = 24;
556            let internal_precision = requested_precision.saturating_add(guard_bits);
557            let target_scale_uint = BigUint::one() << requested_precision;
558            let internal_scale_uint = &target_scale_uint << guard_bits;
559            let guard_factor_uint = BigUint::one() << guard_bits;
560            let guard_factor = BigInt::from_biguint(Sign::Plus, guard_factor_uint.clone());
561            let internal_scale = BigInt::from_biguint(Sign::Plus, internal_scale_uint.clone());
562            let default_max_iters = DEFAULT_MAX_ITERS.min(internal_precision as usize + 128);
563            let max_iters = max_iters.unwrap_or(default_max_iters).max(1);
564            let ln_half = ln1p_fixed(
565                &(-(&internal_scale >> 1usize)),
566                &internal_scale,
567                &guard_factor,
568                max_iters,
569            );
570            let ln_two = -ln_half;
571
572            let value_uint = self.0.to_biguint()?;
573            let ln_value = ln_biguint(
574                &value_uint,
575                internal_precision,
576                &internal_scale_uint,
577                &internal_scale,
578                &guard_factor,
579                &ln_two,
580                max_iters,
581            );
582            let ten_uint = BigUint::from(10u32);
583            let ln_ten = ln_biguint(
584                &ten_uint,
585                internal_precision,
586                &internal_scale_uint,
587                &internal_scale,
588                &guard_factor,
589                &ln_two,
590                max_iters,
591            );
592
593            // Divide ln_value by ln_ten
594            let ln_value = SafeInt::from(ln_value);
595            let ln_ten = SafeInt::from(ln_ten);
596            ln_value / ln_ten
597        }
598    }
599}
600
601fn gcd_biguint(mut a: BigUint, mut b: BigUint) -> BigUint {
602    while !b.is_zero() {
603        let r = &a % &b;
604        a = b;
605        b = r;
606    }
607    a
608}
609
610fn pow_biguint(base: &BigUint, exp: u32) -> BigUint {
611    base.pow(exp)
612}
613
614fn nth_root_ratio_floor(target_num: &BigUint, target_den: &BigUint, q: u32) -> BigUint {
615    if q == 0 {
616        return BigUint::zero();
617    }
618
619    let mut low = BigUint::zero();
620    let mut high = BigUint::one();
621    while pow_biguint(&high, q) * target_den <= *target_num {
622        high <<= 1;
623    }
624
625    while low < high {
626        let mid = (&low + &high + 1u32) >> 1;
627        if pow_biguint(&mid, q) * target_den <= *target_num {
628            low = mid;
629        } else {
630            high = mid - BigUint::one();
631        }
632    }
633
634    low
635}
636
637fn ln1p_fixed(x_fp: &BigInt, scale: &BigInt, guard_factor: &BigInt, max_iters: usize) -> BigInt {
638    // Fixed-point natural log using the Taylor series for ln(1 + x), stopping once the rounded
639    // value at the target precision stops changing or the incremental term is below guard bits.
640    let mut term = x_fp.clone();
641    let mut result = term.clone();
642    let mut prev_rounded = round_to_precision(&result, guard_factor);
643    for n in 2..=max_iters {
644        term = (&term * x_fp).div_floor(scale);
645        if term.is_zero() {
646            break;
647        }
648
649        let next = term.div_floor(&BigInt::from(n as u32));
650        if next.is_zero() {
651            break;
652        }
653
654        if n % 2 == 0 {
655            result -= &next;
656        } else {
657            result += &next;
658        }
659
660        let rounded = round_to_precision(&result, guard_factor);
661        if next.abs() < guard_factor.abs() || rounded == prev_rounded {
662            break;
663        }
664        prev_rounded = rounded;
665    }
666
667    result
668}
669
670fn exp_fixed(x_fp: &BigInt, scale: &BigInt, guard_factor: &BigInt, max_iters: usize) -> BigInt {
671    // Fixed-point exponential using the Taylor series for exp(x), stopping once rounded digits
672    // stabilize at the target precision or the incremental term is below guard bits.
673    let mut term = scale.clone(); // 1.0 in fixed-point space
674    let mut result = term.clone();
675    let mut prev_rounded = round_to_precision(&result, guard_factor);
676    for n in 1..=max_iters {
677        term = (&term * x_fp).div_floor(&(scale * BigInt::from(n as u32)));
678        if term.is_zero() {
679            break;
680        }
681        result += &term;
682
683        let rounded = round_to_precision(&result, guard_factor);
684        if term.abs() < guard_factor.abs() || rounded == prev_rounded {
685            break;
686        }
687        prev_rounded = rounded;
688    }
689
690    result
691}
692
693fn ln_biguint(
694    value: &BigUint,
695    internal_precision: u32,
696    internal_scale_uint: &BigUint,
697    internal_scale: &BigInt,
698    guard_factor: &BigInt,
699    ln_two: &BigInt,
700    max_iters: usize,
701) -> BigInt {
702    debug_assert!(!value.is_zero());
703    if value.is_zero() {
704        return BigInt::zero();
705    }
706
707    let int_prec = internal_precision as usize;
708    let mut shift = value.bits().saturating_sub(1);
709    let mut mantissa = value.clone() << int_prec;
710    mantissa >>= shift;
711
712    // Keep the mantissa close to 1.0 (in [0.5, 1.5)) for fast ln1p convergence.
713    let half_scale = internal_scale_uint >> 1;
714    let scale_plus_half = internal_scale_uint + &half_scale;
715    if mantissa >= scale_plus_half {
716        mantissa >>= 1;
717        shift = shift.saturating_add(1);
718    }
719
720    let mantissa_int = BigInt::from_biguint(Sign::Plus, mantissa);
721    let ln_mantissa = ln1p_fixed(
722        &(mantissa_int - internal_scale),
723        internal_scale,
724        guard_factor,
725        max_iters,
726    );
727
728    ln_mantissa + ln_two * BigInt::from(shift)
729}
730
731fn round_to_precision(value: &BigInt, guard_factor: &BigInt) -> BigInt {
732    let (mut truncated, remainder) = value.div_rem(guard_factor);
733    if !remainder.is_zero() && (remainder.abs() << 1) >= guard_factor.abs() {
734        truncated += remainder.signum();
735    }
736    truncated
737}
738
739impl Neg for SafeInt {
740    type Output = SafeInt;
741
742    #[inline(always)]
743    fn neg(self) -> SafeInt {
744        SafeInt(-self.0)
745    }
746}
747
748impl Neg for &SafeInt {
749    type Output = SafeInt;
750
751    #[inline(always)]
752    fn neg(self) -> SafeInt {
753        SafeInt(-self.0.clone())
754    }
755}
756
757macro_rules! impl_pair_ops {
758    ($trait:ident, $method:ident) => {
759        impl $trait for SafeInt {
760            type Output = SafeInt;
761
762            #[inline(always)]
763            fn $method(self, other: SafeInt) -> SafeInt {
764                SafeInt(self.0.$method(other.0))
765            }
766        }
767
768        impl $trait<&SafeInt> for SafeInt {
769            type Output = SafeInt;
770
771            #[inline(always)]
772            fn $method(self, other: &SafeInt) -> SafeInt {
773                SafeInt(self.0.$method(&other.0))
774            }
775        }
776
777        impl $trait<SafeInt> for &SafeInt {
778            type Output = SafeInt;
779
780            #[inline(always)]
781            fn $method(self, other: SafeInt) -> SafeInt {
782                SafeInt(self.0.clone().$method(other.0))
783            }
784        }
785
786        impl $trait<&SafeInt> for &SafeInt {
787            type Output = SafeInt;
788
789            #[inline(always)]
790            fn $method(self, other: &SafeInt) -> SafeInt {
791                SafeInt(self.0.clone().$method(&other.0))
792            }
793        }
794    };
795}
796
797macro_rules! impl_pair_rem_ops {
798    () => {
799        impl Rem for SafeInt {
800            type Output = Option<SafeInt>;
801
802            #[inline(always)]
803            fn rem(self, other: SafeInt) -> Option<SafeInt> {
804                if other.0.is_zero() {
805                    None
806                } else {
807                    Some(SafeInt(self.0 % other.0))
808                }
809            }
810        }
811
812        impl Rem<&SafeInt> for SafeInt {
813            type Output = Option<SafeInt>;
814
815            #[inline(always)]
816            fn rem(self, other: &SafeInt) -> Option<SafeInt> {
817                if other.0.is_zero() {
818                    None
819                } else {
820                    Some(SafeInt(self.0 % &other.0))
821                }
822            }
823        }
824
825        impl Rem<SafeInt> for &SafeInt {
826            type Output = Option<SafeInt>;
827
828            #[inline(always)]
829            fn rem(self, other: SafeInt) -> Option<SafeInt> {
830                if other.0.is_zero() {
831                    None
832                } else {
833                    Some(SafeInt(self.0.clone() % other.0))
834                }
835            }
836        }
837
838        impl Rem<&SafeInt> for &SafeInt {
839            type Output = Option<SafeInt>;
840
841            #[inline(always)]
842            fn rem(self, other: &SafeInt) -> Option<SafeInt> {
843                if other.0.is_zero() {
844                    None
845                } else {
846                    Some(SafeInt(self.0.clone() % &other.0))
847                }
848            }
849        }
850    };
851}
852
853impl_pair_ops!(Add, add);
854impl_pair_ops!(Sub, sub);
855impl_pair_ops!(Mul, mul);
856impl_pair_rem_ops!();
857impl_pair_ops!(BitAnd, bitand);
858impl_pair_ops!(BitOr, bitor);
859impl_pair_ops!(BitXor, bitxor);
860
861macro_rules! impl_prim_ops {
862    ($trait:ident, $method:ident, [$($t:ty),*]) => {
863        $(
864            impl $trait<$t> for SafeInt {
865                type Output = SafeInt;
866
867                #[inline(always)]
868                fn $method(self, other: $t) -> SafeInt {
869                    SafeInt(self.0.$method(BigInt::from(other)))
870                }
871            }
872
873            impl $trait<$t> for &SafeInt {
874                type Output = SafeInt;
875
876                #[inline(always)]
877                fn $method(self, other: $t) -> SafeInt {
878                    SafeInt(self.0.clone().$method(BigInt::from(other)))
879                }
880            }
881
882            impl $trait<SafeInt> for $t {
883                type Output = SafeInt;
884
885                #[inline(always)]
886                fn $method(self, other: SafeInt) -> SafeInt {
887                    SafeInt(BigInt::from(self).$method(other.0))
888                }
889            }
890
891            impl $trait<&SafeInt> for $t {
892                type Output = SafeInt;
893
894                #[inline(always)]
895                fn $method(self, other: &SafeInt) -> SafeInt {
896                    SafeInt(BigInt::from(self).$method(other.0.clone()))
897                }
898            }
899        )*
900    };
901}
902
903macro_rules! impl_prim_rem_ops {
904    ($($t:ty),*) => {
905        $(
906            impl Rem<$t> for SafeInt {
907                type Output = Option<SafeInt>;
908
909                #[inline(always)]
910                fn rem(self, other: $t) -> Option<SafeInt> {
911                    if other == 0 {
912                        None
913                    } else {
914                        Some(SafeInt(self.0 % BigInt::from(other)))
915                    }
916                }
917            }
918
919            impl Rem<$t> for &SafeInt {
920                type Output = Option<SafeInt>;
921
922                #[inline(always)]
923                fn rem(self, other: $t) -> Option<SafeInt> {
924                    if other == 0 {
925                        None
926                    } else {
927                        Some(SafeInt(self.0.clone() % BigInt::from(other)))
928                    }
929                }
930            }
931
932            impl Rem<SafeInt> for $t {
933                type Output = Option<SafeInt>;
934
935                #[inline(always)]
936                fn rem(self, other: SafeInt) -> Option<SafeInt> {
937                    if other.0.is_zero() {
938                        None
939                    } else {
940                        Some(SafeInt(BigInt::from(self) % other.0))
941                    }
942                }
943            }
944
945            impl Rem<&SafeInt> for $t {
946                type Output = Option<SafeInt>;
947
948                #[inline(always)]
949                fn rem(self, other: &SafeInt) -> Option<SafeInt> {
950                    if other.0.is_zero() {
951                        None
952                    } else {
953                        Some(SafeInt(BigInt::from(self) % other.0.clone()))
954                    }
955                }
956            }
957        )*
958    };
959}
960
961impl_prim_ops!(
962    Add,
963    add,
964    [
965        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
966    ]
967);
968impl_prim_ops!(
969    Sub,
970    sub,
971    [
972        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
973    ]
974);
975impl_prim_ops!(
976    Mul,
977    mul,
978    [
979        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
980    ]
981);
982impl_prim_rem_ops!(
983    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
984);
985impl_prim_ops!(
986    BitAnd,
987    bitand,
988    [
989        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
990    ]
991);
992impl_prim_ops!(
993    BitOr,
994    bitor,
995    [
996        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
997    ]
998);
999impl_prim_ops!(
1000    BitXor,
1001    bitxor,
1002    [
1003        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1004    ]
1005);
1006
1007impl AddAssign<SafeInt> for SafeInt {
1008    #[inline(always)]
1009    fn add_assign(&mut self, rhs: SafeInt) {
1010        self.0 += rhs.0;
1011    }
1012}
1013
1014impl AddAssign<&SafeInt> for SafeInt {
1015    #[inline(always)]
1016    fn add_assign(&mut self, rhs: &SafeInt) {
1017        self.0 += &rhs.0;
1018    }
1019}
1020
1021impl SubAssign<SafeInt> for SafeInt {
1022    #[inline(always)]
1023    fn sub_assign(&mut self, rhs: SafeInt) {
1024        self.0 -= rhs.0;
1025    }
1026}
1027
1028impl SubAssign<&SafeInt> for SafeInt {
1029    #[inline(always)]
1030    fn sub_assign(&mut self, rhs: &SafeInt) {
1031        self.0 -= &rhs.0;
1032    }
1033}
1034
1035impl MulAssign<SafeInt> for SafeInt {
1036    #[inline(always)]
1037    fn mul_assign(&mut self, rhs: SafeInt) {
1038        self.0 *= rhs.0;
1039    }
1040}
1041
1042impl MulAssign<&SafeInt> for SafeInt {
1043    #[inline(always)]
1044    fn mul_assign(&mut self, rhs: &SafeInt) {
1045        self.0 *= &rhs.0;
1046    }
1047}
1048
1049impl RemAssign<SafeInt> for SafeInt {
1050    #[inline(always)]
1051    fn rem_assign(&mut self, rhs: SafeInt) {
1052        if !rhs.0.is_zero() {
1053            self.0 %= rhs.0;
1054        }
1055    }
1056}
1057
1058impl RemAssign<&SafeInt> for SafeInt {
1059    #[inline(always)]
1060    fn rem_assign(&mut self, rhs: &SafeInt) {
1061        if !rhs.0.is_zero() {
1062            self.0 %= &rhs.0;
1063        }
1064    }
1065}
1066
1067impl BitAndAssign<SafeInt> for SafeInt {
1068    #[inline(always)]
1069    fn bitand_assign(&mut self, rhs: SafeInt) {
1070        self.0 &= rhs.0;
1071    }
1072}
1073
1074impl BitAndAssign<&SafeInt> for SafeInt {
1075    #[inline(always)]
1076    fn bitand_assign(&mut self, rhs: &SafeInt) {
1077        self.0 &= &rhs.0;
1078    }
1079}
1080
1081impl BitOrAssign<SafeInt> for SafeInt {
1082    #[inline(always)]
1083    fn bitor_assign(&mut self, rhs: SafeInt) {
1084        self.0 |= rhs.0;
1085    }
1086}
1087
1088impl BitOrAssign<&SafeInt> for SafeInt {
1089    #[inline(always)]
1090    fn bitor_assign(&mut self, rhs: &SafeInt) {
1091        self.0 |= &rhs.0;
1092    }
1093}
1094
1095impl BitXorAssign<SafeInt> for SafeInt {
1096    #[inline(always)]
1097    fn bitxor_assign(&mut self, rhs: SafeInt) {
1098        self.0 ^= rhs.0;
1099    }
1100}
1101
1102impl BitXorAssign<&SafeInt> for SafeInt {
1103    #[inline(always)]
1104    fn bitxor_assign(&mut self, rhs: &SafeInt) {
1105        self.0 ^= &rhs.0;
1106    }
1107}
1108
1109macro_rules! impl_assign_prim {
1110    ($trait:ident, $method:ident, $op:tt, [$($t:ty),*]) => {
1111        $(
1112            impl $trait<$t> for SafeInt {
1113                #[inline(always)]
1114                fn $method(&mut self, rhs: $t) {
1115                    self.0 $op BigInt::from(rhs);
1116                }
1117            }
1118        )*
1119    };
1120}
1121
1122macro_rules! impl_rem_assign_prim {
1123    ($($t:ty),*) => {
1124        $(
1125            impl RemAssign<$t> for SafeInt {
1126                #[inline(always)]
1127                fn rem_assign(&mut self, rhs: $t) {
1128                    if rhs != 0 {
1129                        self.0 %= BigInt::from(rhs);
1130                    }
1131                }
1132            }
1133        )*
1134    };
1135}
1136
1137impl_assign_prim!(AddAssign, add_assign, +=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1138impl_assign_prim!(SubAssign, sub_assign, -=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1139impl_assign_prim!(MulAssign, mul_assign, *=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1140impl_rem_assign_prim!(
1141    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1142);
1143impl_assign_prim!(BitAndAssign, bitand_assign, &=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1144impl_assign_prim!(BitOrAssign, bitor_assign, |=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1145impl_assign_prim!(BitXorAssign, bitxor_assign, ^=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1146
1147impl Div for SafeInt {
1148    type Output = Option<SafeInt>;
1149
1150    #[inline(always)]
1151    fn div(self, other: SafeInt) -> Option<SafeInt> {
1152        if other.0.is_zero() {
1153            None
1154        } else {
1155            Some(SafeInt(self.0 / other.0))
1156        }
1157    }
1158}
1159
1160impl Div<&SafeInt> for SafeInt {
1161    type Output = Option<SafeInt>;
1162
1163    #[inline(always)]
1164    fn div(self, other: &SafeInt) -> Option<SafeInt> {
1165        if other.0.is_zero() {
1166            None
1167        } else {
1168            Some(SafeInt(self.0 / &other.0))
1169        }
1170    }
1171}
1172
1173impl Div<SafeInt> for &SafeInt {
1174    type Output = Option<SafeInt>;
1175
1176    #[inline(always)]
1177    fn div(self, other: SafeInt) -> Option<SafeInt> {
1178        if other.0.is_zero() {
1179            None
1180        } else {
1181            Some(SafeInt(self.0.clone() / other.0))
1182        }
1183    }
1184}
1185
1186impl Div<&SafeInt> for &SafeInt {
1187    type Output = Option<SafeInt>;
1188
1189    #[inline(always)]
1190    fn div(self, other: &SafeInt) -> Option<SafeInt> {
1191        if other.0.is_zero() {
1192            None
1193        } else {
1194            Some(SafeInt(self.0.clone() / &other.0))
1195        }
1196    }
1197}
1198
1199macro_rules! impl_div_safeint_rhs_prim {
1200    ($($t:ty),*) => {
1201        $(
1202            impl Div<$t> for SafeInt {
1203                type Output = Option<SafeInt>;
1204
1205                #[inline(always)]
1206                fn div(self, other: $t) -> Option<SafeInt> {
1207                    if other == 0 {
1208                        None
1209                    } else {
1210                        Some(SafeInt(self.0 / BigInt::from(other)))
1211                    }
1212                }
1213            }
1214
1215            impl Div<$t> for &SafeInt {
1216                type Output = Option<SafeInt>;
1217
1218                #[inline(always)]
1219                fn div(self, other: $t) -> Option<SafeInt> {
1220                    if other == 0 {
1221                        None
1222                    } else {
1223                        Some(SafeInt(self.0.clone() / BigInt::from(other)))
1224                    }
1225                }
1226            }
1227        )*
1228    };
1229}
1230
1231macro_rules! impl_div_prim_lhs_safeint {
1232    ($($t:ty),*) => {
1233        $(
1234            impl Div<SafeInt> for $t {
1235                type Output = Option<SafeInt>;
1236
1237                #[inline(always)]
1238                fn div(self, other: SafeInt) -> Option<SafeInt> {
1239                    if other.0.is_zero() {
1240                        None
1241                    } else {
1242                        Some(SafeInt(BigInt::from(self) / other.0))
1243                    }
1244                }
1245            }
1246
1247            impl Div<&SafeInt> for $t {
1248                type Output = Option<SafeInt>;
1249
1250                #[inline(always)]
1251                fn div(self, other: &SafeInt) -> Option<SafeInt> {
1252                    if other.0.is_zero() {
1253                        None
1254                    } else {
1255                        Some(SafeInt(BigInt::from(self) / other.0.clone()))
1256                    }
1257                }
1258            }
1259        )*
1260    };
1261}
1262
1263impl_div_safeint_rhs_prim!(
1264    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1265);
1266impl_div_prim_lhs_safeint!(
1267    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1268);
1269
1270impl<T: Into<BigInt>> From<T> for SafeInt {
1271    #[inline(always)]
1272    fn from(value: T) -> SafeInt {
1273        SafeInt(value.into())
1274    }
1275}
1276
1277impl<T> PartialEq<T> for SafeInt
1278where
1279    T: Copy,
1280    BigInt: From<T>,
1281{
1282    #[inline(always)]
1283    fn eq(&self, other: &T) -> bool {
1284        self.0 == BigInt::from(*other)
1285    }
1286}
1287
1288impl<T> PartialOrd<T> for SafeInt
1289where
1290    T: Copy,
1291    BigInt: From<T>,
1292{
1293    #[inline(always)]
1294    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
1295        self.0.partial_cmp(&BigInt::from(*other))
1296    }
1297}
1298
1299macro_rules! impl_prim_cmp {
1300    ($($t:ty),*) => {
1301        $(
1302            impl PartialEq<SafeInt> for $t {
1303                #[inline(always)]
1304                fn eq(&self, other: &SafeInt) -> bool {
1305                    BigInt::from(*self) == other.0
1306                }
1307            }
1308
1309            impl PartialOrd<SafeInt> for $t {
1310                #[inline(always)]
1311                fn partial_cmp(&self, other: &SafeInt) -> Option<Ordering> {
1312                    BigInt::from(*self).partial_cmp(&other.0)
1313                }
1314            }
1315        )*
1316    };
1317}
1318
1319impl_prim_cmp!(
1320    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1321);
1322
1323/// Fixed-size, byte-backed integer that can be converted into `SafeInt`.
1324///
1325/// # Examples
1326/// ```
1327/// use safe_bigmath::integer::ConstSafeInt;
1328/// use safe_bigmath::SafeInt;
1329///
1330/// const ONE: ConstSafeInt<2> = ConstSafeInt::from_bytes([0, 1]);
1331/// assert_eq!(SafeInt::from(ONE), SafeInt::from(1));
1332/// ```
1333#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1334#[repr(C)]
1335pub struct ConstSafeInt<const N: usize>([u8; N]);
1336
1337impl<const N: usize> ConstSafeInt<N> {
1338    /// Creates a constant from big-endian two's-complement bytes, where the first byte encodes the sign.
1339    pub const fn from_bytes(value: [u8; N]) -> Self {
1340        Self(value)
1341    }
1342
1343    /// Returns the underlying bytes.
1344    pub const fn as_bytes(&self) -> &[u8; N] {
1345        &self.0
1346    }
1347
1348    /// Converts into a runtime `SafeInt`.
1349    pub fn to_val(self) -> SafeInt {
1350        self.into()
1351    }
1352}
1353
1354impl ConstSafeInt<17> {
1355    /// Builds a 17-byte representation from an `i128` while preserving the sign bit.
1356    ///
1357    /// # Examples
1358    /// ```
1359    /// use safe_bigmath::integer::ConstSafeInt;
1360    /// use safe_bigmath::SafeInt;
1361    ///
1362    /// const NEG_ONE: ConstSafeInt<17> = ConstSafeInt::from_i128(-1);
1363    /// assert_eq!(SafeInt::from(NEG_ONE), SafeInt::from(-1));
1364    /// ```
1365    pub const fn from_i128(value: i128) -> Self {
1366        let is_neg = value < 0;
1367        let value = if value == i128::MIN {
1368            i128::MAX as u128 + 1
1369        } else {
1370            value.unsigned_abs()
1371        };
1372        let mut res = Self::from_u128(value);
1373        if is_neg {
1374            res.0[0] = 1;
1375        }
1376        res
1377    }
1378    /// Builds a 17-byte representation from an unsigned 128-bit value.
1379    pub const fn from_u128(value: u128) -> Self {
1380        let mut res = [0; 17];
1381        let mut value = value;
1382        let mut i = 17;
1383        while i > 0 {
1384            i -= 1;
1385            res[i] = (value & 0xff) as u8;
1386            value >>= 8;
1387        }
1388        Self(res)
1389    }
1390}
1391
1392impl<const N: usize> From<ConstSafeInt<N>> for SafeInt {
1393    #[inline(always)]
1394    fn from(value: ConstSafeInt<N>) -> SafeInt {
1395        let pos = value.0.first().cloned().unwrap_or(0) == 0;
1396        let magnitude = BigUint::from_bytes_be(&value.0[1..]);
1397        let mut res = SafeInt(BigInt::from_biguint(Sign::Plus, magnitude));
1398        if !pos {
1399            res = -res;
1400        }
1401        res
1402    }
1403}
1404
1405impl<const N: usize> From<&ConstSafeInt<N>> for SafeInt {
1406    #[inline(always)]
1407    fn from(value: &ConstSafeInt<N>) -> SafeInt {
1408        let pos = value.0.first().cloned().unwrap_or(0) == 0;
1409        let magnitude = BigUint::from_bytes_be(&value.0[1..]);
1410        let mut res = SafeInt(BigInt::from_biguint(Sign::Plus, magnitude));
1411        if !pos {
1412            res = -res;
1413        }
1414        res
1415    }
1416}
1417
1418const LENCODE_SAFE_INT_VARIANT_MASK: u8 = 0x80;
1419const LENCODE_SAFE_INT_VARIANT_BYTES: u8 = 0x80;
1420const LENCODE_SAFE_INT_SIZE_MASK: u8 = 0x40;
1421const LENCODE_SAFE_INT_SIZE_LARGE: u8 = 0x40;
1422const LENCODE_SAFE_INT_PAYLOAD_MASK: u8 = 0x3F;
1423const LENCODE_SAFE_INT_SMALL_MAX: u8 = LENCODE_SAFE_INT_PAYLOAD_MASK;
1424const LENCODE_MAX_VARINT_BYTES: usize = LENCODE_SAFE_INT_PAYLOAD_MASK as usize;
1425
1426#[inline(always)]
1427fn lencode_encode_biguint_varint_bytes(
1428    bytes: &[u8],
1429    writer: &mut impl Write,
1430) -> lencode::Result<usize> {
1431    if bytes.is_empty() {
1432        return writer.write(&[0u8]);
1433    }
1434    if bytes.len() == 1 && bytes[0] <= LENCODE_SAFE_INT_SMALL_MAX {
1435        return writer.write(&[bytes[0]]);
1436    }
1437    if bytes.len() > LENCODE_MAX_VARINT_BYTES {
1438        return Err(Error::IncorrectLength);
1439    }
1440
1441    let mut total = 0;
1442    total += writer.write(&[LENCODE_SAFE_INT_SIZE_LARGE | (bytes.len() as u8)])?;
1443    total += writer.write(bytes)?;
1444    Ok(total)
1445}
1446
1447#[inline(always)]
1448fn lencode_decode_biguint_varint_from_prefix(
1449    prefix: u8,
1450    reader: &mut impl Read,
1451) -> lencode::Result<BigUint> {
1452    if (prefix & LENCODE_SAFE_INT_SIZE_MASK) == 0 {
1453        return Ok(BigUint::from(prefix & LENCODE_SAFE_INT_PAYLOAD_MASK));
1454    }
1455
1456    let len = (prefix & LENCODE_SAFE_INT_PAYLOAD_MASK) as usize;
1457    if len == 0 {
1458        return Err(Error::InvalidData);
1459    }
1460
1461    let mut buf = vec![0u8; len];
1462    let mut read = 0usize;
1463    while read < len {
1464        let n = reader.read(&mut buf[read..])?;
1465        if n == 0 {
1466            return Err(Error::ReaderOutOfData);
1467        }
1468        read += n;
1469    }
1470    Ok(BigUint::from_bytes_le(&buf))
1471}
1472
1473#[inline(always)]
1474fn lencode_encode_biguint_with_variant(
1475    value: &BigUint,
1476    writer: &mut impl Write,
1477) -> lencode::Result<usize> {
1478    let bytes = value.to_bytes_le();
1479    if bytes.len() <= LENCODE_MAX_VARINT_BYTES {
1480        return lencode_encode_biguint_varint_bytes(&bytes, writer);
1481    }
1482
1483    let mut total = 0;
1484    total += writer.write(&[LENCODE_SAFE_INT_VARIANT_BYTES])?;
1485    total += bytes.encode(writer)?;
1486    Ok(total)
1487}
1488
1489#[inline(always)]
1490fn lencode_decode_biguint_with_variant(reader: &mut impl Read) -> lencode::Result<BigUint> {
1491    let mut tag = [0u8; 1];
1492    if reader.read(&mut tag)? != 1 {
1493        return Err(Error::ReaderOutOfData);
1494    }
1495
1496    if (tag[0] & LENCODE_SAFE_INT_VARIANT_MASK) != 0 {
1497        let bytes: Vec<u8> = Vec::decode(reader)?;
1498        Ok(BigUint::from_bytes_le(&bytes))
1499    } else {
1500        lencode_decode_biguint_varint_from_prefix(tag[0], reader)
1501    }
1502}
1503
1504#[inline(always)]
1505fn lencode_zigzag_encode_bigint(value: &BigInt) -> BigUint {
1506    if value.is_negative() {
1507        let magnitude = (-value).to_biguint().unwrap_or(BigUint::ZERO);
1508        (magnitude << 1usize) - BigUint::from(1u8)
1509    } else {
1510        let magnitude = value.to_biguint().unwrap_or(BigUint::ZERO);
1511        magnitude << 1usize
1512    }
1513}
1514
1515#[inline(always)]
1516fn lencode_zigzag_decode_biguint(value: BigUint) -> BigInt {
1517    if value.is_odd() {
1518        let magnitude = (value + BigUint::from(1u8)) >> 1usize;
1519        -BigInt::from(magnitude)
1520    } else {
1521        BigInt::from(value >> 1usize)
1522    }
1523}
1524
1525impl Encode for SafeInt {
1526    #[inline(always)]
1527    fn encode_ext(
1528        &self,
1529        writer: &mut impl Write,
1530        _dedupe_encoder: Option<&mut DedupeEncoder>,
1531    ) -> lencode::Result<usize> {
1532        let encoded = lencode_zigzag_encode_bigint(&self.0);
1533        lencode_encode_biguint_with_variant(&encoded, writer)
1534    }
1535}
1536
1537impl Decode for SafeInt {
1538    #[inline(always)]
1539    fn decode_ext(
1540        reader: &mut impl Read,
1541        _dedupe_decoder: Option<&mut DedupeDecoder>,
1542    ) -> lencode::Result<Self> {
1543        let unsigned = lencode_decode_biguint_with_variant(reader)?;
1544        Ok(SafeInt::from_raw(lencode_zigzag_decode_biguint(unsigned)))
1545    }
1546}
1547
1548#[test]
1549fn test_const_safe_int() {
1550    assert_eq!(
1551        SafeInt::from(ConstSafeInt::<4>::from_bytes([0, 0, 0, 1])),
1552        1
1553    );
1554    assert_eq!(SafeInt::from(ConstSafeInt::<2>::from_bytes([0, 1])), 1);
1555    assert_eq!(SafeInt::from(ConstSafeInt::<2>::from_bytes([1, 1])), -1);
1556    assert_eq!(SafeInt::from(ConstSafeInt::<2>::from_bytes([1, 0])), -0);
1557    assert_eq!(
1558        SafeInt::from(ConstSafeInt::<3>::from_bytes([1, 5, 254])),
1559        -1534
1560    );
1561    assert_eq!(
1562        SafeInt::from(ConstSafeInt::<17>::from_i128(-538525)),
1563        -538525
1564    );
1565    assert_eq!(
1566        SafeInt::from(ConstSafeInt::<17>::from_i128(123456789)),
1567        123456789
1568    );
1569    assert_eq!(
1570        SafeInt::from(ConstSafeInt::<17>::from_i128(i128::MIN)),
1571        i128::MIN
1572    );
1573    assert_eq!(
1574        SafeInt::from(ConstSafeInt::<17>::from_i128(i128::MAX)),
1575        i128::MAX
1576    );
1577    assert_eq!(
1578        SafeInt::from(ConstSafeInt::<17>::from_u128(u128::MAX)),
1579        u128::MAX
1580    );
1581    assert_eq!(
1582        SafeInt::from(ConstSafeInt::<17>::from_u128(39874398749837343434343434344)),
1583        39874398749837343434343434344u128
1584    );
1585    assert_eq!(SafeInt::from(ConstSafeInt::<17>::from_u128(0)), 0);
1586}
1587
1588#[test]
1589fn general() {
1590    let a = SafeInt::from(10);
1591    let b = SafeInt::from(20);
1592    let c = &a + &b;
1593    let d = a.clone() + c.clone();
1594    let e = a.clone() + &b;
1595    let f = &a + b.clone();
1596    assert_eq!(c, 30);
1597    assert!(d > a);
1598    assert!(a < d);
1599    assert!(a < b);
1600    assert_eq!(e, f);
1601    assert_eq!(f, a + b);
1602    assert_eq!((SafeInt::from(10) / SafeInt::from(3)).unwrap(), 3);
1603    assert_eq!(SafeInt::from(10) / SafeInt::from(0), None);
1604    assert_ne!(SafeInt::from(10), SafeInt::from(20));
1605    assert!(SafeInt::from(37984739847983497938479797988798789783u128).is_odd());
1606    assert!(
1607        SafeInt::from_str("3798473984798349793847979798879878978334738744739847983749837").unwrap()
1608            > 10
1609    );
1610    assert_eq!(
1611        SafeInt::from(33) / SafeInt::from(3),
1612        Some(SafeInt::from(11))
1613    );
1614    assert_eq!(33 / SafeInt::from(3), Some(SafeInt::from(11)));
1615    assert_eq!(SafeInt::from(33) / 3, Some(SafeInt::from(11)));
1616    assert_eq!(SafeInt::from(10) % SafeInt::from(3), Some(SafeInt::from(1)));
1617    assert_eq!(SafeInt::from(10) % SafeInt::from(0), None);
1618    assert_eq!(10 % SafeInt::from(3), Some(SafeInt::from(1)));
1619    assert_eq!(10 % SafeInt::from(0), None);
1620    assert_eq!(SafeInt::from(10) % 3, Some(SafeInt::from(1)));
1621    assert_eq!(SafeInt::from(10) % 0, None);
1622    assert_eq!(
1623        SafeInt::from(10).div_rem(SafeInt::from(3)),
1624        Some((SafeInt::from(3), SafeInt::from(1)))
1625    );
1626    assert_eq!(SafeInt::from(10).div_rem(SafeInt::from(0)), None);
1627    assert_eq!(33 + SafeInt::from(2), 35);
1628    assert_eq!(SafeInt::from(33) + 2, 35);
1629    assert_eq!(SafeInt::from(5) / SafeInt::from(0), None);
1630    assert_eq!(5 / SafeInt::from(0), None);
1631    assert_eq!(SafeInt::from(5) / 0, None);
1632    assert_eq!(&SafeInt::from(789) / 893797983, Some(SafeInt::from(0)));
1633    assert_eq!(&SafeInt::from(28249) / SafeInt::zero(), None);
1634}
1635
1636#[test]
1637fn test_safe_int_cmp_self() {
1638    let a = SafeInt::from(5);
1639    let b = SafeInt::from(7);
1640    let a2 = a.clone();
1641
1642    assert_eq!(a, a2);
1643    assert_ne!(a, b);
1644    assert!(a < b);
1645    assert!(b > a);
1646    assert!(a <= a2);
1647    assert!(a >= a2);
1648    assert_eq!(a.partial_cmp(&b), Some(Ordering::Less));
1649    assert_eq!(b.partial_cmp(&a), Some(Ordering::Greater));
1650    assert_eq!(a.cmp(&a2), Ordering::Equal);
1651    assert_eq!(a.cmp(&b), Ordering::Less);
1652}
1653
1654#[test]
1655fn test_perquintill_power() {
1656    const PRECISION: u32 = 256;
1657    const PERQUINTILL: u128 = 1_000_000_000_000_000_000;
1658
1659    let x = SafeInt::from(21_000_000_000_000_000u64);
1660    let delta = SafeInt::from(7_000_000_000_000_000u64);
1661    let w1 = SafeInt::from(600_000_000_000_000_000u128);
1662    let w2 = SafeInt::from(400_000_000_000_000_000u128);
1663    let denominator = &x + &delta;
1664    assert_eq!(w1.clone() + w2.clone(), SafeInt::from(PERQUINTILL));
1665
1666    let perquintill_result = SafeInt::pow_ratio_scaled(
1667        &x,
1668        &denominator,
1669        &w1,
1670        &w2,
1671        PRECISION,
1672        &SafeInt::from(PERQUINTILL),
1673    )
1674    .expect("perquintill integer result");
1675
1676    assert_eq!(
1677        perquintill_result,
1678        SafeInt::from(649_519_052_838_328_985u128)
1679    );
1680    let readable = crate::SafeDec::<18>::from_raw(perquintill_result);
1681    assert_eq!(format!("{}", readable), "0.649519052838328985");
1682}
1683
1684#[test]
1685fn pow_ratio_scaled_handles_large_weight_denominators() {
1686    let x = SafeInt::from(21_000_000_000_000_000i128);
1687    let denominator = SafeInt::from(21_000_000_000_000_100i128);
1688    let perquintill = SafeInt::from(1_000_000_000_000_000_000i128);
1689
1690    let cases = [
1691        (
1692            SafeInt::from(500_000_000_000_000_000i128),
1693            SafeInt::from(500_000_000_000_000_000i128),
1694        ),
1695        (
1696            SafeInt::from(499_999_999_999_500_000i128),
1697            SafeInt::from(500_000_000_000_500_000i128),
1698        ),
1699        (
1700            SafeInt::from(500_000_000_000_250_000i128),
1701            SafeInt::from(499_999_999_999_750_000i128),
1702        ),
1703    ];
1704
1705    for (w1, w2) in cases {
1706        let result =
1707            SafeInt::pow_ratio_scaled(&x, &denominator, &w1, &w2, 256, &perquintill).unwrap();
1708        assert_eq!(result, SafeInt::from(999_999_999_999_995_238i128));
1709    }
1710}
1711
1712#[test]
1713fn pow_ratio_scaled_converges_on_boundary_weights() {
1714    let x = SafeInt::from(21_000_000_000_000_000i128);
1715    let denominator = SafeInt::from(21_000_000_000_000_001i128);
1716    let w1 = SafeInt::from(499_999_999_500_000_000i128);
1717    let w2 = SafeInt::from(500_000_000_500_000_000i128);
1718    let scale = SafeInt::from(1_000_000_000_000_000_000i128);
1719    let precision = 256u32;
1720
1721    let start = std::time::Instant::now();
1722    let result = SafeInt::pow_ratio_scaled(&x, &denominator, &w1, &w2, precision, &scale).unwrap();
1723    let elapsed = start.elapsed();
1724
1725    assert_eq!(result, SafeInt::from(999_999_999_999_999_952i128));
1726    assert!(
1727        elapsed < core::time::Duration::from_secs(1),
1728        "pow_ratio_scaled took {:?}",
1729        elapsed
1730    );
1731}
1732
1733#[test]
1734fn pow_ratio_scaled_exact_path_handles_high_exponent() {
1735    let base_num = SafeInt::from(999_999_999i128);
1736    let base_den = SafeInt::from(1_000_000_001i128);
1737    let exp_num = SafeInt::from(MAX_EXACT_EXPONENT as i128 - 1);
1738    let exp_den = SafeInt::one();
1739    let scale = SafeInt::from(1_000_000i128);
1740    let precision = 64u32;
1741
1742    let start = std::time::Instant::now();
1743    let result =
1744        SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, precision, &scale)
1745            .expect("exact path should return");
1746    let elapsed = start.elapsed();
1747
1748    assert!(result > SafeInt::zero());
1749    assert!(
1750        elapsed < core::time::Duration::from_secs(1),
1751        "exact path took {:?}",
1752        elapsed
1753    );
1754}
1755
1756#[test]
1757fn pow_ratio_scaled_default_max_iters_completes_quickly() {
1758    let base_num = SafeInt::from(1i128);
1759    let base_den = SafeInt::from(1_000_000_000_000i128);
1760    let exp_num = SafeInt::one();
1761    let exp_den = SafeInt::from(1u128 << 40);
1762    let scale = SafeInt::one();
1763    let precision = 32u32;
1764
1765    let start = std::time::Instant::now();
1766    let default_iter =
1767        SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, precision, &scale)
1768            .unwrap();
1769    let elapsed = start.elapsed();
1770
1771    let explicit_default = SafeInt::pow_ratio_scaled_with_max_iters(
1772        &base_num,
1773        &base_den,
1774        &exp_num,
1775        &exp_den,
1776        precision,
1777        &scale,
1778        Some(DEFAULT_MAX_ITERS),
1779    )
1780    .unwrap();
1781
1782    assert_eq!(default_iter, explicit_default);
1783    assert!(
1784        elapsed < core::time::Duration::from_secs(2),
1785        "default iterations took {:?}",
1786        elapsed
1787    );
1788}
1789
1790#[test]
1791fn pow_ratio_scaled_uses_scale_to_pick_precision() {
1792    // Force the fallback path (large exponent bits) and make sure the minimum precision we pick
1793    // based on `scale` is close to a much higher requested precision.
1794    let base_num = SafeInt::from(123_456_789u64);
1795    let base_den = SafeInt::from(987_654_321u64);
1796    let exp_num = SafeInt::from(987_654_321_123_456_789u128);
1797    let exp_den = SafeInt::from(123_456_789_987_654_321u128);
1798    let scale = SafeInt::from(1_000_000_000_000_000_000i128);
1799
1800    let coarse = SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, 0, &scale)
1801        .expect("coarse precision result");
1802    let precise = SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, 256, &scale)
1803        .expect("high precision result");
1804    let delta = (precise.clone() - coarse.clone()).abs();
1805
1806    assert!(
1807        delta <= 1u32,
1808        "coarse {coarse} vs precise {precise} differed by {delta}"
1809    );
1810}
1811
1812#[test]
1813fn pow_ratio_scaled_handles_small_base_fractional_exponent() {
1814    // Base far from 1 with a fractional exponent; previously this would under-approximate badly.
1815    let base_num = SafeInt::from(1u8);
1816    let base_den = SafeInt::from(10u8);
1817    let exp_num = SafeInt::from(500_000_000_001u64);
1818    let exp_den = SafeInt::from(1_000_000_000_000u64);
1819    let scale = SafeInt::from(1_000_000_000_000_000_000u128);
1820    let precision = 128u32;
1821
1822    let result =
1823        SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, precision, &scale)
1824            .expect("small base fractional exponent");
1825    let expected =
1826        ((0.1f64).powf(0.500000000001f64) * 1_000_000_000_000_000_000f64).floor() as u128;
1827    let delta = (result.clone() - SafeInt::from(expected)).abs();
1828
1829    assert!(
1830        delta <= 128u32,
1831        "result {result} vs expected {expected} (delta {delta})"
1832    );
1833}
1834
1835#[test]
1836fn pow_ratio_scaled_handles_extreme_delta_x() {
1837    let x = SafeInt::from(400_775_553u64);
1838    let dx = SafeInt::from(14_446_633_907_665_582u64);
1839    let base_den = &x + &dx;
1840    let w1 = SafeInt::from(102_337_248_363_782_924u128);
1841    let w2 = SafeInt::from(1_000_000_000_000_000_000u128) - &w1;
1842    let scale = SafeInt::from(1_000_000_000_000_000_000u128);
1843    let precision = 256u32;
1844
1845    let result = SafeInt::pow_ratio_scaled(&x, &base_den, &w1, &w2, precision, &scale)
1846        .expect("extreme delta x");
1847
1848    let expected = ((x.0.to_f64().unwrap() / base_den.0.to_f64().unwrap())
1849        .powf(w1.0.to_f64().unwrap() / w2.0.to_f64().unwrap())
1850        * 1_000_000_000_000_000_000f64)
1851        .floor() as u128;
1852    let delta = (result.clone() - SafeInt::from(expected)).abs();
1853
1854    assert!(
1855        delta <= 1_000_000u128,
1856        "result {result} vs expected {expected} (delta {delta})"
1857    );
1858}
1859
1860#[test]
1861fn pow_ratio_scaled_with_crafted_gcd_values() {
1862    /*
1863       w1_safe and w2_safe are picked with the following rules:
1864          - they don't have GCD > 1
1865          - w1_safe < 1024
1866          - bits(w2_safe) <= 32
1867    */
1868    let x_safe = SafeInt::from_str("2100000000000000000000000").unwrap();
1869    let denominator = SafeInt::from_str("210000000000000000000000").unwrap();
1870    let w1_safe = SafeInt::from_str("499").unwrap();
1871    let w2_safe = SafeInt::from_str("1538820023").unwrap();
1872    let precision = 256;
1873    let perquintill_scale = SafeInt::from_str("1000000000000000000").unwrap();
1874
1875    let start = Instant::now();
1876
1877    SafeInt::pow_ratio_scaled(
1878        &x_safe,
1879        &denominator,
1880        &w1_safe,
1881        &w2_safe,
1882        precision,
1883        &perquintill_scale,
1884    );
1885    let elapsed = start.elapsed();
1886
1887    assert!(
1888        elapsed < Duration::from_secs(1),
1889        "pow_ratio_scaled took {:?} (expected < 1s)",
1890        elapsed
1891    );
1892}
1893
1894#[test]
1895fn pow_bigint_base_with_crafted_gcd_values() {
1896    /*
1897       w1_safe and w2_safe are picked with the following rules:
1898          - they don't have GCD > 1
1899          - w1_safe < 1024
1900          - bits(w2_safe) <= 32
1901    */
1902    let x_safe = SafeInt::from_str("2100000000000000000000000").unwrap();
1903    let w1_safe = SafeInt::from_str("499").unwrap();
1904    let w2_safe = SafeInt::from_str("1538820023").unwrap();
1905    let precision = 256;
1906    let perquintill_scale = SafeInt::from_str("1000000000000000000").unwrap();
1907
1908    let start = Instant::now();
1909
1910    SafeInt::pow_bigint_base(&x_safe, &w1_safe, &w2_safe, precision, &perquintill_scale);
1911    let elapsed = start.elapsed();
1912
1913    assert!(
1914        elapsed < Duration::from_secs(1),
1915        "pow_ratio_scaled took {:?} (expected < 1s)",
1916        elapsed
1917    );
1918}
1919
1920#[test]
1921fn test_zero() {
1922    assert_eq!(SafeInt::zero(), 0);
1923    assert!(SafeInt::zero().is_zero());
1924}
1925
1926#[test]
1927fn test_one() {
1928    let one = SafeInt::one();
1929    assert_eq!(one, 1);
1930}
1931
1932#[cfg(test)]
1933#[inline(always)]
1934fn expected_varint_bytes(value: &BigUint) -> Vec<u8> {
1935    if *value <= BigUint::from(LENCODE_SAFE_INT_SMALL_MAX) {
1936        vec![value.to_u8().expect("value fits in u8")]
1937    } else {
1938        let bytes = value.to_bytes_le();
1939        let mut out = Vec::with_capacity(1 + bytes.len());
1940        out.push(LENCODE_SAFE_INT_SIZE_LARGE | (bytes.len() as u8));
1941        out.extend_from_slice(&bytes);
1942        out
1943    }
1944}
1945
1946#[test]
1947fn lencode_safe_int_roundtrip() {
1948    let big = BigInt::from(1u8) << 200usize;
1949    let values = [
1950        SafeInt::from(0),
1951        SafeInt::from(1),
1952        SafeInt::from(-1),
1953        SafeInt::from(127),
1954        SafeInt::from(128),
1955        SafeInt::from(-128),
1956        SafeInt::from(255),
1957        SafeInt::from(-255),
1958        SafeInt::from_raw(big.clone()),
1959        SafeInt::from_raw(-big),
1960    ];
1961
1962    for value in values {
1963        let mut buf = Vec::new();
1964        let written = value.encode(&mut buf).unwrap();
1965        assert_eq!(written, buf.len());
1966        let decoded = SafeInt::decode(&mut Cursor::new(&buf)).unwrap();
1967        assert_eq!(decoded, value);
1968    }
1969}
1970
1971#[test]
1972fn lencode_safe_int_known_encodings() {
1973    let cases: &[(i32, &[u8])] = &[
1974        (0, &[0x00]),
1975        (1, &[0x02]),
1976        (-1, &[0x01]),
1977        (63, &[0x41, 0x7E]),
1978        (-64, &[0x41, 0x7F]),
1979        (64, &[0x41, 0x80]),
1980        (128, &[0x42, 0x00, 0x01]),
1981        (-128, &[0x41, 0xFF]),
1982        (300, &[0x42, 0x58, 0x02]),
1983    ];
1984
1985    for &(value, expected) in cases {
1986        let mut buf = Vec::new();
1987        let written = SafeInt::from(value).encode(&mut buf).unwrap();
1988        assert_eq!(written, buf.len());
1989        assert_eq!(buf, expected);
1990    }
1991}
1992
1993#[test]
1994fn lencode_safe_int_large_encoding_structure() {
1995    let base = BigInt::from(1u8) << 200usize;
1996    let values = [
1997        SafeInt::from_raw(base.clone()),
1998        SafeInt::from_raw(base.clone() + BigInt::from(0x1234u32)),
1999        SafeInt::from_raw(-base),
2000    ];
2001
2002    for value in values {
2003        let mut buf = Vec::new();
2004        value.encode(&mut buf).unwrap();
2005
2006        let raw = value.raw();
2007        let zigzag = if raw.is_negative() {
2008            let magnitude = (-raw).to_biguint().expect("negative magnitude");
2009            (magnitude << 1usize) - BigUint::from(1u8)
2010        } else {
2011            let magnitude = raw.to_biguint().unwrap_or(BigUint::ZERO);
2012            magnitude << 1usize
2013        };
2014        let payload = zigzag.to_bytes_le();
2015        assert!(payload.len() > 1);
2016        assert_eq!(buf[0], LENCODE_SAFE_INT_SIZE_LARGE | (payload.len() as u8));
2017        assert_eq!(&buf[1..], payload.as_slice());
2018    }
2019}
2020
2021#[test]
2022fn lencode_safe_int_matches_varint_bytes() {
2023    let values = [
2024        SafeInt::from(0),
2025        SafeInt::from(42),
2026        SafeInt::from(-42),
2027        SafeInt::from(1_000_000),
2028        SafeInt::from(-1_000_000),
2029    ];
2030
2031    for value in values {
2032        let raw = value.raw();
2033        let zigzag = if raw.is_negative() {
2034            let magnitude = (-raw).to_biguint().expect("negative magnitude");
2035            (magnitude << 1usize) - BigUint::from(1u8)
2036        } else {
2037            let magnitude = raw.to_biguint().unwrap_or(BigUint::ZERO);
2038            magnitude << 1usize
2039        };
2040        let expected = expected_varint_bytes(&zigzag);
2041
2042        let mut buf = Vec::new();
2043        value.encode(&mut buf).unwrap();
2044        assert_eq!(buf, expected);
2045    }
2046}
2047
2048#[test]
2049fn lencode_safe_int_rejects_zero_length_prefix() {
2050    let data = [LENCODE_SAFE_INT_SIZE_LARGE];
2051    let err = SafeInt::decode(&mut Cursor::new(&data[..])).unwrap_err();
2052    assert!(matches!(err, Error::InvalidData));
2053}
2054
2055#[test]
2056fn lencode_safe_int_rejects_truncated_payload() {
2057    let data = [LENCODE_SAFE_INT_SIZE_LARGE | 0x02u8, 0x01];
2058    let err = SafeInt::decode(&mut Cursor::new(&data[..])).unwrap_err();
2059    assert!(matches!(err, Error::ReaderOutOfData));
2060}
2061
2062#[test]
2063fn lencode_safe_int_large_values_use_bytes_variant() {
2064    let too_large = BigInt::from(1u8) << (8 * LENCODE_MAX_VARINT_BYTES);
2065    let value = SafeInt::from_raw(too_large);
2066    let mut buf = Vec::new();
2067    value.encode(&mut buf).unwrap();
2068
2069    assert_eq!(buf[0], LENCODE_SAFE_INT_VARIANT_BYTES);
2070    let bytes: Vec<u8> = Vec::decode(&mut Cursor::new(&buf[1..])).unwrap();
2071    let zigzag = lencode_zigzag_encode_bigint(value.raw());
2072    assert_eq!(bytes, zigzag.to_bytes_le());
2073
2074    let decoded = SafeInt::decode(&mut Cursor::new(&buf)).unwrap();
2075    assert_eq!(decoded, value);
2076}
2077
2078#[test]
2079fn test_log10() {
2080    let scale = SafeInt::from(1_000_000_000_000_000_000i128);
2081    let precision = 256u32;
2082    let max_iters = Some(DEFAULT_MAX_ITERS);
2083
2084    // Test case value, expected_result
2085    [
2086        (1_u64, 0_u64),
2087        (10, 1),
2088        (11, 1),
2089        (99, 1),
2090        // (100, 2),
2091        (101, 2),
2092        (999, 2),
2093        // (1000, 3),
2094        (1001, 3),
2095        (1_000_000_000_000_000_001, 18),
2096        (9_999_999_999_999_999_999, 18),
2097    ]
2098    .into_iter()
2099    .for_each(|(value, expected)| {
2100        assert_eq!(
2101            SafeInt::from(value).log10(&scale, precision, max_iters),
2102            Some(SafeInt::from(expected))
2103        );
2104    });
2105
2106    assert_eq!(SafeInt::from(0).log10(&scale, precision, max_iters), None);
2107    assert_eq!(SafeInt::from(-1).log10(&scale, precision, max_iters), None);
2108}