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 ConstBitPrimInt:
465        [c0nst] core::ops::BitAnd<Output = Self> +
466        [c0nst] core::ops::BitOr<Output = Self> +
467        [c0nst] core::ops::BitXor<Output = Self> +
468        [c0nst] core::ops::Not<Output = Self> +
469        [c0nst] core::ops::Shl<usize, Output = Self> +
470        [c0nst] core::ops::Shr<usize, Output = Self> +
471        [c0nst] core::ops::BitAndAssign +
472        [c0nst] core::ops::BitOrAssign +
473        [c0nst] core::ops::BitXorAssign +
474        [c0nst] core::ops::ShlAssign<usize> +
475        [c0nst] core::ops::ShrAssign<usize> +
476        [c0nst] ConstOne +
477        [c0nst] ConstZero +
478        Sized + Copy {
479
480            fn swap_bytes(self) -> Self;
481            fn leading_zeros(self) -> u32;
482            fn trailing_zeros(self) -> u32;
483            fn count_zeros(self) -> u32;
484            fn count_ones(self) -> u32;
485            fn leading_ones(self) -> u32 {
486                (!self).leading_zeros()
487            }
488            fn trailing_ones(self) -> u32 {
489                (!self).trailing_zeros()
490            }
491            fn rotate_left(self, n: u32) -> Self;
492            fn rotate_right(self, n: u32) -> Self;
493            fn unsigned_shl(self, n: u32) -> Self;
494            fn unsigned_shr(self, n: u32) -> Self;
495            fn signed_shl(self, n: u32) -> Self {
496                self.unsigned_shl(n)
497            }
498            fn signed_shr(self, n: u32) -> Self {
499                self.unsigned_shr(n)
500            }
501            fn reverse_bits(self) -> Self;
502            fn from_be(x: Self) -> Self;
503            fn from_le(x: Self) -> Self;
504            fn to_be(self) -> Self;
505            fn to_le(self) -> Self;
506    }
507
508    /// Base arithmetic traits for constant primitive integers.
509    ///
510    /// Extends [`ConstBitPrimInt`] with the arithmetic + ordering operations
511    /// that aren't generally available on CT-restricted types. Implementors
512    /// like `FixedUInt<_, _, Ct>` will get `ConstBitPrimInt` but not the
513    /// full `ConstPrimInt` because they don't expose `Div` (long division
514    /// is the leaky algorithmic core for unsigned big integers).
515    pub c0nst trait ConstPrimInt:
516        [c0nst] ConstBitPrimInt +
517        [c0nst] core::ops::Add<Output = Self> +
518        [c0nst] core::ops::Sub<Output = Self> +
519        [c0nst] core::ops::Mul<Output = Self> +
520        [c0nst] core::ops::Div<Output = Self> +
521        [c0nst] core::ops::AddAssign +
522        [c0nst] core::ops::SubAssign +
523        [c0nst] core::cmp::PartialEq +
524        [c0nst] core::cmp::Eq +
525        [c0nst] core::cmp::PartialOrd +
526        [c0nst] core::cmp::Ord +
527        [c0nst] core::convert::From<u8> +
528        [c0nst] core::default::Default +
529        [c0nst] ConstBounded {
530
531            fn pow(self, exp: u32) -> Self;
532    }
533}
534
535macro_rules! const_zero_impl {
536    ($t:ty, $v:expr) => {
537        c0nst::c0nst! {
538            impl c0nst ConstZero for $t {
539                fn zero() -> Self { $v }
540                fn is_zero(&self) -> bool { *self == $v }
541                fn set_zero(&mut self) { *self = $v }
542            }
543        }
544    };
545}
546
547macro_rules! const_one_impl {
548    ($t:ty, $v:expr) => {
549        c0nst::c0nst! {
550            impl c0nst ConstOne for $t {
551                fn one() -> Self { $v }
552                fn is_one(&self) -> bool { *self == $v }
553                fn set_one(&mut self) { *self = $v }
554            }
555        }
556    };
557}
558
559macro_rules! const_bounded_impl {
560    ($t:ty, $min:expr, $max:expr) => {
561        c0nst::c0nst! {
562            impl c0nst ConstBounded for $t {
563                fn min_value() -> Self { $min }
564                fn max_value() -> Self { $max }
565            }
566        }
567    };
568}
569
570macro_rules! const_bit_prim_int_impl {
571    ($t:ty) => {
572        c0nst::c0nst! {
573            impl c0nst ConstBitPrimInt for $t {
574                fn leading_zeros(self) -> u32 { self.leading_zeros() }
575                fn trailing_zeros(self) -> u32 { self.trailing_zeros() }
576                fn count_zeros(self) -> u32 { self.count_zeros() }
577                fn count_ones(self) -> u32 { self.count_ones() }
578                fn swap_bytes(self) -> Self { self.swap_bytes() }
579                fn rotate_left(self, n: u32) -> Self { self.rotate_left(n) }
580                fn rotate_right(self, n: u32) -> Self { self.rotate_right(n) }
581                fn unsigned_shl(self, n: u32) -> Self { self << n }
582                fn unsigned_shr(self, n: u32) -> Self { self >> n }
583                fn reverse_bits(self) -> Self { self.reverse_bits() }
584                fn from_be(x: Self) -> Self { <$t>::from_be(x) }
585                fn from_le(x: Self) -> Self { <$t>::from_le(x) }
586                fn to_be(self) -> Self { self.to_be() }
587                fn to_le(self) -> Self { self.to_le() }
588            }
589        }
590    };
591}
592
593macro_rules! const_prim_int_impl {
594    ($t:ty) => {
595        c0nst::c0nst! {
596            impl c0nst ConstPrimInt for $t {
597                fn pow(self, exp: u32) -> Self { self.pow(exp) }
598            }
599        }
600    };
601}
602
603macro_rules! const_overflowing_add_impl {
604    ($t:ty) => {
605        c0nst::c0nst! {
606            impl c0nst ConstOverflowingAdd for $t {
607                fn overflowing_add(&self, v: &Self) -> (Self, bool) {
608                    (*self).overflowing_add(*v)
609                }
610            }
611        }
612    };
613}
614
615macro_rules! const_overflowing_sub_impl {
616    ($t:ty) => {
617        c0nst::c0nst! {
618            impl c0nst ConstOverflowingSub for $t {
619                fn overflowing_sub(&self, v: &Self) -> (Self, bool) {
620                    (*self).overflowing_sub(*v)
621                }
622            }
623        }
624    };
625}
626
627const_zero_impl!(u8, 0);
628const_zero_impl!(u16, 0);
629const_zero_impl!(u32, 0);
630const_zero_impl!(u64, 0);
631const_zero_impl!(u128, 0);
632
633const_one_impl!(u8, 1);
634const_one_impl!(u16, 1);
635const_one_impl!(u32, 1);
636const_one_impl!(u64, 1);
637const_one_impl!(u128, 1);
638
639const_bounded_impl!(u8, u8::MIN, u8::MAX);
640const_bounded_impl!(u16, u16::MIN, u16::MAX);
641const_bounded_impl!(u32, u32::MIN, u32::MAX);
642const_bounded_impl!(u64, u64::MIN, u64::MAX);
643const_bounded_impl!(u128, u128::MIN, u128::MAX);
644
645const_overflowing_add_impl!(u8);
646const_overflowing_add_impl!(u16);
647const_overflowing_add_impl!(u32);
648const_overflowing_add_impl!(u64);
649const_overflowing_add_impl!(u128);
650
651const_overflowing_sub_impl!(u8);
652const_overflowing_sub_impl!(u16);
653const_overflowing_sub_impl!(u32);
654const_overflowing_sub_impl!(u64);
655const_overflowing_sub_impl!(u128);
656
657macro_rules! const_wrapping_add_impl {
658    ($t:ty) => {
659        c0nst::c0nst! {
660            impl c0nst ConstWrappingAdd for $t {
661                fn wrapping_add(&self, v: &Self) -> Self {
662                    self.overflowing_add(v).0
663                }
664            }
665        }
666    };
667}
668
669macro_rules! const_wrapping_sub_impl {
670    ($t:ty) => {
671        c0nst::c0nst! {
672            impl c0nst ConstWrappingSub for $t {
673                fn wrapping_sub(&self, v: &Self) -> Self {
674                    self.overflowing_sub(v).0
675                }
676            }
677        }
678    };
679}
680
681macro_rules! const_checked_add_impl {
682    ($t:ty) => {
683        c0nst::c0nst! {
684            impl c0nst ConstCheckedAdd for $t {
685                fn checked_add(&self, v: &Self) -> Option<Self> {
686                    let (res, overflow) = self.overflowing_add(v);
687                    if overflow { None } else { Some(res) }
688                }
689            }
690        }
691    };
692}
693
694macro_rules! const_checked_sub_impl {
695    ($t:ty) => {
696        c0nst::c0nst! {
697            impl c0nst ConstCheckedSub for $t {
698                fn checked_sub(&self, v: &Self) -> Option<Self> {
699                    let (res, overflow) = self.overflowing_sub(v);
700                    if overflow { None } else { Some(res) }
701                }
702            }
703        }
704    };
705}
706
707const_wrapping_add_impl!(u8);
708const_wrapping_add_impl!(u16);
709const_wrapping_add_impl!(u32);
710const_wrapping_add_impl!(u64);
711const_wrapping_add_impl!(u128);
712
713const_wrapping_sub_impl!(u8);
714const_wrapping_sub_impl!(u16);
715const_wrapping_sub_impl!(u32);
716const_wrapping_sub_impl!(u64);
717const_wrapping_sub_impl!(u128);
718
719const_checked_add_impl!(u8);
720const_checked_add_impl!(u16);
721const_checked_add_impl!(u32);
722const_checked_add_impl!(u64);
723const_checked_add_impl!(u128);
724
725const_checked_sub_impl!(u8);
726const_checked_sub_impl!(u16);
727const_checked_sub_impl!(u32);
728const_checked_sub_impl!(u64);
729const_checked_sub_impl!(u128);
730
731macro_rules! const_saturating_add_impl {
732    ($t:ty) => {
733        c0nst::c0nst! {
734            impl c0nst ConstSaturatingAdd for $t {
735                fn saturating_add(&self, v: &Self) -> Self {
736                    let (res, overflow) = self.overflowing_add(v);
737                    if overflow { Self::max_value() } else { res }
738                }
739            }
740        }
741    };
742}
743
744macro_rules! const_saturating_sub_impl {
745    ($t:ty) => {
746        c0nst::c0nst! {
747            impl c0nst ConstSaturatingSub for $t {
748                fn saturating_sub(&self, v: &Self) -> Self {
749                    let (res, overflow) = self.overflowing_sub(v);
750                    if overflow { Self::zero() } else { res }
751                }
752            }
753        }
754    };
755}
756
757const_saturating_add_impl!(u8);
758const_saturating_add_impl!(u16);
759const_saturating_add_impl!(u32);
760const_saturating_add_impl!(u64);
761const_saturating_add_impl!(u128);
762
763const_saturating_sub_impl!(u8);
764const_saturating_sub_impl!(u16);
765const_saturating_sub_impl!(u32);
766const_saturating_sub_impl!(u64);
767const_saturating_sub_impl!(u128);
768
769macro_rules! const_overflowing_mul_impl {
770    ($t:ty) => {
771        c0nst::c0nst! {
772            impl c0nst ConstOverflowingMul for $t {
773                fn overflowing_mul(&self, v: &Self) -> (Self, bool) {
774                    (*self).overflowing_mul(*v)
775                }
776            }
777        }
778    };
779}
780
781macro_rules! const_wrapping_mul_impl {
782    ($t:ty) => {
783        c0nst::c0nst! {
784            impl c0nst ConstWrappingMul for $t {
785                fn wrapping_mul(&self, v: &Self) -> Self {
786                    self.overflowing_mul(v).0
787                }
788            }
789        }
790    };
791}
792
793macro_rules! const_checked_mul_impl {
794    ($t:ty) => {
795        c0nst::c0nst! {
796            impl c0nst ConstCheckedMul for $t {
797                fn checked_mul(&self, v: &Self) -> Option<Self> {
798                    let (res, overflow) = self.overflowing_mul(v);
799                    if overflow { None } else { Some(res) }
800                }
801            }
802        }
803    };
804}
805
806macro_rules! const_saturating_mul_impl {
807    ($t:ty) => {
808        c0nst::c0nst! {
809            impl c0nst ConstSaturatingMul for $t {
810                fn saturating_mul(&self, v: &Self) -> Self {
811                    let (res, overflow) = self.overflowing_mul(v);
812                    if overflow { Self::max_value() } else { res }
813                }
814            }
815        }
816    };
817}
818
819const_overflowing_mul_impl!(u8);
820const_overflowing_mul_impl!(u16);
821const_overflowing_mul_impl!(u32);
822const_overflowing_mul_impl!(u64);
823const_overflowing_mul_impl!(u128);
824
825const_wrapping_mul_impl!(u8);
826const_wrapping_mul_impl!(u16);
827const_wrapping_mul_impl!(u32);
828const_wrapping_mul_impl!(u64);
829const_wrapping_mul_impl!(u128);
830
831const_checked_mul_impl!(u8);
832const_checked_mul_impl!(u16);
833const_checked_mul_impl!(u32);
834const_checked_mul_impl!(u64);
835const_checked_mul_impl!(u128);
836
837const_saturating_mul_impl!(u8);
838const_saturating_mul_impl!(u16);
839const_saturating_mul_impl!(u32);
840const_saturating_mul_impl!(u64);
841const_saturating_mul_impl!(u128);
842
843macro_rules! const_checked_div_impl {
844    ($t:ty) => {
845        c0nst::c0nst! {
846            impl c0nst ConstCheckedDiv for $t {
847                fn checked_div(&self, v: &Self) -> Option<Self> {
848                    if v.is_zero() { None } else { Some(*self / *v) }
849                }
850            }
851        }
852    };
853}
854
855macro_rules! const_checked_rem_impl {
856    ($t:ty) => {
857        c0nst::c0nst! {
858            impl c0nst ConstCheckedRem for $t {
859                fn checked_rem(&self, v: &Self) -> Option<Self> {
860                    if v.is_zero() { None } else { Some(*self % *v) }
861                }
862            }
863        }
864    };
865}
866
867const_checked_div_impl!(u8);
868const_checked_div_impl!(u16);
869const_checked_div_impl!(u32);
870const_checked_div_impl!(u64);
871const_checked_div_impl!(u128);
872
873const_checked_rem_impl!(u8);
874const_checked_rem_impl!(u16);
875const_checked_rem_impl!(u32);
876const_checked_rem_impl!(u64);
877const_checked_rem_impl!(u128);
878
879macro_rules! const_euclid_impl {
880    ($t:ty) => {
881        c0nst::c0nst! {
882            impl c0nst ConstEuclid for $t {
883                fn div_euclid(&self, v: &Self) -> Self {
884                    // For unsigned integers, Euclidean division is the same as regular division
885                    *self / *v
886                }
887                fn rem_euclid(&self, v: &Self) -> Self {
888                    // For unsigned integers, Euclidean remainder is the same as regular remainder
889                    *self % *v
890                }
891            }
892        }
893    };
894}
895
896macro_rules! const_checked_euclid_impl {
897    ($t:ty) => {
898        c0nst::c0nst! {
899            impl c0nst ConstCheckedEuclid for $t {
900                fn checked_div_euclid(&self, v: &Self) -> Option<Self> {
901                    if v.is_zero() { None } else { Some(*self / *v) }
902                }
903                fn checked_rem_euclid(&self, v: &Self) -> Option<Self> {
904                    if v.is_zero() { None } else { Some(*self % *v) }
905                }
906            }
907        }
908    };
909}
910
911const_euclid_impl!(u8);
912const_euclid_impl!(u16);
913const_euclid_impl!(u32);
914const_euclid_impl!(u64);
915const_euclid_impl!(u128);
916
917const_checked_euclid_impl!(u8);
918const_checked_euclid_impl!(u16);
919const_checked_euclid_impl!(u32);
920const_checked_euclid_impl!(u64);
921const_checked_euclid_impl!(u128);
922
923macro_rules! const_overflowing_shl_impl {
924    ($t:ty) => {
925        c0nst::c0nst! {
926            impl c0nst ConstOverflowingShl for $t {
927                fn overflowing_shl(&self, rhs: u32) -> (Self, bool) {
928                    (*self).overflowing_shl(rhs)
929                }
930            }
931        }
932    };
933}
934
935macro_rules! const_overflowing_shr_impl {
936    ($t:ty) => {
937        c0nst::c0nst! {
938            impl c0nst ConstOverflowingShr for $t {
939                fn overflowing_shr(&self, rhs: u32) -> (Self, bool) {
940                    (*self).overflowing_shr(rhs)
941                }
942            }
943        }
944    };
945}
946
947macro_rules! const_wrapping_shl_impl {
948    ($t:ty) => {
949        c0nst::c0nst! {
950            impl c0nst ConstWrappingShl for $t {
951                fn wrapping_shl(&self, rhs: u32) -> Self {
952                    ConstOverflowingShl::overflowing_shl(self, rhs).0
953                }
954            }
955        }
956    };
957}
958
959macro_rules! const_wrapping_shr_impl {
960    ($t:ty) => {
961        c0nst::c0nst! {
962            impl c0nst ConstWrappingShr for $t {
963                fn wrapping_shr(&self, rhs: u32) -> Self {
964                    ConstOverflowingShr::overflowing_shr(self, rhs).0
965                }
966            }
967        }
968    };
969}
970
971macro_rules! const_checked_shl_impl {
972    ($t:ty) => {
973        c0nst::c0nst! {
974            impl c0nst ConstCheckedShl for $t {
975                fn checked_shl(&self, rhs: u32) -> Option<Self> {
976                    let (res, overflow) = ConstOverflowingShl::overflowing_shl(self, rhs);
977                    if overflow { None } else { Some(res) }
978                }
979            }
980        }
981    };
982}
983
984macro_rules! const_checked_shr_impl {
985    ($t:ty) => {
986        c0nst::c0nst! {
987            impl c0nst ConstCheckedShr for $t {
988                fn checked_shr(&self, rhs: u32) -> Option<Self> {
989                    let (res, overflow) = ConstOverflowingShr::overflowing_shr(self, rhs);
990                    if overflow { None } else { Some(res) }
991                }
992            }
993        }
994    };
995}
996
997const_overflowing_shl_impl!(u8);
998const_overflowing_shl_impl!(u16);
999const_overflowing_shl_impl!(u32);
1000const_overflowing_shl_impl!(u64);
1001const_overflowing_shl_impl!(u128);
1002
1003const_overflowing_shr_impl!(u8);
1004const_overflowing_shr_impl!(u16);
1005const_overflowing_shr_impl!(u32);
1006const_overflowing_shr_impl!(u64);
1007const_overflowing_shr_impl!(u128);
1008
1009const_wrapping_shl_impl!(u8);
1010const_wrapping_shl_impl!(u16);
1011const_wrapping_shl_impl!(u32);
1012const_wrapping_shl_impl!(u64);
1013const_wrapping_shl_impl!(u128);
1014
1015const_wrapping_shr_impl!(u8);
1016const_wrapping_shr_impl!(u16);
1017const_wrapping_shr_impl!(u32);
1018const_wrapping_shr_impl!(u64);
1019const_wrapping_shr_impl!(u128);
1020
1021const_checked_shl_impl!(u8);
1022const_checked_shl_impl!(u16);
1023const_checked_shl_impl!(u32);
1024const_checked_shl_impl!(u64);
1025const_checked_shl_impl!(u128);
1026
1027const_checked_shr_impl!(u8);
1028const_checked_shr_impl!(u16);
1029const_checked_shr_impl!(u32);
1030const_checked_shr_impl!(u64);
1031const_checked_shr_impl!(u128);
1032
1033macro_rules! const_to_bytes_impl {
1034    ($t:ty, $n:expr) => {
1035        c0nst::c0nst! {
1036            impl c0nst ConstToBytes for $t {
1037                type Bytes = [u8; $n];
1038                fn to_le_bytes(&self) -> [u8; $n] { (*self).to_le_bytes() }
1039                fn to_be_bytes(&self) -> [u8; $n] { (*self).to_be_bytes() }
1040            }
1041        }
1042    };
1043}
1044
1045const_to_bytes_impl!(u8, 1);
1046const_to_bytes_impl!(u16, 2);
1047const_to_bytes_impl!(u32, 4);
1048const_to_bytes_impl!(u64, 8);
1049const_to_bytes_impl!(u128, 16);
1050
1051macro_rules! const_from_bytes_impl {
1052    ($t:ty, $n:expr) => {
1053        c0nst::c0nst! {
1054            impl c0nst ConstFromBytes for $t {
1055                type Bytes = [u8; $n];
1056                fn from_le_bytes(bytes: &[u8; $n]) -> Self { <$t>::from_le_bytes(*bytes) }
1057                fn from_be_bytes(bytes: &[u8; $n]) -> Self { <$t>::from_be_bytes(*bytes) }
1058            }
1059        }
1060    };
1061}
1062
1063const_from_bytes_impl!(u8, 1);
1064const_from_bytes_impl!(u16, 2);
1065const_from_bytes_impl!(u32, 4);
1066const_from_bytes_impl!(u64, 8);
1067const_from_bytes_impl!(u128, 16);
1068
1069macro_rules! const_power_of_two_impl {
1070    ($t:ty) => {
1071        c0nst::c0nst! {
1072            impl c0nst ConstPowerOfTwo for $t {
1073                fn is_power_of_two(&self) -> bool {
1074                    (*self).is_power_of_two()
1075                }
1076                fn next_power_of_two(self) -> Self {
1077                    self.next_power_of_two()
1078                }
1079                fn checked_next_power_of_two(self) -> Option<Self> {
1080                    self.checked_next_power_of_two()
1081                }
1082            }
1083        }
1084    };
1085}
1086
1087const_power_of_two_impl!(u8);
1088const_power_of_two_impl!(u16);
1089const_power_of_two_impl!(u32);
1090const_power_of_two_impl!(u64);
1091const_power_of_two_impl!(u128);
1092
1093macro_rules! const_abs_diff_impl {
1094    ($t:ty) => {
1095        c0nst::c0nst! {
1096            impl c0nst ConstAbsDiff for $t {
1097                fn abs_diff(self, other: Self) -> Self {
1098                    <$t>::abs_diff(self, other)
1099                }
1100            }
1101        }
1102    };
1103}
1104
1105const_abs_diff_impl!(u8);
1106const_abs_diff_impl!(u16);
1107const_abs_diff_impl!(u32);
1108const_abs_diff_impl!(u64);
1109const_abs_diff_impl!(u128);
1110
1111macro_rules! const_checked_pow_impl {
1112    ($t:ty) => {
1113        c0nst::c0nst! {
1114            impl c0nst ConstCheckedPow for $t {
1115                fn checked_pow(self, exp: u32) -> Option<Self> {
1116                    self.checked_pow(exp)
1117                }
1118            }
1119        }
1120    };
1121}
1122
1123const_checked_pow_impl!(u8);
1124const_checked_pow_impl!(u16);
1125const_checked_pow_impl!(u32);
1126const_checked_pow_impl!(u64);
1127const_checked_pow_impl!(u128);
1128
1129macro_rules! const_ilog_impl {
1130    ($t:ty) => {
1131        c0nst::c0nst! {
1132            impl c0nst ConstIlog for $t {
1133                fn ilog2(self) -> u32 {
1134                    self.ilog2()
1135                }
1136                fn ilog10(self) -> u32 {
1137                    self.ilog10()
1138                }
1139                fn ilog(self, base: Self) -> u32 {
1140                    self.ilog(base)
1141                }
1142                fn checked_ilog2(self) -> Option<u32> {
1143                    self.checked_ilog2()
1144                }
1145                fn checked_ilog10(self) -> Option<u32> {
1146                    self.checked_ilog10()
1147                }
1148                fn checked_ilog(self, base: Self) -> Option<u32> {
1149                    self.checked_ilog(base)
1150                }
1151            }
1152        }
1153    };
1154}
1155
1156const_ilog_impl!(u8);
1157const_ilog_impl!(u16);
1158const_ilog_impl!(u32);
1159const_ilog_impl!(u64);
1160const_ilog_impl!(u128);
1161
1162// Native is_multiple_of() requires Rust 1.87+, gate behind 1_87 feature
1163#[cfg(not(feature = "1_87"))]
1164macro_rules! const_multiple_impl {
1165    ($t:ty) => {
1166        c0nst::c0nst! {
1167            impl c0nst ConstMultiple for $t {
1168                fn is_multiple_of(&self, rhs: &Self) -> bool {
1169                    if rhs.is_zero() {
1170                        false
1171                    } else {
1172                        *self % *rhs == 0
1173                    }
1174                }
1175                fn next_multiple_of(self, rhs: Self) -> Self {
1176                    self.next_multiple_of(rhs)
1177                }
1178                fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1179                    self.checked_next_multiple_of(rhs)
1180                }
1181            }
1182        }
1183    };
1184}
1185
1186#[cfg(feature = "1_87")]
1187macro_rules! const_multiple_impl {
1188    ($t:ty) => {
1189        c0nst::c0nst! {
1190            impl c0nst ConstMultiple for $t {
1191                fn is_multiple_of(&self, rhs: &Self) -> bool {
1192                    <$t>::is_multiple_of(*self, *rhs)
1193                }
1194                fn next_multiple_of(self, rhs: Self) -> Self {
1195                    self.next_multiple_of(rhs)
1196                }
1197                fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1198                    self.checked_next_multiple_of(rhs)
1199                }
1200            }
1201        }
1202    };
1203}
1204
1205const_multiple_impl!(u8);
1206const_multiple_impl!(u16);
1207const_multiple_impl!(u32);
1208const_multiple_impl!(u64);
1209const_multiple_impl!(u128);
1210
1211macro_rules! const_div_ceil_impl {
1212    ($t:ty) => {
1213        c0nst::c0nst! {
1214            impl c0nst ConstDivCeil for $t {
1215                fn div_ceil(self, rhs: Self) -> Self {
1216                    <$t>::div_ceil(self, rhs)
1217                }
1218                fn checked_div_ceil(self, rhs: Self) -> Option<Self> {
1219                    if rhs.is_zero() {
1220                        None
1221                    } else {
1222                        Some(<$t>::div_ceil(self, rhs))
1223                    }
1224                }
1225            }
1226        }
1227    };
1228}
1229
1230const_div_ceil_impl!(u8);
1231const_div_ceil_impl!(u16);
1232const_div_ceil_impl!(u32);
1233const_div_ceil_impl!(u64);
1234const_div_ceil_impl!(u128);
1235
1236// Primitive isqrt requires Rust 1.84+, gate behind nightly
1237#[cfg(feature = "nightly")]
1238macro_rules! const_isqrt_impl {
1239    ($t:ty) => {
1240        c0nst::c0nst! {
1241            impl c0nst ConstIsqrt for $t {
1242                fn isqrt(self) -> Self {
1243                    <$t>::isqrt(self)
1244                }
1245                fn checked_isqrt(self) -> Option<Self> {
1246                    // For unsigned types, isqrt always succeeds
1247                    Some(<$t>::isqrt(self))
1248                }
1249            }
1250        }
1251    };
1252}
1253
1254#[cfg(feature = "nightly")]
1255const_isqrt_impl!(u8);
1256#[cfg(feature = "nightly")]
1257const_isqrt_impl!(u16);
1258#[cfg(feature = "nightly")]
1259const_isqrt_impl!(u32);
1260#[cfg(feature = "nightly")]
1261const_isqrt_impl!(u64);
1262#[cfg(feature = "nightly")]
1263const_isqrt_impl!(u128);
1264
1265// Extended precision primitive implementations
1266// Native bigint_helper_methods stable since Rust 1.91.0
1267#[cfg(not(feature = "nightly"))]
1268macro_rules! const_carrying_add_impl {
1269    ($t:ty) => {
1270        c0nst::c0nst! {
1271            impl c0nst ConstCarryingAdd for $t {
1272                fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
1273                    let (sum1, c1) = self.overflowing_add(rhs);
1274                    let (sum2, c2) = sum1.overflowing_add(carry as $t);
1275                    // Non-short-circuiting `|` to keep the body branch-free at
1276                    // the source level (CT discipline).
1277                    (sum2, c1 | c2)
1278                }
1279            }
1280        }
1281    };
1282}
1283
1284#[cfg(feature = "nightly")]
1285macro_rules! const_carrying_add_impl {
1286    ($t:ty) => {
1287        c0nst::c0nst! {
1288            impl c0nst ConstCarryingAdd for $t {
1289                fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
1290                    <$t>::carrying_add(self, rhs, carry)
1291                }
1292            }
1293        }
1294    };
1295}
1296
1297#[cfg(not(feature = "nightly"))]
1298macro_rules! const_borrowing_sub_impl {
1299    ($t:ty) => {
1300        c0nst::c0nst! {
1301            impl c0nst ConstBorrowingSub for $t {
1302                fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
1303                    let (diff1, b1) = self.overflowing_sub(rhs);
1304                    let (diff2, b2) = diff1.overflowing_sub(borrow as $t);
1305                    (diff2, b1 | b2)
1306                }
1307            }
1308        }
1309    };
1310}
1311
1312#[cfg(feature = "nightly")]
1313macro_rules! const_borrowing_sub_impl {
1314    ($t:ty) => {
1315        c0nst::c0nst! {
1316            impl c0nst ConstBorrowingSub for $t {
1317                fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
1318                    <$t>::borrowing_sub(self, rhs, borrow)
1319                }
1320            }
1321        }
1322    };
1323}
1324
1325#[cfg(not(feature = "nightly"))]
1326macro_rules! const_widening_mul_impl {
1327    ($t:ty, $double:ty, $bits:expr) => {
1328        c0nst::c0nst! {
1329            impl c0nst ConstWideningMul for $t {
1330                fn widening_mul(self, rhs: Self) -> (Self, Self) {
1331                    let product = (self as $double) * (rhs as $double);
1332                    (product as $t, (product >> $bits) as $t)
1333                }
1334            }
1335        }
1336    };
1337}
1338
1339#[cfg(feature = "nightly")]
1340macro_rules! const_widening_mul_impl {
1341    ($t:ty, $double:ty, $bits:expr) => {
1342        c0nst::c0nst! {
1343            impl c0nst ConstWideningMul for $t {
1344                fn widening_mul(self, rhs: Self) -> (Self, Self) {
1345                    let product: $double = <$t>::widening_mul(self, rhs);
1346                    (product as $t, (product >> $bits) as $t)
1347                }
1348            }
1349        }
1350    };
1351}
1352
1353#[cfg(not(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                    let product = (self as $double) * (rhs as $double) + (carry as $double);
1360                    (product as $t, (product >> $bits) as $t)
1361                }
1362                fn carrying_mul_add(self, rhs: Self, addend: Self, carry: Self) -> (Self, Self) {
1363                    let product = (self as $double) * (rhs as $double)
1364                        + (addend as $double)
1365                        + (carry as $double);
1366                    (product as $t, (product >> $bits) as $t)
1367                }
1368            }
1369        }
1370    };
1371}
1372
1373#[cfg(feature = "nightly")]
1374macro_rules! const_carrying_mul_impl {
1375    ($t:ty, $double:ty, $bits:expr) => {
1376        c0nst::c0nst! {
1377            impl c0nst ConstCarryingMul for $t {
1378                fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
1379                    <$t>::carrying_mul(self, rhs, carry)
1380                }
1381                fn carrying_mul_add(self, rhs: Self, addend: Self, carry: Self) -> (Self, Self) {
1382                    // No native carrying_mul_add, use carrying_mul + overflowing_add
1383                    let (lo, hi) = <$t>::carrying_mul(self, rhs, carry);
1384                    let (lo2, c) = lo.overflowing_add(addend);
1385                    (lo2, hi.wrapping_add(c as $t))
1386                }
1387            }
1388        }
1389    };
1390}
1391
1392const_carrying_add_impl!(u8);
1393const_carrying_add_impl!(u16);
1394const_carrying_add_impl!(u32);
1395const_carrying_add_impl!(u64);
1396const_carrying_add_impl!(u128);
1397
1398const_borrowing_sub_impl!(u8);
1399const_borrowing_sub_impl!(u16);
1400const_borrowing_sub_impl!(u32);
1401const_borrowing_sub_impl!(u64);
1402const_borrowing_sub_impl!(u128);
1403
1404const_widening_mul_impl!(u8, u16, 8);
1405const_widening_mul_impl!(u16, u32, 16);
1406const_widening_mul_impl!(u32, u64, 32);
1407const_widening_mul_impl!(u64, u128, 64);
1408// TODO: u128 widening_mul requires u256 type (not available in Rust)
1409
1410const_carrying_mul_impl!(u8, u16, 8);
1411const_carrying_mul_impl!(u16, u32, 16);
1412const_carrying_mul_impl!(u32, u64, 32);
1413const_carrying_mul_impl!(u64, u128, 64);
1414// TODO: u128 carrying_mul requires u256 type (not available in Rust)
1415
1416// Native midpoint() requires Rust 1.85+, gate behind 1_87 feature
1417#[cfg(not(feature = "1_87"))]
1418macro_rules! const_midpoint_impl {
1419    ($t:ty) => {
1420        c0nst::c0nst! {
1421            impl c0nst ConstMidpoint for $t {
1422                fn midpoint(self, rhs: Self) -> Self {
1423                    // (a & b) + ((a ^ b) >> 1) avoids overflow
1424                    (self & rhs) + ((self ^ rhs) >> 1)
1425                }
1426            }
1427        }
1428    };
1429}
1430
1431#[cfg(feature = "1_87")]
1432macro_rules! const_midpoint_impl {
1433    ($t:ty) => {
1434        c0nst::c0nst! {
1435            impl c0nst ConstMidpoint for $t {
1436                fn midpoint(self, rhs: Self) -> Self {
1437                    <$t>::midpoint(self, rhs)
1438                }
1439            }
1440        }
1441    };
1442}
1443
1444const_midpoint_impl!(u8);
1445const_midpoint_impl!(u16);
1446const_midpoint_impl!(u32);
1447const_midpoint_impl!(u64);
1448const_midpoint_impl!(u128);
1449
1450// Native unbounded_shl/shr() requires Rust 1.85+, gate behind 1_87 feature
1451#[cfg(not(feature = "1_87"))]
1452macro_rules! const_unbounded_shift_impl {
1453    ($t:ty, $bits:expr) => {
1454        c0nst::c0nst! {
1455            impl c0nst ConstUnboundedShift for $t {
1456                fn unbounded_shl(self, rhs: u32) -> Self {
1457                    if rhs >= $bits { 0 } else { self << rhs }
1458                }
1459                fn unbounded_shr(self, rhs: u32) -> Self {
1460                    if rhs >= $bits { 0 } else { self >> rhs }
1461                }
1462            }
1463        }
1464    };
1465}
1466
1467#[cfg(feature = "1_87")]
1468macro_rules! const_unbounded_shift_impl {
1469    ($t:ty, $bits:expr) => {
1470        c0nst::c0nst! {
1471            impl c0nst ConstUnboundedShift for $t {
1472                fn unbounded_shl(self, rhs: u32) -> Self {
1473                    <$t>::unbounded_shl(self, rhs)
1474                }
1475                fn unbounded_shr(self, rhs: u32) -> Self {
1476                    <$t>::unbounded_shr(self, rhs)
1477                }
1478            }
1479        }
1480    };
1481}
1482
1483const_unbounded_shift_impl!(u8, 8);
1484const_unbounded_shift_impl!(u16, 16);
1485const_unbounded_shift_impl!(u32, 32);
1486const_unbounded_shift_impl!(u64, 64);
1487const_unbounded_shift_impl!(u128, 128);
1488
1489const_bit_prim_int_impl!(u8);
1490const_bit_prim_int_impl!(u16);
1491const_bit_prim_int_impl!(u32);
1492const_bit_prim_int_impl!(u64);
1493const_bit_prim_int_impl!(u128);
1494
1495const_prim_int_impl!(u8);
1496const_prim_int_impl!(u16);
1497const_prim_int_impl!(u32);
1498const_prim_int_impl!(u64);
1499const_prim_int_impl!(u128);
1500
1501#[cfg(test)]
1502mod tests {
1503    use super::*;
1504
1505    c0nst::c0nst! {
1506        pub c0nst fn add_words<T: [c0nst] ConstPrimInt>(a: T, b: T) -> T {
1507            a + b
1508        }
1509
1510        pub c0nst fn assign_add<T: [c0nst] ConstPrimInt>(a: &mut T, b: T) {
1511            *a += b;
1512        }
1513
1514        pub c0nst fn default_word<T: [c0nst] ConstPrimInt>() -> T {
1515            T::default()
1516        }
1517
1518        pub c0nst fn zero_word<T: [c0nst] ConstZero>() -> T {
1519            T::zero()
1520        }
1521
1522        pub c0nst fn one_word<T: [c0nst] ConstOne>() -> T {
1523            T::one()
1524        }
1525
1526        pub c0nst fn min_word<T: [c0nst] ConstBounded>() -> T {
1527            T::min_value()
1528        }
1529
1530        pub c0nst fn max_word<T: [c0nst] ConstBounded>() -> T {
1531            T::max_value()
1532        }
1533
1534        pub c0nst fn is_zero_word<T: [c0nst] ConstZero>(v: &T) -> bool {
1535            v.is_zero()
1536        }
1537
1538        pub c0nst fn set_zero_word<T: [c0nst] ConstZero>(v: &mut T) {
1539            v.set_zero();
1540        }
1541
1542        pub c0nst fn is_one_word<T: [c0nst] ConstOne>(v: &T) -> bool {
1543            v.is_one()
1544        }
1545
1546        pub c0nst fn set_one_word<T: [c0nst] ConstOne>(v: &mut T) {
1547            v.set_one();
1548        }
1549
1550        pub c0nst fn overflowing_add_word<T: [c0nst] ConstOverflowingAdd>(a: &T, b: &T) -> (T, bool) {
1551            a.overflowing_add(b)
1552        }
1553
1554        pub c0nst fn overflowing_sub_word<T: [c0nst] ConstOverflowingSub>(a: &T, b: &T) -> (T, bool) {
1555            a.overflowing_sub(b)
1556        }
1557
1558        pub c0nst fn to_le_bytes_word<T: [c0nst] ConstToBytes>(v: &T) -> T::Bytes {
1559            v.to_le_bytes()
1560        }
1561
1562        pub c0nst fn to_be_bytes_word<T: [c0nst] ConstToBytes>(v: &T) -> T::Bytes {
1563            v.to_be_bytes()
1564        }
1565
1566        pub c0nst fn from_le_bytes_word<T: [c0nst] ConstFromBytes>(bytes: &T::Bytes) -> T {
1567            T::from_le_bytes(bytes)
1568        }
1569
1570        pub c0nst fn from_be_bytes_word<T: [c0nst] ConstFromBytes>(bytes: &T::Bytes) -> T {
1571            T::from_be_bytes(bytes)
1572        }
1573
1574        pub c0nst fn wrapping_add_word<T: [c0nst] ConstWrappingAdd>(a: &T, b: &T) -> T {
1575            a.wrapping_add(b)
1576        }
1577
1578        pub c0nst fn wrapping_sub_word<T: [c0nst] ConstWrappingSub>(a: &T, b: &T) -> T {
1579            a.wrapping_sub(b)
1580        }
1581
1582        pub c0nst fn checked_add_word<T: [c0nst] ConstCheckedAdd>(a: &T, b: &T) -> Option<T> {
1583            a.checked_add(b)
1584        }
1585
1586        pub c0nst fn checked_sub_word<T: [c0nst] ConstCheckedSub>(a: &T, b: &T) -> Option<T> {
1587            a.checked_sub(b)
1588        }
1589
1590        pub c0nst fn saturating_add_word<T: [c0nst] ConstSaturatingAdd>(a: &T, b: &T) -> T {
1591            a.saturating_add(b)
1592        }
1593
1594        pub c0nst fn saturating_sub_word<T: [c0nst] ConstSaturatingSub>(a: &T, b: &T) -> T {
1595            a.saturating_sub(b)
1596        }
1597
1598        pub c0nst fn carrying_add_word<T: [c0nst] ConstCarryingAdd>(a: T, b: T, carry: bool) -> (T, bool) {
1599            a.carrying_add(b, carry)
1600        }
1601
1602        pub c0nst fn borrowing_sub_word<T: [c0nst] ConstBorrowingSub>(a: T, b: T, borrow: bool) -> (T, bool) {
1603            a.borrowing_sub(b, borrow)
1604        }
1605
1606        pub c0nst fn widening_mul_word<T: [c0nst] ConstWideningMul>(a: T, b: T) -> (T, T) {
1607            a.widening_mul(b)
1608        }
1609
1610        pub c0nst fn carrying_mul_word<T: [c0nst] ConstCarryingMul>(a: T, b: T, carry: T) -> (T, T) {
1611            a.carrying_mul(b, carry)
1612        }
1613
1614        pub c0nst fn carrying_mul_add_word<T: [c0nst] ConstCarryingMul>(a: T, b: T, addend: T, carry: T) -> (T, T) {
1615            a.carrying_mul_add(b, addend, carry)
1616        }
1617
1618        pub c0nst fn midpoint_word<T: [c0nst] ConstMidpoint>(a: T, b: T) -> T {
1619            a.midpoint(b)
1620        }
1621
1622        pub c0nst fn unbounded_shl_word<T: [c0nst] ConstUnboundedShift>(a: T, n: u32) -> T {
1623            a.unbounded_shl(n)
1624        }
1625
1626        pub c0nst fn unbounded_shr_word<T: [c0nst] ConstUnboundedShift>(a: T, n: u32) -> T {
1627            a.unbounded_shr(n)
1628        }
1629    }
1630
1631    #[test]
1632    fn test_constprimint_ops() {
1633        assert_eq!(add_words(2u8, 3u8), 5u8);
1634        assert_eq!(default_word::<u32>(), 0u32);
1635        assert_eq!(zero_word::<u64>(), 0u64);
1636        assert_eq!(one_word::<u128>(), 1u128);
1637        assert_eq!(min_word::<u8>(), 0u8);
1638        assert_eq!(max_word::<u8>(), 255u8);
1639
1640        let mut val = 10u8;
1641        assign_add(&mut val, 5u8);
1642        assert_eq!(val, 15u8);
1643
1644        #[cfg(feature = "nightly")]
1645        {
1646            const ADD_RES: u8 = add_words(2u8, 3u8);
1647            const DEFAULT_RES: u32 = default_word::<u32>();
1648            const ZERO_RES: u64 = zero_word::<u64>();
1649            const ONE_RES: u128 = one_word::<u128>();
1650            const MIN_RES: u8 = min_word::<u8>();
1651            const MAX_RES: u8 = max_word::<u8>();
1652            const ASSIGN_RES: u8 = {
1653                let mut v = 10u8;
1654                assign_add(&mut v, 5u8);
1655                v
1656            };
1657            assert_eq!(ADD_RES, 5u8);
1658            assert_eq!(DEFAULT_RES, 0u32);
1659            assert_eq!(ZERO_RES, 0u64);
1660            assert_eq!(ONE_RES, 1u128);
1661            assert_eq!(MIN_RES, 0u8);
1662            assert_eq!(MAX_RES, 255u8);
1663            assert_eq!(ASSIGN_RES, 15u8);
1664        }
1665    }
1666
1667    #[test]
1668    fn test_const_zero_one_methods() {
1669        // Test is_zero
1670        assert!(is_zero_word(&0u8));
1671        assert!(!is_zero_word(&1u8));
1672        assert!(is_zero_word(&0u64));
1673        assert!(!is_zero_word(&42u64));
1674
1675        // Test set_zero
1676        let mut val = 42u32;
1677        set_zero_word(&mut val);
1678        assert_eq!(val, 0u32);
1679
1680        // Test is_one
1681        assert!(is_one_word(&1u8));
1682        assert!(!is_one_word(&0u8));
1683        assert!(!is_one_word(&2u8));
1684        assert!(is_one_word(&1u128));
1685
1686        // Test set_one
1687        let mut val = 0u16;
1688        set_one_word(&mut val);
1689        assert_eq!(val, 1u16);
1690
1691        #[cfg(feature = "nightly")]
1692        {
1693            const IS_ZERO_TRUE: bool = is_zero_word(&0u8);
1694            const IS_ZERO_FALSE: bool = is_zero_word(&1u8);
1695            const SET_ZERO_RES: u32 = {
1696                let mut v = 42u32;
1697                set_zero_word(&mut v);
1698                v
1699            };
1700            const IS_ONE_TRUE: bool = is_one_word(&1u64);
1701            const IS_ONE_FALSE: bool = is_one_word(&0u64);
1702            const SET_ONE_RES: u16 = {
1703                let mut v = 0u16;
1704                set_one_word(&mut v);
1705                v
1706            };
1707            assert!(IS_ZERO_TRUE);
1708            assert!(!IS_ZERO_FALSE);
1709            assert_eq!(SET_ZERO_RES, 0u32);
1710            assert!(IS_ONE_TRUE);
1711            assert!(!IS_ONE_FALSE);
1712            assert_eq!(SET_ONE_RES, 1u16);
1713        }
1714    }
1715
1716    #[test]
1717    fn test_const_overflowing_ops() {
1718        // Test overflowing_add without overflow
1719        let (sum, overflow) = overflowing_add_word(&100u8, &50u8);
1720        assert_eq!(sum, 150u8);
1721        assert!(!overflow);
1722
1723        // Test overflowing_add with overflow
1724        let (sum, overflow) = overflowing_add_word(&200u8, &100u8);
1725        assert_eq!(sum, 44u8); // 300 wraps to 44
1726        assert!(overflow);
1727
1728        // Test overflowing_sub without overflow
1729        let (diff, overflow) = overflowing_sub_word(&100u8, &50u8);
1730        assert_eq!(diff, 50u8);
1731        assert!(!overflow);
1732
1733        // Test overflowing_sub with overflow (underflow)
1734        let (diff, overflow) = overflowing_sub_word(&50u8, &100u8);
1735        assert_eq!(diff, 206u8); // wraps around
1736        assert!(overflow);
1737
1738        // Test with larger types
1739        let (sum, overflow) = overflowing_add_word(&u64::MAX, &1u64);
1740        assert_eq!(sum, 0u64);
1741        assert!(overflow);
1742
1743        #[cfg(feature = "nightly")]
1744        {
1745            const ADD_NO_OVERFLOW: (u8, bool) = overflowing_add_word(&100u8, &50u8);
1746            const ADD_OVERFLOW: (u8, bool) = overflowing_add_word(&200u8, &100u8);
1747            const SUB_NO_OVERFLOW: (u8, bool) = overflowing_sub_word(&100u8, &50u8);
1748            const SUB_OVERFLOW: (u8, bool) = overflowing_sub_word(&50u8, &100u8);
1749
1750            assert_eq!(ADD_NO_OVERFLOW, (150u8, false));
1751            assert_eq!(ADD_OVERFLOW, (44u8, true));
1752            assert_eq!(SUB_NO_OVERFLOW, (50u8, false));
1753            assert_eq!(SUB_OVERFLOW, (206u8, true));
1754        }
1755    }
1756
1757    #[test]
1758    fn test_const_to_bytes() {
1759        // Test to_le_bytes
1760        let bytes = to_le_bytes_word(&0x12345678u32);
1761        assert_eq!(bytes.as_ref(), &[0x78, 0x56, 0x34, 0x12]);
1762
1763        // Test to_be_bytes
1764        let bytes = to_be_bytes_word(&0x12345678u32);
1765        assert_eq!(bytes.as_ref(), &[0x12, 0x34, 0x56, 0x78]);
1766
1767        // Test with u8
1768        let bytes = to_le_bytes_word(&0xABu8);
1769        assert_eq!(bytes.as_ref(), &[0xAB]);
1770
1771        // Test with u64
1772        let bytes = to_le_bytes_word(&0x0102030405060708u64);
1773        assert_eq!(
1774            bytes.as_ref(),
1775            &[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]
1776        );
1777
1778        #[cfg(feature = "nightly")]
1779        {
1780            const LE_BYTES: [u8; 4] = to_le_bytes_word(&0x12345678u32);
1781            const BE_BYTES: [u8; 4] = to_be_bytes_word(&0x12345678u32);
1782            assert_eq!(LE_BYTES, [0x78, 0x56, 0x34, 0x12]);
1783            assert_eq!(BE_BYTES, [0x12, 0x34, 0x56, 0x78]);
1784        }
1785    }
1786
1787    #[test]
1788    fn test_const_from_bytes() {
1789        // Test from_le_bytes with u32
1790        let val: u32 = from_le_bytes_word(&[0x78, 0x56, 0x34, 0x12]);
1791        assert_eq!(val, 0x12345678u32);
1792
1793        // Test from_be_bytes with u32
1794        let val: u32 = from_be_bytes_word(&[0x12, 0x34, 0x56, 0x78]);
1795        assert_eq!(val, 0x12345678u32);
1796
1797        // Test with u8
1798        let val: u8 = from_le_bytes_word(&[0xAB]);
1799        assert_eq!(val, 0xABu8);
1800
1801        // Test with u64
1802        let val: u64 = from_le_bytes_word(&[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]);
1803        assert_eq!(val, 0x0102030405060708u64);
1804
1805        // Test roundtrip
1806        let original = 0xDEADBEEFu32;
1807        let bytes = to_le_bytes_word(&original);
1808        let roundtrip: u32 = from_le_bytes_word(&bytes);
1809        assert_eq!(roundtrip, original);
1810
1811        #[cfg(feature = "nightly")]
1812        {
1813            const FROM_LE: u32 = from_le_bytes_word(&[0x78, 0x56, 0x34, 0x12]);
1814            const FROM_BE: u32 = from_be_bytes_word(&[0x12, 0x34, 0x56, 0x78]);
1815            assert_eq!(FROM_LE, 0x12345678u32);
1816            assert_eq!(FROM_BE, 0x12345678u32);
1817        }
1818    }
1819
1820    #[test]
1821    fn test_const_wrapping_checked_ops() {
1822        // Test wrapping_add without overflow
1823        assert_eq!(wrapping_add_word(&100u8, &50u8), 150u8);
1824        // Test wrapping_add with overflow
1825        assert_eq!(wrapping_add_word(&200u8, &100u8), 44u8);
1826
1827        // Test wrapping_sub without overflow
1828        assert_eq!(wrapping_sub_word(&100u8, &50u8), 50u8);
1829        // Test wrapping_sub with overflow (underflow)
1830        assert_eq!(wrapping_sub_word(&50u8, &100u8), 206u8);
1831
1832        // Test checked_add without overflow
1833        assert_eq!(checked_add_word(&100u8, &50u8), Some(150u8));
1834        // Test checked_add with overflow
1835        assert_eq!(checked_add_word(&200u8, &100u8), None);
1836
1837        // Test checked_sub without overflow
1838        assert_eq!(checked_sub_word(&100u8, &50u8), Some(50u8));
1839        // Test checked_sub with overflow (underflow)
1840        assert_eq!(checked_sub_word(&50u8, &100u8), None);
1841
1842        // Test with larger types
1843        assert_eq!(wrapping_add_word(&u64::MAX, &1u64), 0u64);
1844        assert_eq!(checked_add_word(&u64::MAX, &1u64), None);
1845
1846        #[cfg(feature = "nightly")]
1847        {
1848            const WRAP_ADD_NO_OVERFLOW: u8 = wrapping_add_word(&100u8, &50u8);
1849            const WRAP_ADD_OVERFLOW: u8 = wrapping_add_word(&200u8, &100u8);
1850            const WRAP_SUB_NO_OVERFLOW: u8 = wrapping_sub_word(&100u8, &50u8);
1851            const WRAP_SUB_OVERFLOW: u8 = wrapping_sub_word(&50u8, &100u8);
1852
1853            const CHECK_ADD_OK: Option<u8> = checked_add_word(&100u8, &50u8);
1854            const CHECK_ADD_OVERFLOW: Option<u8> = checked_add_word(&200u8, &100u8);
1855            const CHECK_SUB_OK: Option<u8> = checked_sub_word(&100u8, &50u8);
1856            const CHECK_SUB_OVERFLOW: Option<u8> = checked_sub_word(&50u8, &100u8);
1857
1858            assert_eq!(WRAP_ADD_NO_OVERFLOW, 150u8);
1859            assert_eq!(WRAP_ADD_OVERFLOW, 44u8);
1860            assert_eq!(WRAP_SUB_NO_OVERFLOW, 50u8);
1861            assert_eq!(WRAP_SUB_OVERFLOW, 206u8);
1862
1863            assert_eq!(CHECK_ADD_OK, Some(150u8));
1864            assert_eq!(CHECK_ADD_OVERFLOW, None);
1865            assert_eq!(CHECK_SUB_OK, Some(50u8));
1866            assert_eq!(CHECK_SUB_OVERFLOW, None);
1867        }
1868    }
1869
1870    #[test]
1871    fn test_const_saturating_ops() {
1872        // Test saturating_add without overflow
1873        assert_eq!(saturating_add_word(&100u8, &50u8), 150u8);
1874        // Test saturating_add with overflow (saturates at max)
1875        assert_eq!(saturating_add_word(&200u8, &100u8), 255u8);
1876
1877        // Test saturating_sub without overflow
1878        assert_eq!(saturating_sub_word(&100u8, &50u8), 50u8);
1879        // Test saturating_sub with underflow (saturates at zero)
1880        assert_eq!(saturating_sub_word(&50u8, &100u8), 0u8);
1881
1882        // Test with larger types
1883        assert_eq!(saturating_add_word(&u64::MAX, &1u64), u64::MAX);
1884        assert_eq!(saturating_sub_word(&0u64, &1u64), 0u64);
1885
1886        #[cfg(feature = "nightly")]
1887        {
1888            const SAT_ADD_NO_OVERFLOW: u8 = saturating_add_word(&100u8, &50u8);
1889            const SAT_ADD_OVERFLOW: u8 = saturating_add_word(&200u8, &100u8);
1890            const SAT_SUB_NO_OVERFLOW: u8 = saturating_sub_word(&100u8, &50u8);
1891            const SAT_SUB_OVERFLOW: u8 = saturating_sub_word(&50u8, &100u8);
1892
1893            assert_eq!(SAT_ADD_NO_OVERFLOW, 150u8);
1894            assert_eq!(SAT_ADD_OVERFLOW, 255u8);
1895            assert_eq!(SAT_SUB_NO_OVERFLOW, 50u8);
1896            assert_eq!(SAT_SUB_OVERFLOW, 0u8);
1897        }
1898    }
1899
1900    #[test]
1901    fn test_const_carrying_add() {
1902        // No carry in, no carry out
1903        let (sum, carry) = carrying_add_word(100u8, 50u8, false);
1904        assert_eq!(sum, 150u8);
1905        assert!(!carry);
1906
1907        // No carry in, carry out
1908        let (sum, carry) = carrying_add_word(200u8, 100u8, false);
1909        assert_eq!(sum, 44u8); // 300 wraps to 44
1910        assert!(carry);
1911
1912        // Carry in, no carry out
1913        let (sum, carry) = carrying_add_word(100u8, 50u8, true);
1914        assert_eq!(sum, 151u8);
1915        assert!(!carry);
1916
1917        // Carry in, carry out
1918        let (sum, carry) = carrying_add_word(200u8, 55u8, true);
1919        assert_eq!(sum, 0u8); // 256 wraps to 0
1920        assert!(carry);
1921
1922        // Edge case: max + 0 + 1 = carry
1923        let (sum, carry) = carrying_add_word(u8::MAX, 0u8, true);
1924        assert_eq!(sum, 0u8);
1925        assert!(carry);
1926
1927        // Test with larger types
1928        let (sum, carry) = carrying_add_word(u64::MAX, 0u64, true);
1929        assert_eq!(sum, 0u64);
1930        assert!(carry);
1931
1932        #[cfg(feature = "nightly")]
1933        {
1934            const CA_NO_CARRY: (u8, bool) = carrying_add_word(100u8, 50u8, false);
1935            const CA_CARRY_OUT: (u8, bool) = carrying_add_word(200u8, 100u8, false);
1936            const CA_CARRY_IN: (u8, bool) = carrying_add_word(100u8, 50u8, true);
1937            const CA_BOTH_CARRY: (u8, bool) = carrying_add_word(200u8, 55u8, true);
1938
1939            assert_eq!(CA_NO_CARRY, (150u8, false));
1940            assert_eq!(CA_CARRY_OUT, (44u8, true));
1941            assert_eq!(CA_CARRY_IN, (151u8, false));
1942            assert_eq!(CA_BOTH_CARRY, (0u8, true));
1943        }
1944    }
1945
1946    #[test]
1947    fn test_const_borrowing_sub() {
1948        // No borrow in, no borrow out
1949        let (diff, borrow) = borrowing_sub_word(100u8, 50u8, false);
1950        assert_eq!(diff, 50u8);
1951        assert!(!borrow);
1952
1953        // No borrow in, borrow out
1954        let (diff, borrow) = borrowing_sub_word(50u8, 100u8, false);
1955        assert_eq!(diff, 206u8); // wraps around
1956        assert!(borrow);
1957
1958        // Borrow in, no borrow out
1959        let (diff, borrow) = borrowing_sub_word(100u8, 50u8, true);
1960        assert_eq!(diff, 49u8);
1961        assert!(!borrow);
1962
1963        // Borrow in, borrow out
1964        let (diff, borrow) = borrowing_sub_word(50u8, 50u8, true);
1965        assert_eq!(diff, 255u8); // 0 - 1 wraps to 255
1966        assert!(borrow);
1967
1968        // Edge case: 0 - 0 - 1 = borrow
1969        let (diff, borrow) = borrowing_sub_word(0u8, 0u8, true);
1970        assert_eq!(diff, 255u8);
1971        assert!(borrow);
1972
1973        // Test with larger types
1974        let (diff, borrow) = borrowing_sub_word(0u64, 0u64, true);
1975        assert_eq!(diff, u64::MAX);
1976        assert!(borrow);
1977
1978        #[cfg(feature = "nightly")]
1979        {
1980            const BS_NO_BORROW: (u8, bool) = borrowing_sub_word(100u8, 50u8, false);
1981            const BS_BORROW_OUT: (u8, bool) = borrowing_sub_word(50u8, 100u8, false);
1982            const BS_BORROW_IN: (u8, bool) = borrowing_sub_word(100u8, 50u8, true);
1983            const BS_BOTH_BORROW: (u8, bool) = borrowing_sub_word(50u8, 50u8, true);
1984
1985            assert_eq!(BS_NO_BORROW, (50u8, false));
1986            assert_eq!(BS_BORROW_OUT, (206u8, true));
1987            assert_eq!(BS_BORROW_IN, (49u8, false));
1988            assert_eq!(BS_BOTH_BORROW, (255u8, true));
1989        }
1990    }
1991
1992    #[test]
1993    fn test_const_widening_mul() {
1994        // Simple multiplication, no high part
1995        let (lo, hi) = widening_mul_word(10u8, 5u8);
1996        assert_eq!(lo, 50u8);
1997        assert_eq!(hi, 0u8);
1998
1999        // Multiplication with high part
2000        let (lo, hi) = widening_mul_word(200u8, 3u8);
2001        assert_eq!(lo, 88u8); // 600 & 0xFF = 88
2002        assert_eq!(hi, 2u8); // 600 >> 8 = 2
2003
2004        // Max * max
2005        let (lo, hi) = widening_mul_word(u8::MAX, u8::MAX);
2006        // 255 * 255 = 65025 = 0xFE01
2007        assert_eq!(lo, 0x01u8);
2008        assert_eq!(hi, 0xFEu8);
2009
2010        // Test with u16
2011        let (lo, hi) = widening_mul_word(1000u16, 1000u16);
2012        // 1000 * 1000 = 1000000 = 0x000F4240
2013        assert_eq!(lo, 0x4240u16);
2014        assert_eq!(hi, 0x000Fu16);
2015
2016        // Test with u64
2017        let (lo, hi) = widening_mul_word(u64::MAX, 2u64);
2018        // MAX * 2 = 2 * (2^64 - 1) = 2^65 - 2 = (1, MAX-1)
2019        assert_eq!(lo, u64::MAX - 1);
2020        assert_eq!(hi, 1u64);
2021
2022        #[cfg(feature = "nightly")]
2023        {
2024            const WM_SIMPLE: (u8, u8) = widening_mul_word(10u8, 5u8);
2025            const WM_HIGH: (u8, u8) = widening_mul_word(200u8, 3u8);
2026            const WM_MAX: (u8, u8) = widening_mul_word(u8::MAX, u8::MAX);
2027
2028            assert_eq!(WM_SIMPLE, (50u8, 0u8));
2029            assert_eq!(WM_HIGH, (88u8, 2u8));
2030            assert_eq!(WM_MAX, (0x01u8, 0xFEu8));
2031        }
2032    }
2033
2034    #[test]
2035    fn test_const_carrying_mul() {
2036        // Simple multiplication with no carry
2037        let (lo, hi) = carrying_mul_word(10u8, 5u8, 0u8);
2038        assert_eq!(lo, 50u8);
2039        assert_eq!(hi, 0u8);
2040
2041        // Multiplication with carry added
2042        let (lo, hi) = carrying_mul_word(10u8, 5u8, 10u8);
2043        // 10 * 5 + 10 = 60
2044        assert_eq!(lo, 60u8);
2045        assert_eq!(hi, 0u8);
2046
2047        // Multiplication with high part
2048        let (lo, hi) = carrying_mul_word(200u8, 3u8, 0u8);
2049        assert_eq!(lo, 88u8); // 600 & 0xFF
2050        assert_eq!(hi, 2u8); // 600 >> 8
2051
2052        // Multiplication with carry causing high part
2053        let (lo, hi) = carrying_mul_word(200u8, 3u8, 200u8);
2054        // 200 * 3 + 200 = 800 = 0x0320
2055        assert_eq!(lo, 0x20u8);
2056        assert_eq!(hi, 3u8);
2057
2058        // Max values
2059        let (lo, hi) = carrying_mul_word(u8::MAX, u8::MAX, u8::MAX);
2060        // 255 * 255 + 255 = 65280 = 0xFF00
2061        assert_eq!(lo, 0x00u8);
2062        assert_eq!(hi, 0xFFu8);
2063
2064        // Test with u16
2065        let (lo, hi) = carrying_mul_word(1000u16, 1000u16, 1000u16);
2066        // 1000 * 1000 + 1000 = 1001000 = 0x000F4628
2067        assert_eq!(lo, 0x4628u16);
2068        assert_eq!(hi, 0x000Fu16);
2069
2070        #[cfg(feature = "nightly")]
2071        {
2072            const CM_SIMPLE: (u8, u8) = carrying_mul_word(10u8, 5u8, 0u8);
2073            const CM_WITH_CARRY: (u8, u8) = carrying_mul_word(10u8, 5u8, 10u8);
2074            const CM_MAX: (u8, u8) = carrying_mul_word(u8::MAX, u8::MAX, u8::MAX);
2075
2076            assert_eq!(CM_SIMPLE, (50u8, 0u8));
2077            assert_eq!(CM_WITH_CARRY, (60u8, 0u8));
2078            assert_eq!(CM_MAX, (0x00u8, 0xFFu8));
2079        }
2080    }
2081
2082    #[test]
2083    fn test_const_carrying_mul_add() {
2084        // Simple: 10 * 5 + 7 + 0 = 57
2085        let (lo, hi) = carrying_mul_add_word(10u8, 5u8, 7u8, 0u8);
2086        assert_eq!(lo, 57u8);
2087        assert_eq!(hi, 0u8);
2088
2089        // With all params: 10 * 5 + 10 + 10 = 70
2090        let (lo, hi) = carrying_mul_add_word(10u8, 5u8, 10u8, 10u8);
2091        assert_eq!(lo, 70u8);
2092        assert_eq!(hi, 0u8);
2093
2094        // Addend causes lo overflow: 200 * 3 + 200 + 0 = 800 = 0x0320
2095        // Then we add extra addend to test lo overflow path
2096        // 16 * 16 + 0 + 0 = 256 = 0x0100
2097        let (lo, hi) = carrying_mul_add_word(16u8, 16u8, 0u8, 0u8);
2098        assert_eq!(lo, 0x00u8);
2099        assert_eq!(hi, 1u8);
2100
2101        // Max case: 255 * 255 + 255 + 255 = 65535 = 0xFFFF
2102        // This exercises hi = 0xFF with addend causing no overflow
2103        // (since carrying_mul gives lo=0 when hi=0xFF)
2104        let (lo, hi) = carrying_mul_add_word(u8::MAX, u8::MAX, u8::MAX, u8::MAX);
2105        // 255 * 255 + 255 = 65280 = 0xFF00, then + 255 = 65535 = 0xFFFF
2106        assert_eq!(lo, 0xFFu8);
2107        assert_eq!(hi, 0xFFu8);
2108
2109        // Test case that would trigger wrapping_add:
2110        // We need hi to be MAX and carry from lo addition
2111        // For u8: 255 * 255 + 255 gives (0, 255), then adding 255 gives (255, 255)
2112        // Since lo=0, adding any addend won't overflow, so hi stays 255
2113        // The wrapping_add is for safety even though u8 can't trigger it
2114
2115        #[cfg(feature = "nightly")]
2116        {
2117            const CMA_SIMPLE: (u8, u8) = carrying_mul_add_word(10u8, 5u8, 7u8, 0u8);
2118            const CMA_MAX: (u8, u8) = carrying_mul_add_word(u8::MAX, u8::MAX, u8::MAX, u8::MAX);
2119
2120            assert_eq!(CMA_SIMPLE, (57u8, 0u8));
2121            assert_eq!(CMA_MAX, (0xFFu8, 0xFFu8));
2122        }
2123    }
2124
2125    #[test]
2126    fn test_const_midpoint() {
2127        // Simple midpoint
2128        assert_eq!(midpoint_word(0u8, 10u8), 5u8);
2129        assert_eq!(midpoint_word(10u8, 0u8), 5u8); // order doesn't matter
2130
2131        // Midpoint rounds down
2132        assert_eq!(midpoint_word(0u8, 9u8), 4u8); // (0+9)/2 = 4.5 -> 4
2133        assert_eq!(midpoint_word(1u8, 10u8), 5u8); // (1+10)/2 = 5.5 -> 5
2134
2135        // Same values
2136        assert_eq!(midpoint_word(42u8, 42u8), 42u8);
2137
2138        // Edge cases with max values (no overflow!)
2139        assert_eq!(midpoint_word(u8::MAX, u8::MAX), u8::MAX);
2140        assert_eq!(midpoint_word(u8::MAX, u8::MAX - 1), u8::MAX - 1); // rounds down
2141        assert_eq!(midpoint_word(0u8, u8::MAX), 127u8); // (0+255)/2 = 127.5 -> 127
2142
2143        // Test with larger types
2144        assert_eq!(midpoint_word(0u64, 100u64), 50u64);
2145        assert_eq!(midpoint_word(u64::MAX, u64::MAX), u64::MAX);
2146        assert_eq!(midpoint_word(u64::MAX - 1, u64::MAX), u64::MAX - 1); // rounds down
2147
2148        // u128
2149        assert_eq!(midpoint_word(0u128, u128::MAX), u128::MAX / 2);
2150
2151        #[cfg(feature = "nightly")]
2152        {
2153            const MID_SIMPLE: u8 = midpoint_word(0u8, 10u8);
2154            const MID_ROUND: u8 = midpoint_word(0u8, 9u8);
2155            const MID_MAX: u8 = midpoint_word(u8::MAX, u8::MAX);
2156            const MID_EDGE: u8 = midpoint_word(0u8, u8::MAX);
2157
2158            assert_eq!(MID_SIMPLE, 5u8);
2159            assert_eq!(MID_ROUND, 4u8);
2160            assert_eq!(MID_MAX, u8::MAX);
2161            assert_eq!(MID_EDGE, 127u8);
2162        }
2163    }
2164
2165    #[test]
2166    fn test_const_unbounded_shift() {
2167        // Normal shifts (within bounds)
2168        assert_eq!(unbounded_shl_word(1u8, 0), 1u8);
2169        assert_eq!(unbounded_shl_word(1u8, 1), 2u8);
2170        assert_eq!(unbounded_shl_word(1u8, 7), 128u8);
2171        assert_eq!(unbounded_shr_word(128u8, 7), 1u8);
2172        assert_eq!(unbounded_shr_word(255u8, 4), 15u8);
2173
2174        // At boundary (shift by bit width)
2175        assert_eq!(unbounded_shl_word(1u8, 8), 0u8);
2176        assert_eq!(unbounded_shr_word(255u8, 8), 0u8);
2177
2178        // Beyond boundary
2179        assert_eq!(unbounded_shl_word(255u8, 9), 0u8);
2180        assert_eq!(unbounded_shl_word(255u8, 100), 0u8);
2181        assert_eq!(unbounded_shr_word(255u8, 9), 0u8);
2182        assert_eq!(unbounded_shr_word(255u8, 100), 0u8);
2183
2184        // Test with larger types
2185        assert_eq!(unbounded_shl_word(1u64, 63), 1u64 << 63);
2186        assert_eq!(unbounded_shl_word(1u64, 64), 0u64);
2187        assert_eq!(unbounded_shr_word(u64::MAX, 64), 0u64);
2188
2189        // u128
2190        assert_eq!(unbounded_shl_word(1u128, 127), 1u128 << 127);
2191        assert_eq!(unbounded_shl_word(1u128, 128), 0u128);
2192        assert_eq!(unbounded_shr_word(u128::MAX, 128), 0u128);
2193
2194        #[cfg(feature = "nightly")]
2195        {
2196            const SHL_NORMAL: u8 = unbounded_shl_word(1u8, 4);
2197            const SHL_BOUNDARY: u8 = unbounded_shl_word(1u8, 8);
2198            const SHL_BEYOND: u8 = unbounded_shl_word(1u8, 100);
2199            const SHR_NORMAL: u8 = unbounded_shr_word(128u8, 4);
2200            const SHR_BOUNDARY: u8 = unbounded_shr_word(255u8, 8);
2201            const SHR_BEYOND: u8 = unbounded_shr_word(255u8, 100);
2202
2203            assert_eq!(SHL_NORMAL, 16u8);
2204            assert_eq!(SHL_BOUNDARY, 0u8);
2205            assert_eq!(SHL_BEYOND, 0u8);
2206            assert_eq!(SHR_NORMAL, 8u8);
2207            assert_eq!(SHR_BOUNDARY, 0u8);
2208            assert_eq!(SHR_BEYOND, 0u8);
2209        }
2210    }
2211}