Skip to main content

fixed_bigint/
const_numtraits.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! # Const-friendly num_traits
16//!
17//! This module is essentially a fork of [num_traits](https://crates.io/crates/num_traits) with
18//! nightly const traits support.
19//!
20//! # Features
21//!
22//! - `nightly`: Enables const traits support on nightly Rust.
23//!
24//! # Examples
25
26c0nst::c0nst! {
27    // TODO: num_traits already has ConstZero and ConstOne,
28    // Consider if we should use those as a base here
29
30    /// Const-compatible zero value operations.
31    pub c0nst trait ConstZero {
32        /// Returns the additive identity (zero).
33        fn zero() -> Self;
34        /// Returns `true` if `self` is zero.
35        fn is_zero(&self) -> bool;
36        /// Sets `self` to zero.
37        fn set_zero(&mut self);
38    }
39
40    /// Const-compatible one value operations.
41    pub c0nst trait ConstOne {
42        /// Returns the multiplicative identity (one).
43        fn one() -> Self;
44        /// Returns `true` if `self` is one.
45        fn is_one(&self) -> bool;
46        /// Sets `self` to one.
47        fn set_one(&mut self);
48    }
49
50    /// Const-compatible bounded value operations.
51    pub c0nst trait ConstBounded {
52        /// Returns the smallest value of this type.
53        fn min_value() -> Self;
54        /// Returns the largest value of this type.
55        fn max_value() -> Self;
56    }
57
58    /// Const-compatible overflowing addition.
59    pub c0nst trait ConstOverflowingAdd: Sized + [c0nst] core::ops::Add<Output = Self> {
60        /// Returns a tuple of the sum along with a boolean indicating whether an arithmetic overflow would occur.
61        /// If an overflow would have occurred then the wrapped value is returned.
62        fn overflowing_add(&self, v: &Self) -> (Self, bool);
63    }
64
65    /// Const-compatible overflowing subtraction.
66    pub c0nst trait ConstOverflowingSub: Sized + [c0nst] core::ops::Sub<Output = Self> {
67        /// Returns a tuple of the difference along with a boolean indicating whether an arithmetic overflow would occur.
68        /// If an overflow would have occurred then the wrapped value is returned.
69        fn overflowing_sub(&self, v: &Self) -> (Self, bool);
70    }
71
72    /// Const-compatible wrapping addition.
73    pub c0nst trait ConstWrappingAdd: Sized + [c0nst] ConstOverflowingAdd {
74        /// Wrapping (modular) addition. Computes `self + v`, wrapping around at the boundary of the type.
75        fn wrapping_add(&self, v: &Self) -> Self;
76    }
77
78    /// Const-compatible wrapping subtraction.
79    pub c0nst trait ConstWrappingSub: Sized + [c0nst] ConstOverflowingSub {
80        /// Wrapping (modular) subtraction. Computes `self - v`, wrapping around at the boundary of the type.
81        fn wrapping_sub(&self, v: &Self) -> Self;
82    }
83
84    /// Const-compatible checked addition.
85    pub c0nst trait ConstCheckedAdd: Sized + [c0nst] ConstOverflowingAdd {
86        /// Checked addition. Returns `None` if overflow occurred.
87        fn checked_add(&self, v: &Self) -> Option<Self>;
88    }
89
90    /// Const-compatible checked subtraction.
91    pub c0nst trait ConstCheckedSub: Sized + [c0nst] ConstOverflowingSub {
92        /// Checked subtraction. Returns `None` if overflow occurred.
93        fn checked_sub(&self, v: &Self) -> Option<Self>;
94    }
95
96    /// Const-compatible saturating addition.
97    pub c0nst trait ConstSaturatingAdd: Sized + [c0nst] ConstOverflowingAdd + [c0nst] ConstBounded {
98        /// Saturating addition. Computes `self + v`, saturating at max_value().
99        fn saturating_add(&self, v: &Self) -> Self;
100    }
101
102    /// Const-compatible saturating subtraction.
103    pub c0nst trait ConstSaturatingSub: Sized + [c0nst] ConstOverflowingSub + [c0nst] ConstZero {
104        /// Saturating subtraction. Computes `self - v`, saturating at zero.
105        fn saturating_sub(&self, v: &Self) -> Self;
106    }
107
108    /// Const-compatible overflowing multiplication.
109    pub c0nst trait ConstOverflowingMul: Sized + [c0nst] core::ops::Mul<Output = Self> {
110        /// Returns a tuple of the product along with a boolean indicating whether an arithmetic overflow would occur.
111        /// If an overflow would have occurred then the wrapped value is returned.
112        fn overflowing_mul(&self, v: &Self) -> (Self, bool);
113    }
114
115    /// Const-compatible wrapping multiplication.
116    pub c0nst trait ConstWrappingMul: Sized + [c0nst] ConstOverflowingMul {
117        /// Wrapping (modular) multiplication. Computes `self * v`, wrapping around at the boundary of the type.
118        fn wrapping_mul(&self, v: &Self) -> Self;
119    }
120
121    /// Const-compatible checked multiplication.
122    pub c0nst trait ConstCheckedMul: Sized + [c0nst] ConstOverflowingMul {
123        /// Checked multiplication. Returns `None` if overflow occurred.
124        fn checked_mul(&self, v: &Self) -> Option<Self>;
125    }
126
127    /// Const-compatible saturating multiplication.
128    pub c0nst trait ConstSaturatingMul: Sized + [c0nst] ConstOverflowingMul + [c0nst] ConstBounded {
129        /// Saturating multiplication. Computes `self * v`, saturating at max_value().
130        fn saturating_mul(&self, v: &Self) -> Self;
131    }
132
133    /// Const-compatible checked division.
134    pub c0nst trait ConstCheckedDiv: Sized + [c0nst] core::ops::Div<Output = Self> + [c0nst] ConstZero {
135        /// Checked division. Returns `None` if the divisor is zero.
136        fn checked_div(&self, v: &Self) -> Option<Self>;
137    }
138
139    /// Const-compatible checked remainder.
140    pub c0nst trait ConstCheckedRem: Sized + [c0nst] core::ops::Rem<Output = Self> + [c0nst] ConstZero {
141        /// Checked remainder. Returns `None` if the divisor is zero.
142        fn checked_rem(&self, v: &Self) -> Option<Self>;
143    }
144
145    /// Const-compatible Euclidean division and remainder.
146    pub c0nst trait ConstEuclid: Sized + [c0nst] core::ops::Div<Output = Self> + [c0nst] core::ops::Rem<Output = Self> {
147        /// Euclidean division. For unsigned integers, same as regular division.
148        fn div_euclid(&self, v: &Self) -> Self;
149        /// Euclidean remainder. For unsigned integers, same as regular remainder.
150        fn rem_euclid(&self, v: &Self) -> Self;
151    }
152
153    /// Const-compatible checked Euclidean division and remainder.
154    pub c0nst trait ConstCheckedEuclid: Sized + [c0nst] ConstEuclid + [c0nst] ConstZero {
155        /// Checked Euclidean division. Returns `None` if the divisor is zero.
156        fn checked_div_euclid(&self, v: &Self) -> Option<Self>;
157        /// Checked Euclidean remainder. Returns `None` if the divisor is zero.
158        fn checked_rem_euclid(&self, v: &Self) -> Option<Self>;
159    }
160
161    /// Const-compatible overflowing left shift.
162    pub c0nst trait ConstOverflowingShl: Sized + [c0nst] core::ops::Shl<u32, Output = Self> {
163        /// Shift left with overflow detection.
164        /// Returns the shifted value and whether the shift amount exceeded the bit width.
165        fn overflowing_shl(&self, rhs: u32) -> (Self, bool);
166    }
167
168    /// Const-compatible overflowing right shift.
169    pub c0nst trait ConstOverflowingShr: Sized + [c0nst] core::ops::Shr<u32, Output = Self> {
170        /// Shift right with overflow detection.
171        /// Returns the shifted value and whether the shift amount exceeded the bit width.
172        fn overflowing_shr(&self, rhs: u32) -> (Self, bool);
173    }
174
175    /// Const-compatible wrapping left shift.
176    pub c0nst trait ConstWrappingShl: Sized + [c0nst] ConstOverflowingShl {
177        /// Wrapping shift left. Shifts, masking the shift amount to the bit width.
178        fn wrapping_shl(&self, rhs: u32) -> Self;
179    }
180
181    /// Const-compatible wrapping right shift.
182    pub c0nst trait ConstWrappingShr: Sized + [c0nst] ConstOverflowingShr {
183        /// Wrapping shift right. Shifts, masking the shift amount to the bit width.
184        fn wrapping_shr(&self, rhs: u32) -> Self;
185    }
186
187    /// Const-compatible checked left shift.
188    pub c0nst trait ConstCheckedShl: Sized + [c0nst] ConstOverflowingShl {
189        /// Checked shift left. Returns `None` if the shift amount exceeds bit width.
190        fn checked_shl(&self, rhs: u32) -> Option<Self>;
191    }
192
193    /// Const-compatible checked right shift.
194    pub c0nst trait ConstCheckedShr: Sized + [c0nst] ConstOverflowingShr {
195        /// Checked shift right. Returns `None` if the shift amount exceeds bit width.
196        fn checked_shr(&self, rhs: u32) -> Option<Self>;
197    }
198
199    /// Const-compatible byte serialization.
200    pub c0nst trait ConstToBytes {
201        /// The byte array type for this integer.
202        type Bytes: Copy + [c0nst] AsRef<[u8]> + [c0nst] AsMut<[u8]>;
203        /// Returns the little-endian byte representation.
204        fn to_le_bytes(&self) -> Self::Bytes;
205        /// Returns the big-endian byte representation.
206        fn to_be_bytes(&self) -> Self::Bytes;
207    }
208
209    /// Const-compatible byte deserialization.
210    pub c0nst trait ConstFromBytes: Sized {
211        /// The byte array type for this integer.
212        type Bytes: Copy + [c0nst] AsRef<[u8]> + [c0nst] AsMut<[u8]>;
213        /// Creates a value from its little-endian byte representation.
214        fn from_le_bytes(bytes: &Self::Bytes) -> Self;
215        /// Creates a value from its big-endian byte representation.
216        fn from_be_bytes(bytes: &Self::Bytes) -> Self;
217    }
218
219    /// Const-compatible power-of-two operations.
220    ///
221    /// These methods mirror the inherent methods on primitive integers
222    /// but are not part of num_traits.
223    ///
224    /// # Unsigned types only
225    ///
226    /// This trait is designed for unsigned integer types. Implementing it for
227    /// signed types may produce unexpected results (e.g., negative values are
228    /// never powers of two, and `next_power_of_two` behavior is undefined for
229    /// negative inputs).
230    pub c0nst trait ConstPowerOfTwo: Sized + [c0nst] ConstZero + [c0nst] ConstOne {
231        /// Returns `true` if `self` is a power of two.
232        ///
233        /// Zero is not a power of two.
234        fn is_power_of_two(&self) -> bool;
235
236        /// Returns the smallest power of two greater than or equal to `self`.
237        ///
238        /// # Panics
239        ///
240        /// Panics if the result overflows (i.e., `self > (1 << (bits-1))`).
241        fn next_power_of_two(self) -> Self;
242
243        /// Returns the smallest power of two greater than or equal to `self`.
244        ///
245        /// Returns `None` if the result would overflow.
246        fn checked_next_power_of_two(self) -> Option<Self>;
247    }
248
249    /// Const-compatible absolute difference.
250    ///
251    /// Computes the absolute difference between two values. For unsigned types,
252    /// this is `max(a, b) - min(a, b)`.
253    ///
254    /// # Unsigned types only
255    ///
256    /// This trait is designed for unsigned integer types where `abs_diff` cannot
257    /// overflow. Implementors for signed types must ensure overflow is handled
258    /// correctly (e.g., by returning an unsigned result type or using checked
259    /// arithmetic), as the trait bounds do not enforce this.
260    pub c0nst trait ConstAbsDiff: Sized + [c0nst] core::cmp::Ord + [c0nst] core::ops::Sub<Output = Self> {
261        /// Computes the absolute difference between `self` and `other`.
262        fn abs_diff(self, other: Self) -> Self;
263    }
264
265    /// Const-compatible checked exponentiation.
266    ///
267    /// Returns `None` if the result would overflow.
268    pub c0nst trait ConstCheckedPow: Sized + [c0nst] ConstOne + [c0nst] ConstCheckedMul {
269        /// Checked exponentiation. Computes `self.pow(exp)`, returning `None`
270        /// if overflow occurred.
271        fn checked_pow(self, exp: u32) -> Option<Self>;
272    }
273
274    /// Const-compatible integer logarithm operations.
275    ///
276    /// # Unsigned types only
277    ///
278    /// This trait is designed for unsigned integer types. The logarithm of zero
279    /// is undefined and will panic (or return `None` for checked variants).
280    pub c0nst trait ConstIlog: Sized + [c0nst] ConstZero + [c0nst] ConstOne + [c0nst] core::cmp::Ord + [c0nst] core::ops::Div<Output = Self> {
281        /// Returns the base 2 logarithm of the number, rounded down.
282        ///
283        /// # Panics
284        ///
285        /// Panics if `self` is zero.
286        fn ilog2(self) -> u32;
287
288        /// Returns the base 10 logarithm of the number, rounded down.
289        ///
290        /// # Panics
291        ///
292        /// Panics if `self` is zero.
293        fn ilog10(self) -> u32;
294
295        /// Returns the logarithm of the number with respect to an arbitrary base,
296        /// rounded down.
297        ///
298        /// # Panics
299        ///
300        /// Panics if `self` is zero, or if `base` is less than 2.
301        fn ilog(self, base: Self) -> u32;
302
303        /// Returns the base 2 logarithm of the number, rounded down.
304        ///
305        /// Returns `None` if `self` is zero.
306        fn checked_ilog2(self) -> Option<u32>;
307
308        /// Returns the base 10 logarithm of the number, rounded down.
309        ///
310        /// Returns `None` if `self` is zero.
311        fn checked_ilog10(self) -> Option<u32>;
312
313        /// Returns the logarithm of the number with respect to an arbitrary base,
314        /// rounded down.
315        ///
316        /// Returns `None` if `self` is zero, or if `base` is less than 2.
317        fn checked_ilog(self, base: Self) -> Option<u32>;
318    }
319
320    /// Const-compatible multiple-of operations.
321    ///
322    /// # Unsigned types only
323    ///
324    /// This trait is designed for unsigned integer types.
325    pub c0nst trait ConstMultiple: Sized + [c0nst] ConstZero + [c0nst] core::ops::Rem<Output = Self> + [c0nst] core::ops::Add<Output = Self> + [c0nst] core::ops::Sub<Output = Self> + [c0nst] core::cmp::Eq {
326        /// Returns `true` if `self` is a multiple of `rhs`.
327        ///
328        /// Returns `false` if `rhs` is zero.
329        fn is_multiple_of(&self, rhs: &Self) -> bool;
330
331        /// Returns the smallest value greater than or equal to `self` that
332        /// is a multiple of `rhs`.
333        ///
334        /// # Panics
335        ///
336        /// Panics if `rhs` is zero, or if the result would overflow.
337        fn next_multiple_of(self, rhs: Self) -> Self;
338
339        /// Returns the smallest value greater than or equal to `self` that
340        /// is a multiple of `rhs`.
341        ///
342        /// Returns `None` if `rhs` is zero, or if the result would overflow.
343        fn checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
344    }
345
346    /// Const-compatible ceiling division.
347    ///
348    /// Returns the smallest integer greater than or equal to the exact quotient.
349    pub c0nst trait ConstDivCeil: Sized + [c0nst] ConstZero + [c0nst] ConstOne + [c0nst] ConstCheckedAdd {
350        /// Calculates the quotient of `self` and `rhs`, rounding up.
351        ///
352        /// # Panics
353        ///
354        /// Panics if `rhs` is zero.
355        fn div_ceil(self, rhs: Self) -> Self;
356
357        /// Calculates the quotient of `self` and `rhs`, rounding up.
358        ///
359        /// Returns `None` if `rhs` is zero.
360        fn checked_div_ceil(self, rhs: Self) -> Option<Self>;
361    }
362
363    /// Const-compatible integer square root for unsigned integers.
364    ///
365    /// Returns the largest integer `r` such that `r * r <= self`.
366    pub c0nst trait ConstIsqrt: Sized + [c0nst] ConstZero {
367        /// Returns the integer square root of `self`.
368        fn isqrt(self) -> Self;
369
370        /// Returns the integer square root of `self`.
371        ///
372        /// For unsigned types, this always returns `Some`. The checked variant
373        /// exists for API consistency with signed types where negative values
374        /// would return `None`.
375        fn checked_isqrt(self) -> Option<Self>;
376    }
377
378    /// Const-compatible addition with carry for extended precision arithmetic.
379    ///
380    /// Performs `self + rhs + carry`, returning the sum and output carry.
381    /// This is a full adder operation useful for multi-word addition.
382    pub c0nst trait ConstCarryingAdd: Sized {
383        /// Calculates `self + rhs + carry`, returning `(sum, carry_out)`.
384        ///
385        /// The `carry` input should be `false` for normal addition or `true`
386        /// to add an additional 1 (carry from a previous addition).
387        fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool);
388    }
389
390    /// Const-compatible subtraction with borrow for extended precision arithmetic.
391    ///
392    /// Performs `self - rhs - borrow`, returning the difference and output borrow.
393    /// This is a full subtractor operation useful for multi-word subtraction.
394    pub c0nst trait ConstBorrowingSub: Sized {
395        /// Calculates `self - rhs - borrow`, returning `(difference, borrow_out)`.
396        ///
397        /// The `borrow` input should be `false` for normal subtraction or `true`
398        /// to subtract an additional 1 (borrow from a previous subtraction).
399        fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool);
400    }
401
402    /// Const-compatible widening multiplication for extended precision arithmetic.
403    ///
404    /// Multiplies two values and returns the full double-width result as (low, high).
405    pub c0nst trait ConstWideningMul: Sized {
406        /// Calculates the complete product `self * rhs` without overflow.
407        ///
408        /// Returns `(low, high)` where the full result is `high * 2^BITS + low`.
409        fn widening_mul(self, rhs: Self) -> (Self, Self);
410    }
411
412    /// Const-compatible carrying multiplication for extended precision arithmetic.
413    ///
414    /// Provides multiply-accumulate operations returning double-width results.
415    pub c0nst trait ConstCarryingMul: Sized {
416        /// Calculates `self * rhs + carry`, returning `(low, high)`.
417        ///
418        /// The result fits in double-width (2 * BITS) since
419        /// `MAX * MAX + MAX < (MAX+1)^2 = 2^(2*BITS)`.
420        fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self);
421
422        /// Calculates `self * rhs + addend + carry`, returning `(low, high)`.
423        ///
424        /// The result fits in double-width (2 * BITS) since
425        /// `MAX * MAX + MAX + MAX < (MAX+1)^2 = 2^(2*BITS)`.
426        fn carrying_mul_add(self, rhs: Self, addend: Self, carry: Self) -> (Self, Self);
427    }
428
429    /// Const-compatible midpoint calculation.
430    ///
431    /// Computes the average of two values, rounded down, without overflow.
432    /// Stable since Rust 1.85.0.
433    pub c0nst trait ConstMidpoint: Sized {
434        /// Calculates the midpoint (average) of `self` and `rhs`, rounded down.
435        ///
436        /// This never overflows, even for values close to the maximum.
437        fn midpoint(self, rhs: Self) -> Self;
438    }
439
440    /// Const-compatible unbounded shift operations.
441    ///
442    /// Unlike regular shifts, unbounded shifts don't panic when the shift
443    /// amount exceeds the bit width. Instead:
444    /// - `unbounded_shl(n)` returns 0 when n >= BITS (all bits shifted out)
445    /// - `unbounded_shr(n)` returns 0 when n >= BITS (all bits shifted out)
446    pub c0nst trait ConstUnboundedShift: Sized {
447        /// Unbounded shift left. Returns 0 if `rhs` is greater than or equal to the bit width of the type.
448        fn unbounded_shl(self, rhs: u32) -> Self;
449
450        /// Unbounded shift right. Returns 0 if `rhs` is greater than or equal to the bit width of the type.
451        fn unbounded_shr(self, rhs: u32) -> Self;
452    }
453
454    /// Base arithmetic traits for constant primitive integers.
455    ///
456    /// # Implementor requirements for default methods
457    ///
458    /// The default implementations of `leading_ones` and `trailing_ones` rely on
459    /// `!self` (bitwise NOT) producing a value with the same fixed bit-width, and
460    /// `leading_zeros`/`trailing_zeros` counting from the MSB/LSB of that full
461    /// representation. This is correct for all fixed-width unsigned integers
462    /// (primitives and `FixedUInt`), but implementors of custom types should
463    /// verify these assumptions hold or override the defaults.
464    pub c0nst trait ConstPrimInt:
465        [c0nst] core::ops::Add<Output = Self> +
466        [c0nst] core::ops::Sub<Output = Self> +
467        [c0nst] core::ops::Mul<Output = Self> +
468        [c0nst] core::ops::Div<Output = Self> +
469        [c0nst] core::ops::BitAnd<Output = Self> +
470        [c0nst] core::ops::BitOr<Output = Self> +
471        [c0nst] core::ops::BitXor<Output = Self> +
472        [c0nst] core::ops::Not<Output = Self> +
473        [c0nst] core::ops::Shl<usize, Output = Self> +
474        [c0nst] core::ops::Shr<usize, Output = Self> +
475        [c0nst] core::ops::AddAssign +
476        [c0nst] core::ops::SubAssign +
477        [c0nst] core::ops::BitAndAssign +
478        [c0nst] core::ops::BitOrAssign +
479        [c0nst] core::ops::BitXorAssign +
480        [c0nst] core::ops::ShlAssign<usize> +
481        [c0nst] core::ops::ShrAssign<usize> +
482        [c0nst] core::cmp::PartialEq +
483        [c0nst] core::cmp::Eq +
484        [c0nst] core::cmp::PartialOrd +
485        [c0nst] core::cmp::Ord +
486        [c0nst] core::convert::From<u8> +
487        [c0nst] core::default::Default +
488        [c0nst] ConstOne +
489        [c0nst] ConstZero +
490        [c0nst] ConstBounded +
491        Sized + Copy {
492
493            fn swap_bytes(self) -> Self;
494            fn leading_zeros(self) -> u32;
495            fn trailing_zeros(self) -> u32;
496            fn count_zeros(self) -> u32;
497            fn count_ones(self) -> u32;
498
499            // PR 1: Shifts, rotations, and trivial derivations
500            fn leading_ones(self) -> u32 {
501                (!self).leading_zeros()
502            }
503            fn trailing_ones(self) -> u32 {
504                (!self).trailing_zeros()
505            }
506            fn rotate_left(self, n: u32) -> Self;
507            fn rotate_right(self, n: u32) -> Self;
508            fn unsigned_shl(self, n: u32) -> Self;
509            fn unsigned_shr(self, n: u32) -> Self;
510            fn signed_shl(self, n: u32) -> Self {
511                self.unsigned_shl(n)
512            }
513            fn signed_shr(self, n: u32) -> Self {
514                self.unsigned_shr(n)
515            }
516
517            // PR 2: Endianness conversions, reverse_bits, pow
518            fn reverse_bits(self) -> Self;
519            fn from_be(x: Self) -> Self;
520            fn from_le(x: Self) -> Self;
521            fn to_be(self) -> Self;
522            fn to_le(self) -> Self;
523            fn pow(self, exp: u32) -> Self;
524    }
525}
526
527macro_rules! const_zero_impl {
528    ($t:ty, $v:expr) => {
529        c0nst::c0nst! {
530            impl c0nst ConstZero for $t {
531                fn zero() -> Self { $v }
532                fn is_zero(&self) -> bool { *self == $v }
533                fn set_zero(&mut self) { *self = $v }
534            }
535        }
536    };
537}
538
539macro_rules! const_one_impl {
540    ($t:ty, $v:expr) => {
541        c0nst::c0nst! {
542            impl c0nst ConstOne for $t {
543                fn one() -> Self { $v }
544                fn is_one(&self) -> bool { *self == $v }
545                fn set_one(&mut self) { *self = $v }
546            }
547        }
548    };
549}
550
551macro_rules! const_bounded_impl {
552    ($t:ty, $min:expr, $max:expr) => {
553        c0nst::c0nst! {
554            impl c0nst ConstBounded for $t {
555                fn min_value() -> Self { $min }
556                fn max_value() -> Self { $max }
557            }
558        }
559    };
560}
561
562macro_rules! const_prim_int_impl {
563    ($t:ty) => {
564        c0nst::c0nst! {
565            impl c0nst ConstPrimInt for $t {
566                fn leading_zeros(self) -> u32 { self.leading_zeros() }
567                fn trailing_zeros(self) -> u32 { self.trailing_zeros() }
568                fn count_zeros(self) -> u32 { self.count_zeros() }
569                fn count_ones(self) -> u32 { self.count_ones() }
570                fn swap_bytes(self) -> Self { self.swap_bytes() }
571                fn rotate_left(self, n: u32) -> Self { self.rotate_left(n) }
572                fn rotate_right(self, n: u32) -> Self { self.rotate_right(n) }
573                fn unsigned_shl(self, n: u32) -> Self { self << n }
574                fn unsigned_shr(self, n: u32) -> Self { self >> n }
575                fn reverse_bits(self) -> Self { self.reverse_bits() }
576                fn from_be(x: Self) -> Self { <$t>::from_be(x) }
577                fn from_le(x: Self) -> Self { <$t>::from_le(x) }
578                fn to_be(self) -> Self { self.to_be() }
579                fn to_le(self) -> Self { self.to_le() }
580                fn pow(self, exp: u32) -> Self { self.pow(exp) }
581            }
582        }
583    };
584}
585
586macro_rules! const_overflowing_add_impl {
587    ($t:ty) => {
588        c0nst::c0nst! {
589            impl c0nst ConstOverflowingAdd for $t {
590                fn overflowing_add(&self, v: &Self) -> (Self, bool) {
591                    (*self).overflowing_add(*v)
592                }
593            }
594        }
595    };
596}
597
598macro_rules! const_overflowing_sub_impl {
599    ($t:ty) => {
600        c0nst::c0nst! {
601            impl c0nst ConstOverflowingSub for $t {
602                fn overflowing_sub(&self, v: &Self) -> (Self, bool) {
603                    (*self).overflowing_sub(*v)
604                }
605            }
606        }
607    };
608}
609
610const_zero_impl!(u8, 0);
611const_zero_impl!(u16, 0);
612const_zero_impl!(u32, 0);
613const_zero_impl!(u64, 0);
614const_zero_impl!(u128, 0);
615
616const_one_impl!(u8, 1);
617const_one_impl!(u16, 1);
618const_one_impl!(u32, 1);
619const_one_impl!(u64, 1);
620const_one_impl!(u128, 1);
621
622const_bounded_impl!(u8, u8::MIN, u8::MAX);
623const_bounded_impl!(u16, u16::MIN, u16::MAX);
624const_bounded_impl!(u32, u32::MIN, u32::MAX);
625const_bounded_impl!(u64, u64::MIN, u64::MAX);
626const_bounded_impl!(u128, u128::MIN, u128::MAX);
627
628const_overflowing_add_impl!(u8);
629const_overflowing_add_impl!(u16);
630const_overflowing_add_impl!(u32);
631const_overflowing_add_impl!(u64);
632const_overflowing_add_impl!(u128);
633
634const_overflowing_sub_impl!(u8);
635const_overflowing_sub_impl!(u16);
636const_overflowing_sub_impl!(u32);
637const_overflowing_sub_impl!(u64);
638const_overflowing_sub_impl!(u128);
639
640macro_rules! const_wrapping_add_impl {
641    ($t:ty) => {
642        c0nst::c0nst! {
643            impl c0nst ConstWrappingAdd for $t {
644                fn wrapping_add(&self, v: &Self) -> Self {
645                    self.overflowing_add(v).0
646                }
647            }
648        }
649    };
650}
651
652macro_rules! const_wrapping_sub_impl {
653    ($t:ty) => {
654        c0nst::c0nst! {
655            impl c0nst ConstWrappingSub for $t {
656                fn wrapping_sub(&self, v: &Self) -> Self {
657                    self.overflowing_sub(v).0
658                }
659            }
660        }
661    };
662}
663
664macro_rules! const_checked_add_impl {
665    ($t:ty) => {
666        c0nst::c0nst! {
667            impl c0nst ConstCheckedAdd for $t {
668                fn checked_add(&self, v: &Self) -> Option<Self> {
669                    let (res, overflow) = self.overflowing_add(v);
670                    if overflow { None } else { Some(res) }
671                }
672            }
673        }
674    };
675}
676
677macro_rules! const_checked_sub_impl {
678    ($t:ty) => {
679        c0nst::c0nst! {
680            impl c0nst ConstCheckedSub for $t {
681                fn checked_sub(&self, v: &Self) -> Option<Self> {
682                    let (res, overflow) = self.overflowing_sub(v);
683                    if overflow { None } else { Some(res) }
684                }
685            }
686        }
687    };
688}
689
690const_wrapping_add_impl!(u8);
691const_wrapping_add_impl!(u16);
692const_wrapping_add_impl!(u32);
693const_wrapping_add_impl!(u64);
694const_wrapping_add_impl!(u128);
695
696const_wrapping_sub_impl!(u8);
697const_wrapping_sub_impl!(u16);
698const_wrapping_sub_impl!(u32);
699const_wrapping_sub_impl!(u64);
700const_wrapping_sub_impl!(u128);
701
702const_checked_add_impl!(u8);
703const_checked_add_impl!(u16);
704const_checked_add_impl!(u32);
705const_checked_add_impl!(u64);
706const_checked_add_impl!(u128);
707
708const_checked_sub_impl!(u8);
709const_checked_sub_impl!(u16);
710const_checked_sub_impl!(u32);
711const_checked_sub_impl!(u64);
712const_checked_sub_impl!(u128);
713
714macro_rules! const_saturating_add_impl {
715    ($t:ty) => {
716        c0nst::c0nst! {
717            impl c0nst ConstSaturatingAdd for $t {
718                fn saturating_add(&self, v: &Self) -> Self {
719                    let (res, overflow) = self.overflowing_add(v);
720                    if overflow { Self::max_value() } else { res }
721                }
722            }
723        }
724    };
725}
726
727macro_rules! const_saturating_sub_impl {
728    ($t:ty) => {
729        c0nst::c0nst! {
730            impl c0nst ConstSaturatingSub for $t {
731                fn saturating_sub(&self, v: &Self) -> Self {
732                    let (res, overflow) = self.overflowing_sub(v);
733                    if overflow { Self::zero() } else { res }
734                }
735            }
736        }
737    };
738}
739
740const_saturating_add_impl!(u8);
741const_saturating_add_impl!(u16);
742const_saturating_add_impl!(u32);
743const_saturating_add_impl!(u64);
744const_saturating_add_impl!(u128);
745
746const_saturating_sub_impl!(u8);
747const_saturating_sub_impl!(u16);
748const_saturating_sub_impl!(u32);
749const_saturating_sub_impl!(u64);
750const_saturating_sub_impl!(u128);
751
752macro_rules! const_overflowing_mul_impl {
753    ($t:ty) => {
754        c0nst::c0nst! {
755            impl c0nst ConstOverflowingMul for $t {
756                fn overflowing_mul(&self, v: &Self) -> (Self, bool) {
757                    (*self).overflowing_mul(*v)
758                }
759            }
760        }
761    };
762}
763
764macro_rules! const_wrapping_mul_impl {
765    ($t:ty) => {
766        c0nst::c0nst! {
767            impl c0nst ConstWrappingMul for $t {
768                fn wrapping_mul(&self, v: &Self) -> Self {
769                    self.overflowing_mul(v).0
770                }
771            }
772        }
773    };
774}
775
776macro_rules! const_checked_mul_impl {
777    ($t:ty) => {
778        c0nst::c0nst! {
779            impl c0nst ConstCheckedMul for $t {
780                fn checked_mul(&self, v: &Self) -> Option<Self> {
781                    let (res, overflow) = self.overflowing_mul(v);
782                    if overflow { None } else { Some(res) }
783                }
784            }
785        }
786    };
787}
788
789macro_rules! const_saturating_mul_impl {
790    ($t:ty) => {
791        c0nst::c0nst! {
792            impl c0nst ConstSaturatingMul for $t {
793                fn saturating_mul(&self, v: &Self) -> Self {
794                    let (res, overflow) = self.overflowing_mul(v);
795                    if overflow { Self::max_value() } else { res }
796                }
797            }
798        }
799    };
800}
801
802const_overflowing_mul_impl!(u8);
803const_overflowing_mul_impl!(u16);
804const_overflowing_mul_impl!(u32);
805const_overflowing_mul_impl!(u64);
806const_overflowing_mul_impl!(u128);
807
808const_wrapping_mul_impl!(u8);
809const_wrapping_mul_impl!(u16);
810const_wrapping_mul_impl!(u32);
811const_wrapping_mul_impl!(u64);
812const_wrapping_mul_impl!(u128);
813
814const_checked_mul_impl!(u8);
815const_checked_mul_impl!(u16);
816const_checked_mul_impl!(u32);
817const_checked_mul_impl!(u64);
818const_checked_mul_impl!(u128);
819
820const_saturating_mul_impl!(u8);
821const_saturating_mul_impl!(u16);
822const_saturating_mul_impl!(u32);
823const_saturating_mul_impl!(u64);
824const_saturating_mul_impl!(u128);
825
826macro_rules! const_checked_div_impl {
827    ($t:ty) => {
828        c0nst::c0nst! {
829            impl c0nst ConstCheckedDiv for $t {
830                fn checked_div(&self, v: &Self) -> Option<Self> {
831                    if v.is_zero() { None } else { Some(*self / *v) }
832                }
833            }
834        }
835    };
836}
837
838macro_rules! const_checked_rem_impl {
839    ($t:ty) => {
840        c0nst::c0nst! {
841            impl c0nst ConstCheckedRem for $t {
842                fn checked_rem(&self, v: &Self) -> Option<Self> {
843                    if v.is_zero() { None } else { Some(*self % *v) }
844                }
845            }
846        }
847    };
848}
849
850const_checked_div_impl!(u8);
851const_checked_div_impl!(u16);
852const_checked_div_impl!(u32);
853const_checked_div_impl!(u64);
854const_checked_div_impl!(u128);
855
856const_checked_rem_impl!(u8);
857const_checked_rem_impl!(u16);
858const_checked_rem_impl!(u32);
859const_checked_rem_impl!(u64);
860const_checked_rem_impl!(u128);
861
862macro_rules! const_euclid_impl {
863    ($t:ty) => {
864        c0nst::c0nst! {
865            impl c0nst ConstEuclid for $t {
866                fn div_euclid(&self, v: &Self) -> Self {
867                    // For unsigned integers, Euclidean division is the same as regular division
868                    *self / *v
869                }
870                fn rem_euclid(&self, v: &Self) -> Self {
871                    // For unsigned integers, Euclidean remainder is the same as regular remainder
872                    *self % *v
873                }
874            }
875        }
876    };
877}
878
879macro_rules! const_checked_euclid_impl {
880    ($t:ty) => {
881        c0nst::c0nst! {
882            impl c0nst ConstCheckedEuclid for $t {
883                fn checked_div_euclid(&self, v: &Self) -> Option<Self> {
884                    if v.is_zero() { None } else { Some(*self / *v) }
885                }
886                fn checked_rem_euclid(&self, v: &Self) -> Option<Self> {
887                    if v.is_zero() { None } else { Some(*self % *v) }
888                }
889            }
890        }
891    };
892}
893
894const_euclid_impl!(u8);
895const_euclid_impl!(u16);
896const_euclid_impl!(u32);
897const_euclid_impl!(u64);
898const_euclid_impl!(u128);
899
900const_checked_euclid_impl!(u8);
901const_checked_euclid_impl!(u16);
902const_checked_euclid_impl!(u32);
903const_checked_euclid_impl!(u64);
904const_checked_euclid_impl!(u128);
905
906macro_rules! const_overflowing_shl_impl {
907    ($t:ty) => {
908        c0nst::c0nst! {
909            impl c0nst ConstOverflowingShl for $t {
910                fn overflowing_shl(&self, rhs: u32) -> (Self, bool) {
911                    (*self).overflowing_shl(rhs)
912                }
913            }
914        }
915    };
916}
917
918macro_rules! const_overflowing_shr_impl {
919    ($t:ty) => {
920        c0nst::c0nst! {
921            impl c0nst ConstOverflowingShr for $t {
922                fn overflowing_shr(&self, rhs: u32) -> (Self, bool) {
923                    (*self).overflowing_shr(rhs)
924                }
925            }
926        }
927    };
928}
929
930macro_rules! const_wrapping_shl_impl {
931    ($t:ty) => {
932        c0nst::c0nst! {
933            impl c0nst ConstWrappingShl for $t {
934                fn wrapping_shl(&self, rhs: u32) -> Self {
935                    ConstOverflowingShl::overflowing_shl(self, rhs).0
936                }
937            }
938        }
939    };
940}
941
942macro_rules! const_wrapping_shr_impl {
943    ($t:ty) => {
944        c0nst::c0nst! {
945            impl c0nst ConstWrappingShr for $t {
946                fn wrapping_shr(&self, rhs: u32) -> Self {
947                    ConstOverflowingShr::overflowing_shr(self, rhs).0
948                }
949            }
950        }
951    };
952}
953
954macro_rules! const_checked_shl_impl {
955    ($t:ty) => {
956        c0nst::c0nst! {
957            impl c0nst ConstCheckedShl for $t {
958                fn checked_shl(&self, rhs: u32) -> Option<Self> {
959                    let (res, overflow) = ConstOverflowingShl::overflowing_shl(self, rhs);
960                    if overflow { None } else { Some(res) }
961                }
962            }
963        }
964    };
965}
966
967macro_rules! const_checked_shr_impl {
968    ($t:ty) => {
969        c0nst::c0nst! {
970            impl c0nst ConstCheckedShr for $t {
971                fn checked_shr(&self, rhs: u32) -> Option<Self> {
972                    let (res, overflow) = ConstOverflowingShr::overflowing_shr(self, rhs);
973                    if overflow { None } else { Some(res) }
974                }
975            }
976        }
977    };
978}
979
980const_overflowing_shl_impl!(u8);
981const_overflowing_shl_impl!(u16);
982const_overflowing_shl_impl!(u32);
983const_overflowing_shl_impl!(u64);
984const_overflowing_shl_impl!(u128);
985
986const_overflowing_shr_impl!(u8);
987const_overflowing_shr_impl!(u16);
988const_overflowing_shr_impl!(u32);
989const_overflowing_shr_impl!(u64);
990const_overflowing_shr_impl!(u128);
991
992const_wrapping_shl_impl!(u8);
993const_wrapping_shl_impl!(u16);
994const_wrapping_shl_impl!(u32);
995const_wrapping_shl_impl!(u64);
996const_wrapping_shl_impl!(u128);
997
998const_wrapping_shr_impl!(u8);
999const_wrapping_shr_impl!(u16);
1000const_wrapping_shr_impl!(u32);
1001const_wrapping_shr_impl!(u64);
1002const_wrapping_shr_impl!(u128);
1003
1004const_checked_shl_impl!(u8);
1005const_checked_shl_impl!(u16);
1006const_checked_shl_impl!(u32);
1007const_checked_shl_impl!(u64);
1008const_checked_shl_impl!(u128);
1009
1010const_checked_shr_impl!(u8);
1011const_checked_shr_impl!(u16);
1012const_checked_shr_impl!(u32);
1013const_checked_shr_impl!(u64);
1014const_checked_shr_impl!(u128);
1015
1016macro_rules! const_to_bytes_impl {
1017    ($t:ty, $n:expr) => {
1018        c0nst::c0nst! {
1019            impl c0nst ConstToBytes for $t {
1020                type Bytes = [u8; $n];
1021                fn to_le_bytes(&self) -> [u8; $n] { (*self).to_le_bytes() }
1022                fn to_be_bytes(&self) -> [u8; $n] { (*self).to_be_bytes() }
1023            }
1024        }
1025    };
1026}
1027
1028const_to_bytes_impl!(u8, 1);
1029const_to_bytes_impl!(u16, 2);
1030const_to_bytes_impl!(u32, 4);
1031const_to_bytes_impl!(u64, 8);
1032const_to_bytes_impl!(u128, 16);
1033
1034macro_rules! const_from_bytes_impl {
1035    ($t:ty, $n:expr) => {
1036        c0nst::c0nst! {
1037            impl c0nst ConstFromBytes for $t {
1038                type Bytes = [u8; $n];
1039                fn from_le_bytes(bytes: &[u8; $n]) -> Self { <$t>::from_le_bytes(*bytes) }
1040                fn from_be_bytes(bytes: &[u8; $n]) -> Self { <$t>::from_be_bytes(*bytes) }
1041            }
1042        }
1043    };
1044}
1045
1046const_from_bytes_impl!(u8, 1);
1047const_from_bytes_impl!(u16, 2);
1048const_from_bytes_impl!(u32, 4);
1049const_from_bytes_impl!(u64, 8);
1050const_from_bytes_impl!(u128, 16);
1051
1052macro_rules! const_power_of_two_impl {
1053    ($t:ty) => {
1054        c0nst::c0nst! {
1055            impl c0nst ConstPowerOfTwo for $t {
1056                fn is_power_of_two(&self) -> bool {
1057                    (*self).is_power_of_two()
1058                }
1059                fn next_power_of_two(self) -> Self {
1060                    self.next_power_of_two()
1061                }
1062                fn checked_next_power_of_two(self) -> Option<Self> {
1063                    self.checked_next_power_of_two()
1064                }
1065            }
1066        }
1067    };
1068}
1069
1070const_power_of_two_impl!(u8);
1071const_power_of_two_impl!(u16);
1072const_power_of_two_impl!(u32);
1073const_power_of_two_impl!(u64);
1074const_power_of_two_impl!(u128);
1075
1076macro_rules! const_abs_diff_impl {
1077    ($t:ty) => {
1078        c0nst::c0nst! {
1079            impl c0nst ConstAbsDiff for $t {
1080                fn abs_diff(self, other: Self) -> Self {
1081                    <$t>::abs_diff(self, other)
1082                }
1083            }
1084        }
1085    };
1086}
1087
1088const_abs_diff_impl!(u8);
1089const_abs_diff_impl!(u16);
1090const_abs_diff_impl!(u32);
1091const_abs_diff_impl!(u64);
1092const_abs_diff_impl!(u128);
1093
1094macro_rules! const_checked_pow_impl {
1095    ($t:ty) => {
1096        c0nst::c0nst! {
1097            impl c0nst ConstCheckedPow for $t {
1098                fn checked_pow(self, exp: u32) -> Option<Self> {
1099                    self.checked_pow(exp)
1100                }
1101            }
1102        }
1103    };
1104}
1105
1106const_checked_pow_impl!(u8);
1107const_checked_pow_impl!(u16);
1108const_checked_pow_impl!(u32);
1109const_checked_pow_impl!(u64);
1110const_checked_pow_impl!(u128);
1111
1112macro_rules! const_ilog_impl {
1113    ($t:ty) => {
1114        c0nst::c0nst! {
1115            impl c0nst ConstIlog for $t {
1116                fn ilog2(self) -> u32 {
1117                    self.ilog2()
1118                }
1119                fn ilog10(self) -> u32 {
1120                    self.ilog10()
1121                }
1122                fn ilog(self, base: Self) -> u32 {
1123                    self.ilog(base)
1124                }
1125                fn checked_ilog2(self) -> Option<u32> {
1126                    self.checked_ilog2()
1127                }
1128                fn checked_ilog10(self) -> Option<u32> {
1129                    self.checked_ilog10()
1130                }
1131                fn checked_ilog(self, base: Self) -> Option<u32> {
1132                    self.checked_ilog(base)
1133                }
1134            }
1135        }
1136    };
1137}
1138
1139const_ilog_impl!(u8);
1140const_ilog_impl!(u16);
1141const_ilog_impl!(u32);
1142const_ilog_impl!(u64);
1143const_ilog_impl!(u128);
1144
1145// Native is_multiple_of() requires Rust 1.87+, gate behind 1_87 feature
1146#[cfg(not(feature = "1_87"))]
1147macro_rules! const_multiple_impl {
1148    ($t:ty) => {
1149        c0nst::c0nst! {
1150            impl c0nst ConstMultiple for $t {
1151                fn is_multiple_of(&self, rhs: &Self) -> bool {
1152                    if rhs.is_zero() {
1153                        false
1154                    } else {
1155                        *self % *rhs == 0
1156                    }
1157                }
1158                fn next_multiple_of(self, rhs: Self) -> Self {
1159                    self.next_multiple_of(rhs)
1160                }
1161                fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1162                    self.checked_next_multiple_of(rhs)
1163                }
1164            }
1165        }
1166    };
1167}
1168
1169#[cfg(feature = "1_87")]
1170macro_rules! const_multiple_impl {
1171    ($t:ty) => {
1172        c0nst::c0nst! {
1173            impl c0nst ConstMultiple for $t {
1174                fn is_multiple_of(&self, rhs: &Self) -> bool {
1175                    <$t>::is_multiple_of(*self, *rhs)
1176                }
1177                fn next_multiple_of(self, rhs: Self) -> Self {
1178                    self.next_multiple_of(rhs)
1179                }
1180                fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1181                    self.checked_next_multiple_of(rhs)
1182                }
1183            }
1184        }
1185    };
1186}
1187
1188const_multiple_impl!(u8);
1189const_multiple_impl!(u16);
1190const_multiple_impl!(u32);
1191const_multiple_impl!(u64);
1192const_multiple_impl!(u128);
1193
1194macro_rules! const_div_ceil_impl {
1195    ($t:ty) => {
1196        c0nst::c0nst! {
1197            impl c0nst ConstDivCeil for $t {
1198                fn div_ceil(self, rhs: Self) -> Self {
1199                    <$t>::div_ceil(self, rhs)
1200                }
1201                fn checked_div_ceil(self, rhs: Self) -> Option<Self> {
1202                    if rhs.is_zero() {
1203                        None
1204                    } else {
1205                        Some(<$t>::div_ceil(self, rhs))
1206                    }
1207                }
1208            }
1209        }
1210    };
1211}
1212
1213const_div_ceil_impl!(u8);
1214const_div_ceil_impl!(u16);
1215const_div_ceil_impl!(u32);
1216const_div_ceil_impl!(u64);
1217const_div_ceil_impl!(u128);
1218
1219// Primitive isqrt requires Rust 1.84+, gate behind nightly
1220#[cfg(feature = "nightly")]
1221macro_rules! const_isqrt_impl {
1222    ($t:ty) => {
1223        c0nst::c0nst! {
1224            impl c0nst ConstIsqrt for $t {
1225                fn isqrt(self) -> Self {
1226                    <$t>::isqrt(self)
1227                }
1228                fn checked_isqrt(self) -> Option<Self> {
1229                    // For unsigned types, isqrt always succeeds
1230                    Some(<$t>::isqrt(self))
1231                }
1232            }
1233        }
1234    };
1235}
1236
1237#[cfg(feature = "nightly")]
1238const_isqrt_impl!(u8);
1239#[cfg(feature = "nightly")]
1240const_isqrt_impl!(u16);
1241#[cfg(feature = "nightly")]
1242const_isqrt_impl!(u32);
1243#[cfg(feature = "nightly")]
1244const_isqrt_impl!(u64);
1245#[cfg(feature = "nightly")]
1246const_isqrt_impl!(u128);
1247
1248// Extended precision primitive implementations
1249// Native bigint_helper_methods stable since Rust 1.91.0
1250#[cfg(not(feature = "nightly"))]
1251macro_rules! const_carrying_add_impl {
1252    ($t:ty) => {
1253        c0nst::c0nst! {
1254            impl c0nst ConstCarryingAdd for $t {
1255                fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
1256                    let (sum1, c1) = self.overflowing_add(rhs);
1257                    let (sum2, c2) = sum1.overflowing_add(carry as $t);
1258                    (sum2, c1 || c2)
1259                }
1260            }
1261        }
1262    };
1263}
1264
1265#[cfg(feature = "nightly")]
1266macro_rules! const_carrying_add_impl {
1267    ($t:ty) => {
1268        c0nst::c0nst! {
1269            impl c0nst ConstCarryingAdd for $t {
1270                fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
1271                    <$t>::carrying_add(self, rhs, carry)
1272                }
1273            }
1274        }
1275    };
1276}
1277
1278#[cfg(not(feature = "nightly"))]
1279macro_rules! const_borrowing_sub_impl {
1280    ($t:ty) => {
1281        c0nst::c0nst! {
1282            impl c0nst ConstBorrowingSub for $t {
1283                fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
1284                    let (diff1, b1) = self.overflowing_sub(rhs);
1285                    let (diff2, b2) = diff1.overflowing_sub(borrow as $t);
1286                    (diff2, b1 || b2)
1287                }
1288            }
1289        }
1290    };
1291}
1292
1293#[cfg(feature = "nightly")]
1294macro_rules! const_borrowing_sub_impl {
1295    ($t:ty) => {
1296        c0nst::c0nst! {
1297            impl c0nst ConstBorrowingSub for $t {
1298                fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
1299                    <$t>::borrowing_sub(self, rhs, borrow)
1300                }
1301            }
1302        }
1303    };
1304}
1305
1306#[cfg(not(feature = "nightly"))]
1307macro_rules! const_widening_mul_impl {
1308    ($t:ty, $double:ty, $bits:expr) => {
1309        c0nst::c0nst! {
1310            impl c0nst ConstWideningMul for $t {
1311                fn widening_mul(self, rhs: Self) -> (Self, Self) {
1312                    let product = (self as $double) * (rhs as $double);
1313                    (product as $t, (product >> $bits) as $t)
1314                }
1315            }
1316        }
1317    };
1318}
1319
1320#[cfg(feature = "nightly")]
1321macro_rules! const_widening_mul_impl {
1322    ($t:ty, $double:ty, $bits:expr) => {
1323        c0nst::c0nst! {
1324            impl c0nst ConstWideningMul for $t {
1325                fn widening_mul(self, rhs: Self) -> (Self, Self) {
1326                    <$t>::widening_mul(self, rhs)
1327                }
1328            }
1329        }
1330    };
1331}
1332
1333#[cfg(not(feature = "nightly"))]
1334macro_rules! const_carrying_mul_impl {
1335    ($t:ty, $double:ty, $bits:expr) => {
1336        c0nst::c0nst! {
1337            impl c0nst ConstCarryingMul for $t {
1338                fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
1339                    let product = (self as $double) * (rhs as $double) + (carry as $double);
1340                    (product as $t, (product >> $bits) as $t)
1341                }
1342                fn carrying_mul_add(self, rhs: Self, addend: Self, carry: Self) -> (Self, Self) {
1343                    let product = (self as $double) * (rhs as $double)
1344                        + (addend as $double)
1345                        + (carry as $double);
1346                    (product as $t, (product >> $bits) as $t)
1347                }
1348            }
1349        }
1350    };
1351}
1352
1353#[cfg(feature = "nightly")]
1354macro_rules! const_carrying_mul_impl {
1355    ($t:ty, $double:ty, $bits:expr) => {
1356        c0nst::c0nst! {
1357            impl c0nst ConstCarryingMul for $t {
1358                fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
1359                    <$t>::carrying_mul(self, rhs, carry)
1360                }
1361                fn carrying_mul_add(self, rhs: Self, addend: Self, carry: Self) -> (Self, Self) {
1362                    // No native carrying_mul_add, use carrying_mul + overflowing_add
1363                    let (lo, hi) = <$t>::carrying_mul(self, rhs, carry);
1364                    let (lo2, c) = lo.overflowing_add(addend);
1365                    (lo2, hi.wrapping_add(c as $t))
1366                }
1367            }
1368        }
1369    };
1370}
1371
1372const_carrying_add_impl!(u8);
1373const_carrying_add_impl!(u16);
1374const_carrying_add_impl!(u32);
1375const_carrying_add_impl!(u64);
1376const_carrying_add_impl!(u128);
1377
1378const_borrowing_sub_impl!(u8);
1379const_borrowing_sub_impl!(u16);
1380const_borrowing_sub_impl!(u32);
1381const_borrowing_sub_impl!(u64);
1382const_borrowing_sub_impl!(u128);
1383
1384const_widening_mul_impl!(u8, u16, 8);
1385const_widening_mul_impl!(u16, u32, 16);
1386const_widening_mul_impl!(u32, u64, 32);
1387const_widening_mul_impl!(u64, u128, 64);
1388// TODO: u128 widening_mul requires u256 type (not available in Rust)
1389
1390const_carrying_mul_impl!(u8, u16, 8);
1391const_carrying_mul_impl!(u16, u32, 16);
1392const_carrying_mul_impl!(u32, u64, 32);
1393const_carrying_mul_impl!(u64, u128, 64);
1394// TODO: u128 carrying_mul requires u256 type (not available in Rust)
1395
1396// Native midpoint() requires Rust 1.85+, gate behind 1_87 feature
1397#[cfg(not(feature = "1_87"))]
1398macro_rules! const_midpoint_impl {
1399    ($t:ty) => {
1400        c0nst::c0nst! {
1401            impl c0nst ConstMidpoint for $t {
1402                fn midpoint(self, rhs: Self) -> Self {
1403                    // (a & b) + ((a ^ b) >> 1) avoids overflow
1404                    (self & rhs) + ((self ^ rhs) >> 1)
1405                }
1406            }
1407        }
1408    };
1409}
1410
1411#[cfg(feature = "1_87")]
1412macro_rules! const_midpoint_impl {
1413    ($t:ty) => {
1414        c0nst::c0nst! {
1415            impl c0nst ConstMidpoint for $t {
1416                fn midpoint(self, rhs: Self) -> Self {
1417                    <$t>::midpoint(self, rhs)
1418                }
1419            }
1420        }
1421    };
1422}
1423
1424const_midpoint_impl!(u8);
1425const_midpoint_impl!(u16);
1426const_midpoint_impl!(u32);
1427const_midpoint_impl!(u64);
1428const_midpoint_impl!(u128);
1429
1430// Native unbounded_shl/shr() requires Rust 1.85+, gate behind 1_87 feature
1431#[cfg(not(feature = "1_87"))]
1432macro_rules! const_unbounded_shift_impl {
1433    ($t:ty, $bits:expr) => {
1434        c0nst::c0nst! {
1435            impl c0nst ConstUnboundedShift for $t {
1436                fn unbounded_shl(self, rhs: u32) -> Self {
1437                    if rhs >= $bits { 0 } else { self << rhs }
1438                }
1439                fn unbounded_shr(self, rhs: u32) -> Self {
1440                    if rhs >= $bits { 0 } else { self >> rhs }
1441                }
1442            }
1443        }
1444    };
1445}
1446
1447#[cfg(feature = "1_87")]
1448macro_rules! const_unbounded_shift_impl {
1449    ($t:ty, $bits:expr) => {
1450        c0nst::c0nst! {
1451            impl c0nst ConstUnboundedShift for $t {
1452                fn unbounded_shl(self, rhs: u32) -> Self {
1453                    <$t>::unbounded_shl(self, rhs)
1454                }
1455                fn unbounded_shr(self, rhs: u32) -> Self {
1456                    <$t>::unbounded_shr(self, rhs)
1457                }
1458            }
1459        }
1460    };
1461}
1462
1463const_unbounded_shift_impl!(u8, 8);
1464const_unbounded_shift_impl!(u16, 16);
1465const_unbounded_shift_impl!(u32, 32);
1466const_unbounded_shift_impl!(u64, 64);
1467const_unbounded_shift_impl!(u128, 128);
1468
1469const_prim_int_impl!(u8);
1470const_prim_int_impl!(u16);
1471const_prim_int_impl!(u32);
1472const_prim_int_impl!(u64);
1473const_prim_int_impl!(u128);
1474
1475#[cfg(test)]
1476mod tests {
1477    use super::*;
1478
1479    c0nst::c0nst! {
1480        pub c0nst fn add_words<T: [c0nst] ConstPrimInt>(a: T, b: T) -> T {
1481            a + b
1482        }
1483
1484        pub c0nst fn assign_add<T: [c0nst] ConstPrimInt>(a: &mut T, b: T) {
1485            *a += b;
1486        }
1487
1488        pub c0nst fn default_word<T: [c0nst] ConstPrimInt>() -> T {
1489            T::default()
1490        }
1491
1492        pub c0nst fn zero_word<T: [c0nst] ConstZero>() -> T {
1493            T::zero()
1494        }
1495
1496        pub c0nst fn one_word<T: [c0nst] ConstOne>() -> T {
1497            T::one()
1498        }
1499
1500        pub c0nst fn min_word<T: [c0nst] ConstBounded>() -> T {
1501            T::min_value()
1502        }
1503
1504        pub c0nst fn max_word<T: [c0nst] ConstBounded>() -> T {
1505            T::max_value()
1506        }
1507
1508        pub c0nst fn is_zero_word<T: [c0nst] ConstZero>(v: &T) -> bool {
1509            v.is_zero()
1510        }
1511
1512        pub c0nst fn set_zero_word<T: [c0nst] ConstZero>(v: &mut T) {
1513            v.set_zero();
1514        }
1515
1516        pub c0nst fn is_one_word<T: [c0nst] ConstOne>(v: &T) -> bool {
1517            v.is_one()
1518        }
1519
1520        pub c0nst fn set_one_word<T: [c0nst] ConstOne>(v: &mut T) {
1521            v.set_one();
1522        }
1523
1524        pub c0nst fn overflowing_add_word<T: [c0nst] ConstOverflowingAdd>(a: &T, b: &T) -> (T, bool) {
1525            a.overflowing_add(b)
1526        }
1527
1528        pub c0nst fn overflowing_sub_word<T: [c0nst] ConstOverflowingSub>(a: &T, b: &T) -> (T, bool) {
1529            a.overflowing_sub(b)
1530        }
1531
1532        pub c0nst fn to_le_bytes_word<T: [c0nst] ConstToBytes>(v: &T) -> T::Bytes {
1533            v.to_le_bytes()
1534        }
1535
1536        pub c0nst fn to_be_bytes_word<T: [c0nst] ConstToBytes>(v: &T) -> T::Bytes {
1537            v.to_be_bytes()
1538        }
1539
1540        pub c0nst fn from_le_bytes_word<T: [c0nst] ConstFromBytes>(bytes: &T::Bytes) -> T {
1541            T::from_le_bytes(bytes)
1542        }
1543
1544        pub c0nst fn from_be_bytes_word<T: [c0nst] ConstFromBytes>(bytes: &T::Bytes) -> T {
1545            T::from_be_bytes(bytes)
1546        }
1547
1548        pub c0nst fn wrapping_add_word<T: [c0nst] ConstWrappingAdd>(a: &T, b: &T) -> T {
1549            a.wrapping_add(b)
1550        }
1551
1552        pub c0nst fn wrapping_sub_word<T: [c0nst] ConstWrappingSub>(a: &T, b: &T) -> T {
1553            a.wrapping_sub(b)
1554        }
1555
1556        pub c0nst fn checked_add_word<T: [c0nst] ConstCheckedAdd>(a: &T, b: &T) -> Option<T> {
1557            a.checked_add(b)
1558        }
1559
1560        pub c0nst fn checked_sub_word<T: [c0nst] ConstCheckedSub>(a: &T, b: &T) -> Option<T> {
1561            a.checked_sub(b)
1562        }
1563
1564        pub c0nst fn saturating_add_word<T: [c0nst] ConstSaturatingAdd>(a: &T, b: &T) -> T {
1565            a.saturating_add(b)
1566        }
1567
1568        pub c0nst fn saturating_sub_word<T: [c0nst] ConstSaturatingSub>(a: &T, b: &T) -> T {
1569            a.saturating_sub(b)
1570        }
1571
1572        pub c0nst fn carrying_add_word<T: [c0nst] ConstCarryingAdd>(a: T, b: T, carry: bool) -> (T, bool) {
1573            a.carrying_add(b, carry)
1574        }
1575
1576        pub c0nst fn borrowing_sub_word<T: [c0nst] ConstBorrowingSub>(a: T, b: T, borrow: bool) -> (T, bool) {
1577            a.borrowing_sub(b, borrow)
1578        }
1579
1580        pub c0nst fn widening_mul_word<T: [c0nst] ConstWideningMul>(a: T, b: T) -> (T, T) {
1581            a.widening_mul(b)
1582        }
1583
1584        pub c0nst fn carrying_mul_word<T: [c0nst] ConstCarryingMul>(a: T, b: T, carry: T) -> (T, T) {
1585            a.carrying_mul(b, carry)
1586        }
1587
1588        pub c0nst fn carrying_mul_add_word<T: [c0nst] ConstCarryingMul>(a: T, b: T, addend: T, carry: T) -> (T, T) {
1589            a.carrying_mul_add(b, addend, carry)
1590        }
1591
1592        pub c0nst fn midpoint_word<T: [c0nst] ConstMidpoint>(a: T, b: T) -> T {
1593            a.midpoint(b)
1594        }
1595
1596        pub c0nst fn unbounded_shl_word<T: [c0nst] ConstUnboundedShift>(a: T, n: u32) -> T {
1597            a.unbounded_shl(n)
1598        }
1599
1600        pub c0nst fn unbounded_shr_word<T: [c0nst] ConstUnboundedShift>(a: T, n: u32) -> T {
1601            a.unbounded_shr(n)
1602        }
1603    }
1604
1605    #[test]
1606    fn test_constprimint_ops() {
1607        assert_eq!(add_words(2u8, 3u8), 5u8);
1608        assert_eq!(default_word::<u32>(), 0u32);
1609        assert_eq!(zero_word::<u64>(), 0u64);
1610        assert_eq!(one_word::<u128>(), 1u128);
1611        assert_eq!(min_word::<u8>(), 0u8);
1612        assert_eq!(max_word::<u8>(), 255u8);
1613
1614        let mut val = 10u8;
1615        assign_add(&mut val, 5u8);
1616        assert_eq!(val, 15u8);
1617
1618        #[cfg(feature = "nightly")]
1619        {
1620            const ADD_RES: u8 = add_words(2u8, 3u8);
1621            const DEFAULT_RES: u32 = default_word::<u32>();
1622            const ZERO_RES: u64 = zero_word::<u64>();
1623            const ONE_RES: u128 = one_word::<u128>();
1624            const MIN_RES: u8 = min_word::<u8>();
1625            const MAX_RES: u8 = max_word::<u8>();
1626            const ASSIGN_RES: u8 = {
1627                let mut v = 10u8;
1628                assign_add(&mut v, 5u8);
1629                v
1630            };
1631            assert_eq!(ADD_RES, 5u8);
1632            assert_eq!(DEFAULT_RES, 0u32);
1633            assert_eq!(ZERO_RES, 0u64);
1634            assert_eq!(ONE_RES, 1u128);
1635            assert_eq!(MIN_RES, 0u8);
1636            assert_eq!(MAX_RES, 255u8);
1637            assert_eq!(ASSIGN_RES, 15u8);
1638        }
1639    }
1640
1641    #[test]
1642    fn test_const_zero_one_methods() {
1643        // Test is_zero
1644        assert!(is_zero_word(&0u8));
1645        assert!(!is_zero_word(&1u8));
1646        assert!(is_zero_word(&0u64));
1647        assert!(!is_zero_word(&42u64));
1648
1649        // Test set_zero
1650        let mut val = 42u32;
1651        set_zero_word(&mut val);
1652        assert_eq!(val, 0u32);
1653
1654        // Test is_one
1655        assert!(is_one_word(&1u8));
1656        assert!(!is_one_word(&0u8));
1657        assert!(!is_one_word(&2u8));
1658        assert!(is_one_word(&1u128));
1659
1660        // Test set_one
1661        let mut val = 0u16;
1662        set_one_word(&mut val);
1663        assert_eq!(val, 1u16);
1664
1665        #[cfg(feature = "nightly")]
1666        {
1667            const IS_ZERO_TRUE: bool = is_zero_word(&0u8);
1668            const IS_ZERO_FALSE: bool = is_zero_word(&1u8);
1669            const SET_ZERO_RES: u32 = {
1670                let mut v = 42u32;
1671                set_zero_word(&mut v);
1672                v
1673            };
1674            const IS_ONE_TRUE: bool = is_one_word(&1u64);
1675            const IS_ONE_FALSE: bool = is_one_word(&0u64);
1676            const SET_ONE_RES: u16 = {
1677                let mut v = 0u16;
1678                set_one_word(&mut v);
1679                v
1680            };
1681            assert!(IS_ZERO_TRUE);
1682            assert!(!IS_ZERO_FALSE);
1683            assert_eq!(SET_ZERO_RES, 0u32);
1684            assert!(IS_ONE_TRUE);
1685            assert!(!IS_ONE_FALSE);
1686            assert_eq!(SET_ONE_RES, 1u16);
1687        }
1688    }
1689
1690    #[test]
1691    fn test_const_overflowing_ops() {
1692        // Test overflowing_add without overflow
1693        let (sum, overflow) = overflowing_add_word(&100u8, &50u8);
1694        assert_eq!(sum, 150u8);
1695        assert!(!overflow);
1696
1697        // Test overflowing_add with overflow
1698        let (sum, overflow) = overflowing_add_word(&200u8, &100u8);
1699        assert_eq!(sum, 44u8); // 300 wraps to 44
1700        assert!(overflow);
1701
1702        // Test overflowing_sub without overflow
1703        let (diff, overflow) = overflowing_sub_word(&100u8, &50u8);
1704        assert_eq!(diff, 50u8);
1705        assert!(!overflow);
1706
1707        // Test overflowing_sub with overflow (underflow)
1708        let (diff, overflow) = overflowing_sub_word(&50u8, &100u8);
1709        assert_eq!(diff, 206u8); // wraps around
1710        assert!(overflow);
1711
1712        // Test with larger types
1713        let (sum, overflow) = overflowing_add_word(&u64::MAX, &1u64);
1714        assert_eq!(sum, 0u64);
1715        assert!(overflow);
1716
1717        #[cfg(feature = "nightly")]
1718        {
1719            const ADD_NO_OVERFLOW: (u8, bool) = overflowing_add_word(&100u8, &50u8);
1720            const ADD_OVERFLOW: (u8, bool) = overflowing_add_word(&200u8, &100u8);
1721            const SUB_NO_OVERFLOW: (u8, bool) = overflowing_sub_word(&100u8, &50u8);
1722            const SUB_OVERFLOW: (u8, bool) = overflowing_sub_word(&50u8, &100u8);
1723
1724            assert_eq!(ADD_NO_OVERFLOW, (150u8, false));
1725            assert_eq!(ADD_OVERFLOW, (44u8, true));
1726            assert_eq!(SUB_NO_OVERFLOW, (50u8, false));
1727            assert_eq!(SUB_OVERFLOW, (206u8, true));
1728        }
1729    }
1730
1731    #[test]
1732    fn test_const_to_bytes() {
1733        // Test to_le_bytes
1734        let bytes = to_le_bytes_word(&0x12345678u32);
1735        assert_eq!(bytes.as_ref(), &[0x78, 0x56, 0x34, 0x12]);
1736
1737        // Test to_be_bytes
1738        let bytes = to_be_bytes_word(&0x12345678u32);
1739        assert_eq!(bytes.as_ref(), &[0x12, 0x34, 0x56, 0x78]);
1740
1741        // Test with u8
1742        let bytes = to_le_bytes_word(&0xABu8);
1743        assert_eq!(bytes.as_ref(), &[0xAB]);
1744
1745        // Test with u64
1746        let bytes = to_le_bytes_word(&0x0102030405060708u64);
1747        assert_eq!(
1748            bytes.as_ref(),
1749            &[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]
1750        );
1751
1752        #[cfg(feature = "nightly")]
1753        {
1754            const LE_BYTES: [u8; 4] = to_le_bytes_word(&0x12345678u32);
1755            const BE_BYTES: [u8; 4] = to_be_bytes_word(&0x12345678u32);
1756            assert_eq!(LE_BYTES, [0x78, 0x56, 0x34, 0x12]);
1757            assert_eq!(BE_BYTES, [0x12, 0x34, 0x56, 0x78]);
1758        }
1759    }
1760
1761    #[test]
1762    fn test_const_from_bytes() {
1763        // Test from_le_bytes with u32
1764        let val: u32 = from_le_bytes_word(&[0x78, 0x56, 0x34, 0x12]);
1765        assert_eq!(val, 0x12345678u32);
1766
1767        // Test from_be_bytes with u32
1768        let val: u32 = from_be_bytes_word(&[0x12, 0x34, 0x56, 0x78]);
1769        assert_eq!(val, 0x12345678u32);
1770
1771        // Test with u8
1772        let val: u8 = from_le_bytes_word(&[0xAB]);
1773        assert_eq!(val, 0xABu8);
1774
1775        // Test with u64
1776        let val: u64 = from_le_bytes_word(&[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]);
1777        assert_eq!(val, 0x0102030405060708u64);
1778
1779        // Test roundtrip
1780        let original = 0xDEADBEEFu32;
1781        let bytes = to_le_bytes_word(&original);
1782        let roundtrip: u32 = from_le_bytes_word(&bytes);
1783        assert_eq!(roundtrip, original);
1784
1785        #[cfg(feature = "nightly")]
1786        {
1787            const FROM_LE: u32 = from_le_bytes_word(&[0x78, 0x56, 0x34, 0x12]);
1788            const FROM_BE: u32 = from_be_bytes_word(&[0x12, 0x34, 0x56, 0x78]);
1789            assert_eq!(FROM_LE, 0x12345678u32);
1790            assert_eq!(FROM_BE, 0x12345678u32);
1791        }
1792    }
1793
1794    #[test]
1795    fn test_const_wrapping_checked_ops() {
1796        // Test wrapping_add without overflow
1797        assert_eq!(wrapping_add_word(&100u8, &50u8), 150u8);
1798        // Test wrapping_add with overflow
1799        assert_eq!(wrapping_add_word(&200u8, &100u8), 44u8);
1800
1801        // Test wrapping_sub without overflow
1802        assert_eq!(wrapping_sub_word(&100u8, &50u8), 50u8);
1803        // Test wrapping_sub with overflow (underflow)
1804        assert_eq!(wrapping_sub_word(&50u8, &100u8), 206u8);
1805
1806        // Test checked_add without overflow
1807        assert_eq!(checked_add_word(&100u8, &50u8), Some(150u8));
1808        // Test checked_add with overflow
1809        assert_eq!(checked_add_word(&200u8, &100u8), None);
1810
1811        // Test checked_sub without overflow
1812        assert_eq!(checked_sub_word(&100u8, &50u8), Some(50u8));
1813        // Test checked_sub with overflow (underflow)
1814        assert_eq!(checked_sub_word(&50u8, &100u8), None);
1815
1816        // Test with larger types
1817        assert_eq!(wrapping_add_word(&u64::MAX, &1u64), 0u64);
1818        assert_eq!(checked_add_word(&u64::MAX, &1u64), None);
1819
1820        #[cfg(feature = "nightly")]
1821        {
1822            const WRAP_ADD_NO_OVERFLOW: u8 = wrapping_add_word(&100u8, &50u8);
1823            const WRAP_ADD_OVERFLOW: u8 = wrapping_add_word(&200u8, &100u8);
1824            const WRAP_SUB_NO_OVERFLOW: u8 = wrapping_sub_word(&100u8, &50u8);
1825            const WRAP_SUB_OVERFLOW: u8 = wrapping_sub_word(&50u8, &100u8);
1826
1827            const CHECK_ADD_OK: Option<u8> = checked_add_word(&100u8, &50u8);
1828            const CHECK_ADD_OVERFLOW: Option<u8> = checked_add_word(&200u8, &100u8);
1829            const CHECK_SUB_OK: Option<u8> = checked_sub_word(&100u8, &50u8);
1830            const CHECK_SUB_OVERFLOW: Option<u8> = checked_sub_word(&50u8, &100u8);
1831
1832            assert_eq!(WRAP_ADD_NO_OVERFLOW, 150u8);
1833            assert_eq!(WRAP_ADD_OVERFLOW, 44u8);
1834            assert_eq!(WRAP_SUB_NO_OVERFLOW, 50u8);
1835            assert_eq!(WRAP_SUB_OVERFLOW, 206u8);
1836
1837            assert_eq!(CHECK_ADD_OK, Some(150u8));
1838            assert_eq!(CHECK_ADD_OVERFLOW, None);
1839            assert_eq!(CHECK_SUB_OK, Some(50u8));
1840            assert_eq!(CHECK_SUB_OVERFLOW, None);
1841        }
1842    }
1843
1844    #[test]
1845    fn test_const_saturating_ops() {
1846        // Test saturating_add without overflow
1847        assert_eq!(saturating_add_word(&100u8, &50u8), 150u8);
1848        // Test saturating_add with overflow (saturates at max)
1849        assert_eq!(saturating_add_word(&200u8, &100u8), 255u8);
1850
1851        // Test saturating_sub without overflow
1852        assert_eq!(saturating_sub_word(&100u8, &50u8), 50u8);
1853        // Test saturating_sub with underflow (saturates at zero)
1854        assert_eq!(saturating_sub_word(&50u8, &100u8), 0u8);
1855
1856        // Test with larger types
1857        assert_eq!(saturating_add_word(&u64::MAX, &1u64), u64::MAX);
1858        assert_eq!(saturating_sub_word(&0u64, &1u64), 0u64);
1859
1860        #[cfg(feature = "nightly")]
1861        {
1862            const SAT_ADD_NO_OVERFLOW: u8 = saturating_add_word(&100u8, &50u8);
1863            const SAT_ADD_OVERFLOW: u8 = saturating_add_word(&200u8, &100u8);
1864            const SAT_SUB_NO_OVERFLOW: u8 = saturating_sub_word(&100u8, &50u8);
1865            const SAT_SUB_OVERFLOW: u8 = saturating_sub_word(&50u8, &100u8);
1866
1867            assert_eq!(SAT_ADD_NO_OVERFLOW, 150u8);
1868            assert_eq!(SAT_ADD_OVERFLOW, 255u8);
1869            assert_eq!(SAT_SUB_NO_OVERFLOW, 50u8);
1870            assert_eq!(SAT_SUB_OVERFLOW, 0u8);
1871        }
1872    }
1873
1874    #[test]
1875    fn test_const_carrying_add() {
1876        // No carry in, no carry out
1877        let (sum, carry) = carrying_add_word(100u8, 50u8, false);
1878        assert_eq!(sum, 150u8);
1879        assert!(!carry);
1880
1881        // No carry in, carry out
1882        let (sum, carry) = carrying_add_word(200u8, 100u8, false);
1883        assert_eq!(sum, 44u8); // 300 wraps to 44
1884        assert!(carry);
1885
1886        // Carry in, no carry out
1887        let (sum, carry) = carrying_add_word(100u8, 50u8, true);
1888        assert_eq!(sum, 151u8);
1889        assert!(!carry);
1890
1891        // Carry in, carry out
1892        let (sum, carry) = carrying_add_word(200u8, 55u8, true);
1893        assert_eq!(sum, 0u8); // 256 wraps to 0
1894        assert!(carry);
1895
1896        // Edge case: max + 0 + 1 = carry
1897        let (sum, carry) = carrying_add_word(u8::MAX, 0u8, true);
1898        assert_eq!(sum, 0u8);
1899        assert!(carry);
1900
1901        // Test with larger types
1902        let (sum, carry) = carrying_add_word(u64::MAX, 0u64, true);
1903        assert_eq!(sum, 0u64);
1904        assert!(carry);
1905
1906        #[cfg(feature = "nightly")]
1907        {
1908            const CA_NO_CARRY: (u8, bool) = carrying_add_word(100u8, 50u8, false);
1909            const CA_CARRY_OUT: (u8, bool) = carrying_add_word(200u8, 100u8, false);
1910            const CA_CARRY_IN: (u8, bool) = carrying_add_word(100u8, 50u8, true);
1911            const CA_BOTH_CARRY: (u8, bool) = carrying_add_word(200u8, 55u8, true);
1912
1913            assert_eq!(CA_NO_CARRY, (150u8, false));
1914            assert_eq!(CA_CARRY_OUT, (44u8, true));
1915            assert_eq!(CA_CARRY_IN, (151u8, false));
1916            assert_eq!(CA_BOTH_CARRY, (0u8, true));
1917        }
1918    }
1919
1920    #[test]
1921    fn test_const_borrowing_sub() {
1922        // No borrow in, no borrow out
1923        let (diff, borrow) = borrowing_sub_word(100u8, 50u8, false);
1924        assert_eq!(diff, 50u8);
1925        assert!(!borrow);
1926
1927        // No borrow in, borrow out
1928        let (diff, borrow) = borrowing_sub_word(50u8, 100u8, false);
1929        assert_eq!(diff, 206u8); // wraps around
1930        assert!(borrow);
1931
1932        // Borrow in, no borrow out
1933        let (diff, borrow) = borrowing_sub_word(100u8, 50u8, true);
1934        assert_eq!(diff, 49u8);
1935        assert!(!borrow);
1936
1937        // Borrow in, borrow out
1938        let (diff, borrow) = borrowing_sub_word(50u8, 50u8, true);
1939        assert_eq!(diff, 255u8); // 0 - 1 wraps to 255
1940        assert!(borrow);
1941
1942        // Edge case: 0 - 0 - 1 = borrow
1943        let (diff, borrow) = borrowing_sub_word(0u8, 0u8, true);
1944        assert_eq!(diff, 255u8);
1945        assert!(borrow);
1946
1947        // Test with larger types
1948        let (diff, borrow) = borrowing_sub_word(0u64, 0u64, true);
1949        assert_eq!(diff, u64::MAX);
1950        assert!(borrow);
1951
1952        #[cfg(feature = "nightly")]
1953        {
1954            const BS_NO_BORROW: (u8, bool) = borrowing_sub_word(100u8, 50u8, false);
1955            const BS_BORROW_OUT: (u8, bool) = borrowing_sub_word(50u8, 100u8, false);
1956            const BS_BORROW_IN: (u8, bool) = borrowing_sub_word(100u8, 50u8, true);
1957            const BS_BOTH_BORROW: (u8, bool) = borrowing_sub_word(50u8, 50u8, true);
1958
1959            assert_eq!(BS_NO_BORROW, (50u8, false));
1960            assert_eq!(BS_BORROW_OUT, (206u8, true));
1961            assert_eq!(BS_BORROW_IN, (49u8, false));
1962            assert_eq!(BS_BOTH_BORROW, (255u8, true));
1963        }
1964    }
1965
1966    #[test]
1967    fn test_const_widening_mul() {
1968        // Simple multiplication, no high part
1969        let (lo, hi) = widening_mul_word(10u8, 5u8);
1970        assert_eq!(lo, 50u8);
1971        assert_eq!(hi, 0u8);
1972
1973        // Multiplication with high part
1974        let (lo, hi) = widening_mul_word(200u8, 3u8);
1975        assert_eq!(lo, 88u8); // 600 & 0xFF = 88
1976        assert_eq!(hi, 2u8); // 600 >> 8 = 2
1977
1978        // Max * max
1979        let (lo, hi) = widening_mul_word(u8::MAX, u8::MAX);
1980        // 255 * 255 = 65025 = 0xFE01
1981        assert_eq!(lo, 0x01u8);
1982        assert_eq!(hi, 0xFEu8);
1983
1984        // Test with u16
1985        let (lo, hi) = widening_mul_word(1000u16, 1000u16);
1986        // 1000 * 1000 = 1000000 = 0x000F4240
1987        assert_eq!(lo, 0x4240u16);
1988        assert_eq!(hi, 0x000Fu16);
1989
1990        // Test with u64
1991        let (lo, hi) = widening_mul_word(u64::MAX, 2u64);
1992        // MAX * 2 = 2 * (2^64 - 1) = 2^65 - 2 = (1, MAX-1)
1993        assert_eq!(lo, u64::MAX - 1);
1994        assert_eq!(hi, 1u64);
1995
1996        #[cfg(feature = "nightly")]
1997        {
1998            const WM_SIMPLE: (u8, u8) = widening_mul_word(10u8, 5u8);
1999            const WM_HIGH: (u8, u8) = widening_mul_word(200u8, 3u8);
2000            const WM_MAX: (u8, u8) = widening_mul_word(u8::MAX, u8::MAX);
2001
2002            assert_eq!(WM_SIMPLE, (50u8, 0u8));
2003            assert_eq!(WM_HIGH, (88u8, 2u8));
2004            assert_eq!(WM_MAX, (0x01u8, 0xFEu8));
2005        }
2006    }
2007
2008    #[test]
2009    fn test_const_carrying_mul() {
2010        // Simple multiplication with no carry
2011        let (lo, hi) = carrying_mul_word(10u8, 5u8, 0u8);
2012        assert_eq!(lo, 50u8);
2013        assert_eq!(hi, 0u8);
2014
2015        // Multiplication with carry added
2016        let (lo, hi) = carrying_mul_word(10u8, 5u8, 10u8);
2017        // 10 * 5 + 10 = 60
2018        assert_eq!(lo, 60u8);
2019        assert_eq!(hi, 0u8);
2020
2021        // Multiplication with high part
2022        let (lo, hi) = carrying_mul_word(200u8, 3u8, 0u8);
2023        assert_eq!(lo, 88u8); // 600 & 0xFF
2024        assert_eq!(hi, 2u8); // 600 >> 8
2025
2026        // Multiplication with carry causing high part
2027        let (lo, hi) = carrying_mul_word(200u8, 3u8, 200u8);
2028        // 200 * 3 + 200 = 800 = 0x0320
2029        assert_eq!(lo, 0x20u8);
2030        assert_eq!(hi, 3u8);
2031
2032        // Max values
2033        let (lo, hi) = carrying_mul_word(u8::MAX, u8::MAX, u8::MAX);
2034        // 255 * 255 + 255 = 65280 = 0xFF00
2035        assert_eq!(lo, 0x00u8);
2036        assert_eq!(hi, 0xFFu8);
2037
2038        // Test with u16
2039        let (lo, hi) = carrying_mul_word(1000u16, 1000u16, 1000u16);
2040        // 1000 * 1000 + 1000 = 1001000 = 0x000F4628
2041        assert_eq!(lo, 0x4628u16);
2042        assert_eq!(hi, 0x000Fu16);
2043
2044        #[cfg(feature = "nightly")]
2045        {
2046            const CM_SIMPLE: (u8, u8) = carrying_mul_word(10u8, 5u8, 0u8);
2047            const CM_WITH_CARRY: (u8, u8) = carrying_mul_word(10u8, 5u8, 10u8);
2048            const CM_MAX: (u8, u8) = carrying_mul_word(u8::MAX, u8::MAX, u8::MAX);
2049
2050            assert_eq!(CM_SIMPLE, (50u8, 0u8));
2051            assert_eq!(CM_WITH_CARRY, (60u8, 0u8));
2052            assert_eq!(CM_MAX, (0x00u8, 0xFFu8));
2053        }
2054    }
2055
2056    #[test]
2057    fn test_const_carrying_mul_add() {
2058        // Simple: 10 * 5 + 7 + 0 = 57
2059        let (lo, hi) = carrying_mul_add_word(10u8, 5u8, 7u8, 0u8);
2060        assert_eq!(lo, 57u8);
2061        assert_eq!(hi, 0u8);
2062
2063        // With all params: 10 * 5 + 10 + 10 = 70
2064        let (lo, hi) = carrying_mul_add_word(10u8, 5u8, 10u8, 10u8);
2065        assert_eq!(lo, 70u8);
2066        assert_eq!(hi, 0u8);
2067
2068        // Addend causes lo overflow: 200 * 3 + 200 + 0 = 800 = 0x0320
2069        // Then we add extra addend to test lo overflow path
2070        // 16 * 16 + 0 + 0 = 256 = 0x0100
2071        let (lo, hi) = carrying_mul_add_word(16u8, 16u8, 0u8, 0u8);
2072        assert_eq!(lo, 0x00u8);
2073        assert_eq!(hi, 1u8);
2074
2075        // Max case: 255 * 255 + 255 + 255 = 65535 = 0xFFFF
2076        // This exercises hi = 0xFF with addend causing no overflow
2077        // (since carrying_mul gives lo=0 when hi=0xFF)
2078        let (lo, hi) = carrying_mul_add_word(u8::MAX, u8::MAX, u8::MAX, u8::MAX);
2079        // 255 * 255 + 255 = 65280 = 0xFF00, then + 255 = 65535 = 0xFFFF
2080        assert_eq!(lo, 0xFFu8);
2081        assert_eq!(hi, 0xFFu8);
2082
2083        // Test case that would trigger wrapping_add:
2084        // We need hi to be MAX and carry from lo addition
2085        // For u8: 255 * 255 + 255 gives (0, 255), then adding 255 gives (255, 255)
2086        // Since lo=0, adding any addend won't overflow, so hi stays 255
2087        // The wrapping_add is for safety even though u8 can't trigger it
2088
2089        #[cfg(feature = "nightly")]
2090        {
2091            const CMA_SIMPLE: (u8, u8) = carrying_mul_add_word(10u8, 5u8, 7u8, 0u8);
2092            const CMA_MAX: (u8, u8) = carrying_mul_add_word(u8::MAX, u8::MAX, u8::MAX, u8::MAX);
2093
2094            assert_eq!(CMA_SIMPLE, (57u8, 0u8));
2095            assert_eq!(CMA_MAX, (0xFFu8, 0xFFu8));
2096        }
2097    }
2098
2099    #[test]
2100    fn test_const_midpoint() {
2101        // Simple midpoint
2102        assert_eq!(midpoint_word(0u8, 10u8), 5u8);
2103        assert_eq!(midpoint_word(10u8, 0u8), 5u8); // order doesn't matter
2104
2105        // Midpoint rounds down
2106        assert_eq!(midpoint_word(0u8, 9u8), 4u8); // (0+9)/2 = 4.5 -> 4
2107        assert_eq!(midpoint_word(1u8, 10u8), 5u8); // (1+10)/2 = 5.5 -> 5
2108
2109        // Same values
2110        assert_eq!(midpoint_word(42u8, 42u8), 42u8);
2111
2112        // Edge cases with max values (no overflow!)
2113        assert_eq!(midpoint_word(u8::MAX, u8::MAX), u8::MAX);
2114        assert_eq!(midpoint_word(u8::MAX, u8::MAX - 1), u8::MAX - 1); // rounds down
2115        assert_eq!(midpoint_word(0u8, u8::MAX), 127u8); // (0+255)/2 = 127.5 -> 127
2116
2117        // Test with larger types
2118        assert_eq!(midpoint_word(0u64, 100u64), 50u64);
2119        assert_eq!(midpoint_word(u64::MAX, u64::MAX), u64::MAX);
2120        assert_eq!(midpoint_word(u64::MAX - 1, u64::MAX), u64::MAX - 1); // rounds down
2121
2122        // u128
2123        assert_eq!(midpoint_word(0u128, u128::MAX), u128::MAX / 2);
2124
2125        #[cfg(feature = "nightly")]
2126        {
2127            const MID_SIMPLE: u8 = midpoint_word(0u8, 10u8);
2128            const MID_ROUND: u8 = midpoint_word(0u8, 9u8);
2129            const MID_MAX: u8 = midpoint_word(u8::MAX, u8::MAX);
2130            const MID_EDGE: u8 = midpoint_word(0u8, u8::MAX);
2131
2132            assert_eq!(MID_SIMPLE, 5u8);
2133            assert_eq!(MID_ROUND, 4u8);
2134            assert_eq!(MID_MAX, u8::MAX);
2135            assert_eq!(MID_EDGE, 127u8);
2136        }
2137    }
2138
2139    #[test]
2140    fn test_const_unbounded_shift() {
2141        // Normal shifts (within bounds)
2142        assert_eq!(unbounded_shl_word(1u8, 0), 1u8);
2143        assert_eq!(unbounded_shl_word(1u8, 1), 2u8);
2144        assert_eq!(unbounded_shl_word(1u8, 7), 128u8);
2145        assert_eq!(unbounded_shr_word(128u8, 7), 1u8);
2146        assert_eq!(unbounded_shr_word(255u8, 4), 15u8);
2147
2148        // At boundary (shift by bit width)
2149        assert_eq!(unbounded_shl_word(1u8, 8), 0u8);
2150        assert_eq!(unbounded_shr_word(255u8, 8), 0u8);
2151
2152        // Beyond boundary
2153        assert_eq!(unbounded_shl_word(255u8, 9), 0u8);
2154        assert_eq!(unbounded_shl_word(255u8, 100), 0u8);
2155        assert_eq!(unbounded_shr_word(255u8, 9), 0u8);
2156        assert_eq!(unbounded_shr_word(255u8, 100), 0u8);
2157
2158        // Test with larger types
2159        assert_eq!(unbounded_shl_word(1u64, 63), 1u64 << 63);
2160        assert_eq!(unbounded_shl_word(1u64, 64), 0u64);
2161        assert_eq!(unbounded_shr_word(u64::MAX, 64), 0u64);
2162
2163        // u128
2164        assert_eq!(unbounded_shl_word(1u128, 127), 1u128 << 127);
2165        assert_eq!(unbounded_shl_word(1u128, 128), 0u128);
2166        assert_eq!(unbounded_shr_word(u128::MAX, 128), 0u128);
2167
2168        #[cfg(feature = "nightly")]
2169        {
2170            const SHL_NORMAL: u8 = unbounded_shl_word(1u8, 4);
2171            const SHL_BOUNDARY: u8 = unbounded_shl_word(1u8, 8);
2172            const SHL_BEYOND: u8 = unbounded_shl_word(1u8, 100);
2173            const SHR_NORMAL: u8 = unbounded_shr_word(128u8, 4);
2174            const SHR_BOUNDARY: u8 = unbounded_shr_word(255u8, 8);
2175            const SHR_BEYOND: u8 = unbounded_shr_word(255u8, 100);
2176
2177            assert_eq!(SHL_NORMAL, 16u8);
2178            assert_eq!(SHL_BOUNDARY, 0u8);
2179            assert_eq!(SHL_BEYOND, 0u8);
2180            assert_eq!(SHR_NORMAL, 8u8);
2181            assert_eq!(SHR_BOUNDARY, 0u8);
2182            assert_eq!(SHR_BEYOND, 0u8);
2183        }
2184    }
2185}