Skip to main content

const_num_traits/ops/
typestate.rs

1//! Zero-cost typestate proofs.
2//!
3//! A *typestate* is a zero-runtime-cost proof that a value satisfies a
4//! structural property, built once by a checked constructor and *spent* by an
5//! op that exploits it to delete a branch, an `Option`, or a division. Every
6//! type here ships at least one such consuming op. Pure-`core` and always
7//! available — it costs nothing unless its types are named.
8//!
9//! Resident families:
10//! - [`PowerOfTwo`] + [`PowerOfTwoOps`] (unsigned): div/rem/align as shifts/masks.
11//! - [`BitIndex`] + [`BitIndexOps`] (all ints): shift by an amount proven `< BITS`.
12//! - [`HasNonZero`] bridge to [`core::num::NonZero`] + [`DivNonZero`] (unsigned):
13//!   infallible division.
14//! - [`NonNegative`] / [`Positive`] (signed): unsigned cast, `abs`, `isqrt`, plus
15//!   `const` narrowings into each other / `NonZero` / `NonMin`.
16//! - [`NonMin`] (signed): total `neg`/`abs` and total signed division.
17//! - [`Odd`] / [`Even`]: bare proofs (no consuming op in this crate).
18//! - [`Finite`] (floats): a total order (`Ord`/`Eq`) that bare floats lack.
19//!
20//! With the `ct` feature, families with a *secret-derived* predicate also gain a
21//! masked `new_ct`. [`BitIndex`] (public shift amounts) and [`Finite`] (floats
22//! are outside the CT model) have none.
23
24use crate::int::PrimBits;
25use crate::ops::parity::Parity;
26use crate::ops::pow2::IsPowerOfTwo;
27use core::marker::PhantomData;
28
29/// Error returned by the `TryFrom` constructors of the typestate proofs when
30/// the value fails the proof's predicate (e.g. a non-odd value into [`Odd`]).
31///
32/// A single shared, zero-sized error: the target type at the call site already
33/// names which predicate failed. The fallible *reference* narrowing keeps using
34/// the lighter inherent `from_ref` (returning `Option`) — `core` has no trait
35/// for fallible reference conversion, so there is nothing to mirror there.
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub struct TypestateError;
38
39impl core::fmt::Display for TypestateError {
40    #[inline]
41    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42        f.write_str("value does not satisfy the typestate's predicate")
43    }
44}
45
46// `core::error::Error` is available in `no_std` since Rust 1.81 (< our MSRV).
47impl core::error::Error for TypestateError {}
48
49/// Proof that a value is a power of two (`2^k`, `k ≥ 0`), for an unsigned
50/// integer type `T`.
51///
52/// **Representation is the exponent `k`, not the value** — so the consuming
53/// operations in [`PowerOfTwoOps`] are pure shifts and masks with nothing
54/// recomputed per call, and a (future) big-integer backend carries a tiny
55/// `u32` proof regardless of its width. The field is private, so the
56/// representation is an implementation detail. Consequently `PowerOfTwo` does
57/// **not** deref to `T`; use [`get`](Self::get) (which reconstructs `1 << k`)
58/// or [`exp`](Self::exp).
59///
60/// `PowerOfTwo<T>` is always `Copy` (it stores only a `u32`), independent of
61/// whether `T` is.
62///
63/// # Examples
64///
65/// ```
66/// use const_num_traits::{PowerOfTwo, PowerOfTwoOps};
67///
68/// let p = PowerOfTwo::<u32>::new(16).unwrap();
69/// assert_eq!(p.exp(), 4);
70/// assert_eq!(p.get(), 16);
71/// assert_eq!(100u32.div_pow2(p), 6); // 100 / 16
72/// assert_eq!(100u32.rem_pow2(p), 4); // 100 % 16
73/// assert!(PowerOfTwo::<u32>::new(6).is_none());
74/// ```
75pub struct PowerOfTwo<T> {
76    // Invariant: `1 << exp` is a valid power of two of `T` (`exp < T::BITS`).
77    exp: u32,
78    _t: PhantomData<T>,
79}
80
81impl<T> Clone for PowerOfTwo<T> {
82    #[inline]
83    fn clone(&self) -> Self {
84        *self
85    }
86}
87impl<T> Copy for PowerOfTwo<T> {}
88
89impl<T> PowerOfTwo<T> {
90    /// Constructs the proof directly from an exponent, without checking.
91    ///
92    /// # Safety
93    ///
94    /// `exp` must be `< T::BITS` (so that `1 << exp` is a valid power of two of
95    /// `T`). Passing a too-large exponent makes the consuming ops produce
96    /// nonsense or overflow.
97    #[inline]
98    pub const unsafe fn from_exp_unchecked(exp: u32) -> Self {
99        PowerOfTwo {
100            exp,
101            _t: PhantomData,
102        }
103    }
104
105    /// The exponent `k` such that the proven value is `2^k`. Free (no recompute).
106    #[inline]
107    pub const fn exp(self) -> u32 {
108        self.exp
109    }
110}
111
112c0nst::c0nst! {
113impl<T> PowerOfTwo<T> {
114    /// Safe constructor for any carrier, not just the primitives: `Some` iff
115    /// `value` is a power of two. Keeps the `unsafe` crate-internal; the
116    /// per-primitive [`new`](Self::new) stays the `const` fast path.
117    #[inline]
118    pub c0nst fn new_checked(value: T) -> Option<Self>
119    where
120        T: [c0nst] IsPowerOfTwo + [c0nst] PrimBits,
121    {
122        if value.is_power_of_two() {
123            let width = T::ZERO.count_zeros();
124            let exp = width - 1 - value.leading_zeros();
125            // SAFETY: `value` is a power of two, so `exp < width` (= `T::BITS`).
126            Some(unsafe { Self::from_exp_unchecked(exp) })
127        } else {
128            None
129        }
130    }
131}
132}
133
134c0nst::c0nst! {
135/// Operations that *consume* a [`PowerOfTwo`] proof to replace division and
136/// remainder with a shift and a mask. Distinct from the blanket
137/// `MultipleOf`/`NextMultipleOf`, which can't be specialised on a power-of-two
138/// divisor on stable Rust.
139///
140/// Owned results carry an associated [`Output`](Self::Output) so non-`Copy`
141/// types can implement the trait for their reference type.
142pub c0nst trait PowerOfTwoOps: Sized {
143    /// The owned result type (`Self` for the primitive impls).
144    type Output;
145
146    /// `self / p`, computed as `self >> p.exp()`.
147    fn div_pow2(self, p: PowerOfTwo<Self>) -> Self::Output;
148
149    /// `self % p`, computed as `self & ((1 << p.exp()) - 1)`.
150    fn rem_pow2(self, p: PowerOfTwo<Self>) -> Self::Output;
151
152    /// `self % p == 0`, computed as a mask test (no division).
153    fn is_multiple_of_pow2(self, p: PowerOfTwo<Self>) -> bool;
154
155    /// Smallest multiple of `p` that is `>= self` ("align up"), computed
156    /// branch-free as `(self + mask) & !mask`. Uses `+`, so it **panics on
157    /// overflow in debug** (and the const-eval form errors) when `self` is
158    /// within `p` of the maximum — use
159    /// [`checked_next_multiple_of_pow2`](Self::checked_next_multiple_of_pow2)
160    /// for untrusted input.
161    fn next_multiple_of_pow2(self, p: PowerOfTwo<Self>) -> Self::Output;
162
163    /// [`next_multiple_of_pow2`](Self::next_multiple_of_pow2), returning `None`
164    /// on overflow instead of panicking.
165    fn checked_next_multiple_of_pow2(self, p: PowerOfTwo<Self>) -> Option<Self::Output>;
166}
167}
168
169macro_rules! pow2_typestate_impl {
170    ($($t:ty),+) => {$(
171        impl PowerOfTwo<$t> {
172            /// Checked constructor: `Some` iff `value` is a power of two.
173            ///
174            /// `const fn` on stable and nightly (delegates to the inherent
175            /// `is_power_of_two`/`ilog2`, both const since ≤ 1.67).
176            #[inline]
177            pub const fn new(value: $t) -> Option<Self> {
178                if value.is_power_of_two() {
179                    Some(PowerOfTwo { exp: value.ilog2(), _t: PhantomData })
180                } else {
181                    None
182                }
183            }
184
185            /// Reconstructs the proven value, `1 << exp`.
186            #[inline]
187            pub const fn get(self) -> $t {
188                (1 as $t) << self.exp
189            }
190        }
191
192        c0nst::c0nst! {
193        c0nst impl PowerOfTwoOps for $t {
194            type Output = $t;
195
196            #[inline]
197            fn div_pow2(self, p: PowerOfTwo<$t>) -> $t {
198                self >> p.exp
199            }
200
201            #[inline]
202            fn rem_pow2(self, p: PowerOfTwo<$t>) -> $t {
203                let mask = ((1 as $t) << p.exp) - 1;
204                self & mask
205            }
206
207            #[inline]
208            fn is_multiple_of_pow2(self, p: PowerOfTwo<$t>) -> bool {
209                let mask = ((1 as $t) << p.exp) - 1;
210                (self & mask) == 0
211            }
212
213            #[inline]
214            fn next_multiple_of_pow2(self, p: PowerOfTwo<$t>) -> $t {
215                let mask = ((1 as $t) << p.exp) - 1;
216                (self + mask) & !mask
217            }
218
219            #[inline]
220            fn checked_next_multiple_of_pow2(self, p: PowerOfTwo<$t>) -> Option<$t> {
221                let mask = ((1 as $t) << p.exp) - 1;
222                match self.checked_add(mask) {
223                    Some(s) => Some(s & !mask),
224                    None => None,
225                }
226            }
227        }
228        }
229
230        /// Checked construction by value; mirrors [`PowerOfTwo::new`]. (The
231        /// generic carrier path stays [`PowerOfTwo::new_checked`].)
232        impl TryFrom<$t> for PowerOfTwo<$t> {
233            type Error = TypestateError;
234            #[inline]
235            fn try_from(value: $t) -> Result<Self, TypestateError> {
236                Self::new(value).ok_or(TypestateError)
237            }
238        }
239    )+};
240}
241
242pow2_typestate_impl!(u8, u16, u32, u64, u128, usize);
243
244// ─────────────────────────────── BitIndex (shift amount) ──────────────────
245
246/// Proof that a value is a valid bit index for `T` (`0 <= index < T::BITS`), so
247/// a shift by it can't overflow, panic, or hit the "shift `>= BITS`" UB.
248///
249/// Like [`PowerOfTwo`], the rep is the `u32` index (never `T`), so the proof is
250/// `Copy` regardless of `T`; consuming ops live in [`BitIndexOps`] (signed and
251/// unsigned). No constant-time constructor — shift amounts are public.
252///
253/// ```
254/// use const_num_traits::{BitIndex, BitIndexOps};
255///
256/// let i = BitIndex::<u8>::new(3).unwrap();
257/// assert_eq!(1u8.shl_index(i), 8);
258/// assert_eq!(0x80u8.shr_index(i), 0x10);
259/// assert!(BitIndex::<u8>::new(8).is_none()); // == BITS, rejected
260/// ```
261pub struct BitIndex<T> {
262    // Invariant: `index < T::BITS`.
263    index: u32,
264    _t: PhantomData<T>,
265}
266
267impl<T> Clone for BitIndex<T> {
268    #[inline]
269    fn clone(&self) -> Self {
270        *self
271    }
272}
273impl<T> Copy for BitIndex<T> {}
274
275impl<T> BitIndex<T> {
276    /// Constructs the proof directly from an index, without checking.
277    ///
278    /// # Safety
279    ///
280    /// `index` must be `< T::BITS`; otherwise the consuming shifts are
281    /// undefined / panic.
282    #[inline]
283    pub const unsafe fn from_u32_unchecked(index: u32) -> Self {
284        BitIndex {
285            index,
286            _t: PhantomData,
287        }
288    }
289
290    /// The proven index. Free (no recompute).
291    #[inline]
292    pub const fn get(self) -> u32 {
293        self.index
294    }
295}
296
297c0nst::c0nst! {
298impl<T> BitIndex<T> {
299    /// Safe constructor for any [`PrimBits`] carrier, not just the primitives:
300    /// `Some` iff `index < T::BITS`. The per-primitive [`new`](Self::new) stays
301    /// the `const` fast path.
302    #[inline]
303    pub c0nst fn new_checked(index: u32) -> Option<Self>
304    where
305        T: [c0nst] PrimBits,
306    {
307        if index < T::ZERO.count_zeros() {
308            Some(BitIndex { index, _t: PhantomData })
309        } else {
310            None
311        }
312    }
313}
314}
315
316c0nst::c0nst! {
317/// Operations that *consume* a [`BitIndex`] proof to shift without the
318/// overflow-check branch: the amount is proven `< BITS`, so there is no
319/// debug-time panic and no `unbounded_*` masking.
320///
321/// Owned results carry an associated [`Output`](Self::Output) so non-`Copy`
322/// types can implement the trait for their reference type.
323pub c0nst trait BitIndexOps: Sized {
324    /// The owned result type (`Self` for the primitive impls).
325    type Output;
326
327    /// `self << index`, total because `index < BITS`.
328    fn shl_index(self, index: BitIndex<Self>) -> Self::Output;
329
330    /// `self >> index`, total because `index < BITS`.
331    fn shr_index(self, index: BitIndex<Self>) -> Self::Output;
332}
333}
334
335macro_rules! bit_index_impl {
336    ($($t:ty),+) => {$(
337        impl BitIndex<$t> {
338            /// Checked constructor: `Some` iff `index < <$t>::BITS`.
339            #[inline]
340            pub const fn new(index: u32) -> Option<Self> {
341                if index < <$t>::BITS {
342                    Some(BitIndex { index, _t: PhantomData })
343                } else {
344                    None
345                }
346            }
347        }
348
349        c0nst::c0nst! {
350        c0nst impl BitIndexOps for $t {
351            type Output = $t;
352
353            #[inline]
354            fn shl_index(self, index: BitIndex<$t>) -> $t {
355                self << index.index
356            }
357
358            #[inline]
359            fn shr_index(self, index: BitIndex<$t>) -> $t {
360                self >> index.index
361            }
362        }
363        }
364
365        /// Checked construction from an index (`< BITS`); mirrors
366        /// [`BitIndex::new`]. The source is the `u32` index, not the carrier `$t`.
367        impl TryFrom<u32> for BitIndex<$t> {
368            type Error = TypestateError;
369            #[inline]
370            fn try_from(index: u32) -> Result<Self, TypestateError> {
371                Self::new(index).ok_or(TypestateError)
372            }
373        }
374    )+};
375}
376
377bit_index_impl!(
378    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
379);
380
381// ─────────────────────────────── NonZero bridge ───────────────────────────
382
383c0nst::c0nst! {
384/// Bridge to [`core::num::NonZero`] — "the non-zero form of `Self`".
385///
386/// This does **not** duplicate `core::num::NonZero`: for the integer primitives
387/// [`NonZero`](Self::NonZero) *is* `core::num::NonZero<Self>`, with its real
388/// niche. (`core::num::NonZero<T>` is sealed to primitives, so a future bignum
389/// backend supplies its own non-zero type as the associated type instead.)
390///
391/// The value is recovered through the crate-owned const accessor
392/// [`nonzero_get`](Self::nonzero_get) rather than an `Into<Self>` bound:
393/// `From<NonZero<T>> for T` is not `const`, so such a bound would poison every
394/// generic `const` consumer.
395pub c0nst trait HasNonZero: Sized {
396    /// The non-zero form of `Self` (`core::num::NonZero<Self>` for primitives).
397    type NonZero: Copy;
398
399    /// `Some` iff `self != 0`.
400    fn into_nonzero(self) -> Option<Self::NonZero>;
401
402    /// Recover the underlying value from its non-zero form.
403    fn nonzero_get(nz: Self::NonZero) -> Self;
404}
405}
406
407c0nst::c0nst! {
408/// Infallible division / remainder by a proven-non-zero divisor.
409///
410/// `div_nonzero` / `rem_nonzero` have no divide-by-zero branch and never return
411/// `Option`. For the *primitives* the codegen win is ≈ 0 — LLVM already elides
412/// the check via `NonZero`'s niche; the wins are the `Option`-free API and
413/// big-integer backends' hand-written no-branch division.
414///
415/// **Unsigned only.** Signed `MIN / -1` still overflows, so the total signed
416/// form lives on [`NonMin::div_nonzero`] / [`NonMin::rem_nonzero`] (the dividend
417/// proven `!= MIN`), not here.
418pub c0nst trait DivNonZero: [c0nst] HasNonZero {
419    /// Owned result. A fresh `Output` — the divisor is `Self::NonZero`, not
420    /// `Self`, so `Div::Output` cannot be reused.
421    type Output;
422
423    /// `self / d`, infallibly.
424    fn div_nonzero(self, d: Self::NonZero) -> Self::Output;
425
426    /// `self % d`, infallibly.
427    fn rem_nonzero(self, d: Self::NonZero) -> Self::Output;
428}
429}
430
431macro_rules! nonzero_bridge_impl {
432    ($($t:ty),+) => {$(
433        c0nst::c0nst! {
434        c0nst impl HasNonZero for $t {
435            type NonZero = core::num::NonZero<$t>;
436
437            #[inline]
438            fn into_nonzero(self) -> Option<core::num::NonZero<$t>> {
439                core::num::NonZero::new(self)
440            }
441
442            #[inline]
443            fn nonzero_get(nz: core::num::NonZero<$t>) -> $t {
444                nz.get()
445            }
446        }
447        }
448
449        c0nst::c0nst! {
450        c0nst impl DivNonZero for $t {
451            type Output = $t;
452
453            #[inline]
454            fn div_nonzero(self, d: core::num::NonZero<$t>) -> $t {
455                self / d.get()
456            }
457
458            #[inline]
459            fn rem_nonzero(self, d: core::num::NonZero<$t>) -> $t {
460                self % d.get()
461            }
462        }
463        }
464    )+};
465}
466
467nonzero_bridge_impl!(u8, u16, u32, u64, u128, usize);
468
469// ─────────────────────────────── sign typestates ──────────────────────────
470
471/// Proof that a signed value is `>= 0`.
472#[repr(transparent)]
473#[derive(Clone, Copy, Debug, PartialEq, Eq)]
474pub struct NonNegative<T>(T);
475
476/// Proof that a signed value is `> 0`.
477#[repr(transparent)]
478#[derive(Clone, Copy, Debug, PartialEq, Eq)]
479pub struct Positive<T>(T);
480
481macro_rules! sign_typestate_impl {
482    ($($t:ty => $u:ty),+) => {$(
483        impl NonNegative<$t> {
484            /// `Some` iff `value >= 0`.
485            #[inline]
486            pub const fn new(value: $t) -> Option<Self> {
487                if value >= 0 { Some(NonNegative(value)) } else { None }
488            }
489            /// # Safety
490            /// `value` must be `>= 0`.
491            #[inline]
492            pub const unsafe fn new_unchecked(value: $t) -> Self { NonNegative(value) }
493            /// The proven value.
494            #[inline]
495            pub const fn get(self) -> $t { self.0 }
496            /// Zero-cost borrowed proof (repr(transparent) reinterpret).
497            #[inline]
498            pub fn from_ref(value: &$t) -> Option<&Self> {
499                if *value >= 0 {
500                    Some(unsafe { &*(value as *const $t as *const Self) })
501                } else { None }
502            }
503            /// Infallible cast to the unsigned counterpart — the value is `>= 0`
504            /// so the bit pattern is preserved; no `Option`, no panic.
505            #[inline]
506            pub const fn to_unsigned(self) -> $u { self.0 as $u }
507            /// `abs` is the identity on a non-negative value (branch-free).
508            #[inline]
509            pub const fn abs(self) -> $t { self.0 }
510            /// `isqrt` is total on a non-negative value (the inherent signed
511            /// `isqrt` would otherwise panic on negatives).
512            #[inline]
513            pub const fn isqrt(self) -> $t { self.0.isqrt() }
514            /// `NonNegative ⊂ NonMin` (`>= 0`, and `MIN < 0`, so `!= MIN`) —
515            /// narrows with no recheck so it can feed total `neg`/`abs`/division.
516            #[inline]
517            pub const fn into_nonmin(self) -> NonMin<$t> { NonMin(self.0) }
518        }
519
520        impl Positive<$t> {
521            /// `Some` iff `value > 0`.
522            #[inline]
523            pub const fn new(value: $t) -> Option<Self> {
524                if value > 0 { Some(Positive(value)) } else { None }
525            }
526            /// # Safety
527            /// `value` must be `> 0`.
528            #[inline]
529            pub const unsafe fn new_unchecked(value: $t) -> Self { Positive(value) }
530            /// The proven value.
531            #[inline]
532            pub const fn get(self) -> $t { self.0 }
533            /// Zero-cost borrowed proof (repr(transparent) reinterpret).
534            #[inline]
535            pub fn from_ref(value: &$t) -> Option<&Self> {
536                if *value > 0 {
537                    Some(unsafe { &*(value as *const $t as *const Self) })
538                } else { None }
539            }
540            /// Infallible cast to the unsigned counterpart.
541            #[inline]
542            pub const fn to_unsigned(self) -> $u { self.0 as $u }
543            /// `abs` is the identity on a positive value.
544            #[inline]
545            pub const fn abs(self) -> $t { self.0 }
546            /// `isqrt` is total on a positive value.
547            #[inline]
548            pub const fn isqrt(self) -> $t { self.0.isqrt() }
549
550            // ── refinement lattice (cheap const-fn narrowings) ──
551            /// `Positive ⊂ NonNegative`.
552            #[inline]
553            pub const fn into_nonnegative(self) -> NonNegative<$t> {
554                NonNegative(self.0)
555            }
556            /// `Positive ⊂ NonZero` — narrows to `core::num::NonZero` with no
557            /// recheck, so a `Positive` divisor can feed `DivNonZero` directly.
558            #[inline]
559            pub const fn into_nonzero(self) -> core::num::NonZero<$t> {
560                // SAFETY: value > 0, hence non-zero.
561                unsafe { core::num::NonZero::new_unchecked(self.0) }
562            }
563            /// `Positive ⊂ NonMin` (`> 0`, so `!= MIN`).
564            #[inline]
565            pub const fn into_nonmin(self) -> NonMin<$t> { NonMin(self.0) }
566        }
567
568        /// Checked construction by value; mirrors [`NonNegative::new`].
569        impl TryFrom<$t> for NonNegative<$t> {
570            type Error = TypestateError;
571            #[inline]
572            fn try_from(value: $t) -> Result<Self, TypestateError> {
573                Self::new(value).ok_or(TypestateError)
574            }
575        }
576
577        /// Checked construction by value; mirrors [`Positive::new`].
578        impl TryFrom<$t> for Positive<$t> {
579            type Error = TypestateError;
580            #[inline]
581            fn try_from(value: $t) -> Result<Self, TypestateError> {
582                Self::new(value).ok_or(TypestateError)
583            }
584        }
585    )+};
586}
587
588sign_typestate_impl!(
589    i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128, isize => usize
590);
591
592// ─────────────────────────────── NonMin (signed) ──────────────────────────
593
594/// Proof that a signed value is **not** `T::MIN`.
595///
596/// `neg`/`abs` overflow only at `MIN`, and the only signed-division overflow is
597/// `MIN / -1`. So with the dividend proven `!= MIN`, [`neg`](Self::neg) /
598/// [`abs`](Self::abs) and [`div_nonzero`](Self::div_nonzero) /
599/// [`rem_nonzero`](Self::rem_nonzero) by any non-zero divisor are total — the
600/// co-proof the unsigned [`DivNonZero`] doesn't need. [`Positive`] /
601/// [`NonNegative`] narrow here for free (`into_nonmin`).
602///
603/// ```
604/// use const_num_traits::NonMin;
605/// use core::num::NonZero;
606///
607/// let a = NonMin::<i32>::new(-7).unwrap();
608/// assert_eq!(a.abs(), 7);
609/// assert_eq!(a.neg(), 7);
610/// let d = NonZero::new(2).unwrap();
611/// assert_eq!(a.div_nonzero(d), -3); // -7 / 2, truncating
612/// assert_eq!(a.rem_nonzero(d), -1); // -7 % 2
613/// assert!(NonMin::<i32>::new(i32::MIN).is_none());
614/// ```
615#[repr(transparent)]
616#[derive(Clone, Copy, Debug, PartialEq, Eq)]
617pub struct NonMin<T>(T);
618
619macro_rules! nonmin_impl {
620    ($($t:ty),+) => {$(
621        impl NonMin<$t> {
622            /// `Some` iff `value != <$t>::MIN`.
623            #[inline]
624            pub const fn new(value: $t) -> Option<Self> {
625                if value != <$t>::MIN { Some(NonMin(value)) } else { None }
626            }
627            /// # Safety
628            /// `value` must not equal `<$t>::MIN` (i.e. `value != <$t>::MIN`) —
629            /// the invariant consumed by `neg`/`abs`/`div_nonzero`/`rem_nonzero`.
630            #[inline]
631            pub const unsafe fn new_unchecked(value: $t) -> Self { NonMin(value) }
632            /// The proven value.
633            #[inline]
634            pub const fn get(self) -> $t { self.0 }
635            /// Zero-cost borrowed proof (repr(transparent) reinterpret).
636            #[inline]
637            pub fn from_ref(value: &$t) -> Option<&Self> {
638                if *value != <$t>::MIN {
639                    Some(unsafe { &*(value as *const $t as *const Self) })
640                } else { None }
641            }
642            /// Total negation — `MIN` (the sole overflow) is excluded.
643            #[inline]
644            pub const fn neg(self) -> $t { -self.0 }
645            /// Total `abs` — `MIN` (the sole overflow) is excluded.
646            #[inline]
647            pub const fn abs(self) -> $t { self.0.abs() }
648            /// Total signed division by a non-zero divisor: the dividend is
649            /// proven `!= MIN`, so `MIN / -1` (the only overflow) can't occur,
650            /// and the divisor's niche rules out divide-by-zero.
651            #[inline]
652            pub const fn div_nonzero(self, d: core::num::NonZero<$t>) -> $t {
653                self.0 / d.get()
654            }
655            /// Total signed remainder by a non-zero divisor (same reasoning as
656            /// [`div_nonzero`](Self::div_nonzero); `MIN % -1` is excluded).
657            #[inline]
658            pub const fn rem_nonzero(self, d: core::num::NonZero<$t>) -> $t {
659                self.0 % d.get()
660            }
661        }
662
663        /// Checked construction by value; mirrors [`NonMin::new`].
664        impl TryFrom<$t> for NonMin<$t> {
665            type Error = TypestateError;
666            #[inline]
667            fn try_from(value: $t) -> Result<Self, TypestateError> {
668                Self::new(value).ok_or(TypestateError)
669            }
670        }
671    )+};
672}
673
674nonmin_impl!(i8, i16, i32, i64, i128, isize);
675
676// ─────────────────────────────────── Odd ──────────────────────────────────
677
678/// Proof that a value is odd.
679///
680/// A **bare** typestate: it carries the proof but has no consuming op in this
681/// crate. It ships here because that is where its predicate ([`Parity`]) lives.
682/// Note that `Odd` also implies non-zero — zero is even — so it doubles as a
683/// "non-zero and odd" proof without a separate `OddNonZero` type.
684#[repr(transparent)]
685#[derive(Clone, Copy, Debug, PartialEq, Eq)]
686pub struct Odd<T>(T);
687
688impl<T> Odd<T> {
689    /// # Safety
690    /// `value` must be odd.
691    #[inline]
692    pub const unsafe fn new_unchecked(value: T) -> Self {
693        Odd(value)
694    }
695
696    /// The proven-odd value.
697    #[inline]
698    pub fn get(self) -> T {
699        self.0
700    }
701}
702
703/// Borrows the proven-odd value without consuming the proof.
704impl<T> AsRef<T> for Odd<T> {
705    #[inline]
706    fn as_ref(&self) -> &T {
707        &self.0
708    }
709}
710
711c0nst::c0nst! {
712impl<T: Parity + Copy> Odd<T> {
713    /// `Some` iff `value` is odd. `const`-callable on nightly when
714    /// `T: [const] Parity`, so a const modulus can be proven odd in a `const`
715    /// block (no runtime panic path); plain on stable.
716    #[inline]
717    pub c0nst fn new(value: T) -> Option<Self>
718    where
719        T: [c0nst] Parity,
720    {
721        if value.is_odd() { Some(Odd(value)) } else { None }
722    }
723}
724}
725
726impl<T> Odd<T>
727where
728    for<'a> &'a T: Parity,
729{
730    /// Zero-cost borrowed proof — relies on the blanket `impl Parity for &T`
731    /// (for `Copy` `T`) or a non-`Copy` type's own `Parity for &Self`.
732    #[inline]
733    pub fn from_ref(value: &T) -> Option<&Self> {
734        if value.is_odd() {
735            Some(unsafe { &*(value as *const T as *const Odd<T>) })
736        } else {
737            None
738        }
739    }
740}
741
742/// Proof that a value is even — the parity sibling of [`Odd`].
743///
744/// A **bare** proof (no consuming op in this crate), provided for symmetry with
745/// [`Odd`] and to complete the masked-constructor set (`Even::new_ct`).
746#[repr(transparent)]
747#[derive(Clone, Copy, Debug, PartialEq, Eq)]
748pub struct Even<T>(T);
749
750impl<T> Even<T> {
751    /// # Safety
752    /// `value` must be even.
753    #[inline]
754    pub const unsafe fn new_unchecked(value: T) -> Self {
755        Even(value)
756    }
757
758    /// The proven-even value.
759    #[inline]
760    pub fn get(self) -> T {
761        self.0
762    }
763}
764
765/// Borrows the proven-even value without consuming the proof.
766impl<T> AsRef<T> for Even<T> {
767    #[inline]
768    fn as_ref(&self) -> &T {
769        &self.0
770    }
771}
772
773// Checked construction by value — the `core`-idiomatic fallible inverse of
774// `From`, mirroring `Odd::new` / `Even::new`. Per-primitive (not generic over
775// `Parity`): a generic `impl<T> TryFrom<T> for Odd<T>` collides with `core`'s
776// reflexive `TryFrom` blanket. Bignum carriers use the generic `new`/`from_ref`.
777macro_rules! parity_try_from {
778    ($($t:ty),+) => {$(
779        impl TryFrom<$t> for Odd<$t> {
780            type Error = TypestateError;
781            #[inline]
782            fn try_from(value: $t) -> Result<Self, TypestateError> {
783                Self::new(value).ok_or(TypestateError)
784            }
785        }
786        impl TryFrom<$t> for Even<$t> {
787            type Error = TypestateError;
788            #[inline]
789            fn try_from(value: $t) -> Result<Self, TypestateError> {
790                Self::new(value).ok_or(TypestateError)
791            }
792        }
793    )+};
794}
795parity_try_from!(
796    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
797);
798
799c0nst::c0nst! {
800impl<T: Parity + Copy> Even<T> {
801    /// `Some` iff `value` is even. `const`-callable on nightly when
802    /// `T: [const] Parity` (sibling of [`Odd::new`]); plain on stable.
803    #[inline]
804    pub c0nst fn new(value: T) -> Option<Self>
805    where
806        T: [c0nst] Parity,
807    {
808        if value.is_even() { Some(Even(value)) } else { None }
809    }
810}
811}
812
813impl<T> Even<T>
814where
815    for<'a> &'a T: Parity,
816{
817    /// Zero-cost borrowed proof.
818    #[inline]
819    pub fn from_ref(value: &T) -> Option<&Self> {
820        if value.is_even() {
821            Some(unsafe { &*(value as *const T as *const Even<T>) })
822        } else {
823            None
824        }
825    }
826}
827
828// ─────────────────────────────── Finite (float) ───────────────────────────
829
830/// Proof that a float is finite (neither `NaN` nor `±∞`).
831///
832/// Spent by a **total order**: `Finite<T>` implements [`Ord`]/[`Eq`], which bare
833/// `f32`/`f64` can't (`NaN` breaks reflexivity and trichotomy). With `NaN` gone,
834/// `partial_cmp` is always `Some`, so sorting / `min`/`max` / `BTreeMap` keys are
835/// total. `repr(transparent)`; no `new_ct` (floats are outside the CT model).
836///
837/// ```
838/// use const_num_traits::Finite;
839///
840/// let a = Finite::<f64>::new(1.0).unwrap();
841/// let b = Finite::<f64>::new(2.0).unwrap();
842/// assert!(a < b);
843/// assert_eq!(a.max(b).get(), 2.0);
844/// assert!(Finite::<f64>::new(f64::NAN).is_none());
845/// assert!(Finite::<f64>::new(f64::INFINITY).is_none());
846/// ```
847#[repr(transparent)]
848#[derive(Clone, Copy, Debug)]
849pub struct Finite<T>(T);
850
851macro_rules! finite_impl {
852    ($($t:ty => $exp_mask:expr),+) => {$(
853        impl Finite<$t> {
854            /// `Some` iff `value` is finite (not `NaN`, not `±∞`).
855            ///
856            /// `const fn`: finiteness is a bit test — the exponent field is
857            /// *not* all-ones — which sidesteps the non-`const` `is_finite`.
858            #[inline]
859            pub const fn new(value: $t) -> Option<Self> {
860                if (value.to_bits() & $exp_mask) != $exp_mask {
861                    Some(Finite(value))
862                } else {
863                    None
864                }
865            }
866            /// # Safety
867            /// `value` must be finite.
868            #[inline]
869            pub const unsafe fn new_unchecked(value: $t) -> Self { Finite(value) }
870            /// The proven-finite value.
871            #[inline]
872            pub const fn get(self) -> $t { self.0 }
873            /// Zero-cost borrowed proof (repr(transparent) reinterpret).
874            #[inline]
875            pub fn from_ref(value: &$t) -> Option<&Self> {
876                if (value.to_bits() & $exp_mask) != $exp_mask {
877                    Some(unsafe { &*(value as *const $t as *const Self) })
878                } else {
879                    None
880                }
881            }
882        }
883
884        /// Checked construction by value; mirrors [`Finite::new`]. The natural
885        /// boundary for rejecting `NaN`/`±∞` from external float input with `?`.
886        impl TryFrom<$t> for Finite<$t> {
887            type Error = TypestateError;
888            #[inline]
889            fn try_from(value: $t) -> Result<Self, TypestateError> {
890                Self::new(value).ok_or(TypestateError)
891            }
892        }
893
894        impl PartialEq for Finite<$t> {
895            #[inline]
896            fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
897        }
898        // With `NaN` excluded, `==` is reflexive, so `Eq` is sound.
899        impl Eq for Finite<$t> {}
900
901        impl PartialOrd for Finite<$t> {
902            #[inline]
903            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
904                Some(self.cmp(other))
905            }
906        }
907        impl Ord for Finite<$t> {
908            #[inline]
909            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
910                // Both operands are finite ⇒ `partial_cmp` is always `Some`;
911                // this `unwrap` is the proof being spent and can never panic.
912                self.0.partial_cmp(&other.0).unwrap()
913            }
914        }
915    )+};
916}
917
918finite_impl!(
919    f32 => 0x7F80_0000u32,
920    f64 => 0x7FF0_0000_0000_0000u64
921);
922
923// ──────────────── constant-time constructors (the `ct` feature) ────────────
924//
925// Masked (`subtle::CtOption`) counterparts of the plain branching constructors,
926// one per typestate family, built on the existing `ct` predicates. The plain
927// constructors are the documented Tier-B baseline; these keep the secret-derived
928// predicate masked. Plain (never-`const`) like the rest of `ops::ct`.
929
930#[cfg(feature = "ct")]
931pub use ct_constructors::CtNonZero;
932
933#[cfg(feature = "ct")]
934mod ct_constructors {
935    use super::{Even, HasNonZero, NonMin, NonNegative, Odd, Positive, PowerOfTwo};
936    use crate::ops::ct::{CtIsPowerOfTwo, CtIsZero, CtParity};
937    use subtle::{Choice, ConstantTimeEq, CtOption};
938
939    macro_rules! ct_pow2 {
940        ($($t:ty),+) => {$(
941            impl PowerOfTwo<$t> {
942                /// Constant-time [`new`](Self::new): a `CtOption` that is
943                /// `None`-masked when `value` is not a power of two.
944                #[inline]
945                pub fn new_ct(value: $t) -> CtOption<PowerOfTwo<$t>> {
946                    let choice = value.ct_is_power_of_two();
947                    // Branchless exponent: for a power of two `trailing_zeros`
948                    // IS the exponent. For `0` it returns BITS, and `BITS % BITS`
949                    // wraps to 0 (still `< BITS`), so the unchecked invariant
950                    // holds even though that value is masked out below.
951                    let exp = value.trailing_zeros() % <$t>::BITS;
952                    // SAFETY: `exp < BITS` always; meaningful only when `choice`
953                    // is set (value is a power of two), masked out otherwise.
954                    let proof = unsafe { PowerOfTwo::from_exp_unchecked(exp) };
955                    CtOption::new(proof, choice)
956                }
957            }
958        )+};
959    }
960    ct_pow2!(u8, u16, u32, u64, u128, usize);
961
962    macro_rules! ct_sign {
963        ($($t:ty),+) => {$(
964            impl NonNegative<$t> {
965                /// Constant-time [`new`](Self::new): `None`-masked when `value < 0`.
966                #[inline]
967                pub fn new_ct(value: $t) -> CtOption<NonNegative<$t>> {
968                    let neg = Choice::from(((value >> (<$t>::BITS - 1)) & 1) as u8);
969                    CtOption::new(NonNegative(value), !neg)
970                }
971            }
972            impl Positive<$t> {
973                /// Constant-time [`new`](Self::new): `None`-masked when `value <= 0`.
974                #[inline]
975                pub fn new_ct(value: $t) -> CtOption<Positive<$t>> {
976                    let neg = Choice::from(((value >> (<$t>::BITS - 1)) & 1) as u8);
977                    let zero = value.ct_is_zero();
978                    CtOption::new(Positive(value), !neg & !zero)
979                }
980            }
981        )+};
982    }
983    ct_sign!(i8, i16, i32, i64, i128, isize);
984
985    macro_rules! ct_nonmin {
986        ($($t:ty),+) => {$(
987            impl NonMin<$t> {
988                /// Constant-time [`new`](Self::new): `None`-masked when
989                /// `value == MIN`.
990                #[inline]
991                pub fn new_ct(value: $t) -> CtOption<NonMin<$t>> {
992                    let is_min = value.ct_eq(&<$t>::MIN);
993                    CtOption::new(NonMin(value), !is_min)
994                }
995            }
996        )+};
997    }
998    ct_nonmin!(i8, i16, i32, i64, i128, isize);
999
1000    impl<T: CtParity + Copy> Odd<T> {
1001        /// Constant-time [`new`](Self::new): `None`-masked when `value` is even.
1002        #[inline]
1003        pub fn new_ct(value: T) -> CtOption<Odd<T>> {
1004            let choice = value.ct_is_odd();
1005            CtOption::new(Odd(value), choice)
1006        }
1007    }
1008
1009    impl<T: CtParity + Copy> Even<T> {
1010        /// Constant-time [`new`](Self::new): `None`-masked when `value` is odd.
1011        #[inline]
1012        pub fn new_ct(value: T) -> CtOption<Even<T>> {
1013            let choice = value.ct_is_even();
1014            CtOption::new(Even(value), choice)
1015        }
1016    }
1017
1018    /// Constant-time bridge to [`core::num::NonZero`] — the masked counterpart
1019    /// of [`HasNonZero::into_nonzero`](super::HasNonZero::into_nonzero).
1020    pub trait CtNonZero: HasNonZero {
1021        /// `None`-masked when `self == 0`.
1022        fn into_nonzero_ct(self) -> CtOption<Self::NonZero>;
1023    }
1024
1025    macro_rules! ct_nonzero {
1026        ($($t:ty),+) => {$(
1027            impl CtNonZero for $t {
1028                #[inline]
1029                fn into_nonzero_ct(self) -> CtOption<core::num::NonZero<$t>> {
1030                    let zero = self.ct_is_zero();
1031                    // Force non-zero in the masked branch so new_unchecked stays
1032                    // sound (a `NonZero` holding 0 is UB even when masked out).
1033                    let safe = self | (zero.unwrap_u8() as $t);
1034                    let nz = unsafe { core::num::NonZero::new_unchecked(safe) };
1035                    CtOption::new(nz, !zero)
1036                }
1037            }
1038        )+};
1039    }
1040    ct_nonzero!(u8, u16, u32, u64, u128, usize);
1041}
1042
1043#[cfg(test)]
1044mod tests {
1045    use super::*;
1046
1047    #[test]
1048    fn construction_and_accessors() {
1049        assert!(PowerOfTwo::<u32>::new(0).is_none());
1050        assert!(PowerOfTwo::<u32>::new(3).is_none());
1051        assert!(PowerOfTwo::<u32>::new(6).is_none());
1052
1053        let p = PowerOfTwo::<u32>::new(64).unwrap();
1054        assert_eq!(p.exp(), 6);
1055        assert_eq!(p.get(), 64);
1056
1057        // edges: 2^0 = 1, and the largest power of two for the type
1058        assert_eq!(PowerOfTwo::<u8>::new(1).unwrap().exp(), 0);
1059        assert_eq!(PowerOfTwo::<u8>::new(128).unwrap().get(), 128);
1060
1061        // the generic safe constructor agrees with the per-primitive `new`
1062        assert_eq!(PowerOfTwo::<u32>::new_checked(64).unwrap().exp(), 6);
1063        assert!(PowerOfTwo::<u32>::new_checked(63).is_none());
1064        assert_eq!(PowerOfTwo::<u8>::new_checked(128).unwrap().get(), 128);
1065        assert_eq!(BitIndex::<u32>::new_checked(5).unwrap().get(), 5);
1066        assert!(BitIndex::<u32>::new_checked(32).is_none());
1067    }
1068
1069    #[test]
1070    fn consuming_ops() {
1071        let p = PowerOfTwo::<u32>::new(16).unwrap();
1072        assert_eq!(100u32.div_pow2(p), 100 / 16);
1073        assert_eq!(100u32.rem_pow2(p), 100 % 16);
1074        assert!(!100u32.is_multiple_of_pow2(p));
1075        assert!(96u32.is_multiple_of_pow2(p));
1076
1077        // 2^0 = 1: div is identity, rem is always 0
1078        let one = PowerOfTwo::<u64>::new(1).unwrap();
1079        assert_eq!(12345u64.div_pow2(one), 12345);
1080        assert_eq!(12345u64.rem_pow2(one), 0);
1081        assert!(12345u64.is_multiple_of_pow2(one));
1082    }
1083
1084    #[test]
1085    fn matches_naive_exhaustive_u8() {
1086        for k in 0..8u32 {
1087            let d = 1u8 << k;
1088            let p = PowerOfTwo::<u8>::new(d).unwrap();
1089            for x in 0..=u8::MAX {
1090                assert_eq!(x.div_pow2(p), x >> k);
1091                assert_eq!(x.rem_pow2(p), x & (d - 1));
1092                assert_eq!(x.is_multiple_of_pow2(p), x % d == 0);
1093            }
1094        }
1095    }
1096
1097    #[test]
1098    fn const_constructor_on_stable() {
1099        const P: Option<PowerOfTwo<u32>> = PowerOfTwo::<u32>::new(256);
1100        const GOT: u32 = match P {
1101            Some(p) => p.get(),
1102            None => 0,
1103        };
1104        assert_eq!(GOT, 256);
1105    }
1106
1107    #[test]
1108    fn next_multiple_of_pow2_works() {
1109        let p = PowerOfTwo::<u32>::new(8).unwrap();
1110        assert_eq!(5u32.next_multiple_of_pow2(p), 8);
1111        assert_eq!(8u32.next_multiple_of_pow2(p), 8);
1112        assert_eq!(9u32.next_multiple_of_pow2(p), 16);
1113        assert_eq!(0u32.next_multiple_of_pow2(p), 0);
1114        assert_eq!(100u32.checked_next_multiple_of_pow2(p), Some(104));
1115        assert_eq!(u32::MAX.checked_next_multiple_of_pow2(p), None);
1116    }
1117
1118    #[test]
1119    fn nonzero_bridge_and_div() {
1120        let d = 17u32.into_nonzero().unwrap();
1121        assert_eq!(u32::nonzero_get(d), 17);
1122        assert_eq!(100u32.div_nonzero(d), 100 / 17);
1123        assert_eq!(100u32.rem_nonzero(d), 100 % 17);
1124        assert!(0u32.into_nonzero().is_none());
1125    }
1126
1127    #[test]
1128    fn sign_typestates() {
1129        assert!(NonNegative::<i32>::new(-1).is_none());
1130        assert_eq!(NonNegative::<i32>::new(5).unwrap().to_unsigned(), 5u32);
1131        assert_eq!(NonNegative::<i32>::new(0).unwrap().abs(), 0);
1132        assert_eq!(NonNegative::<i32>::new(81).unwrap().isqrt(), 9);
1133
1134        assert!(Positive::<i32>::new(0).is_none());
1135        assert!(Positive::<i32>::new(-1).is_none());
1136        let p = Positive::<i32>::new(7).unwrap();
1137        assert_eq!(p.to_unsigned(), 7u32);
1138        assert_eq!(p.into_nonnegative().get(), 7);
1139        assert_eq!(p.into_nonzero().get(), 7);
1140
1141        // borrowed proofs
1142        let v = 5i32;
1143        assert!(NonNegative::<i32>::from_ref(&v).is_some());
1144        let n = -5i32;
1145        assert!(Positive::<i32>::from_ref(&n).is_none());
1146    }
1147
1148    #[test]
1149    fn odd_typestate() {
1150        assert!(Odd::<u32>::new(4).is_none());
1151        assert_eq!(Odd::<u32>::new(7).unwrap().get(), 7);
1152        assert!(Odd::<i32>::new(-3).is_some()); // -3 is odd
1153        // from_ref via the blanket `Parity for &T` (D1)
1154        let v = 9u32;
1155        assert!(Odd::from_ref(&v).is_some());
1156        let e = 8u32;
1157        assert!(Odd::from_ref(&e).is_none());
1158        // Even sibling
1159        assert!(Even::<u32>::new(4).is_some());
1160        assert!(Even::<u32>::new(7).is_none());
1161        assert_eq!(Even::<u32>::new(8).unwrap().get(), 8);
1162        assert!(Even::from_ref(&8u32).is_some());
1163        // borrow the proven value without consuming the proof
1164        let o = Odd::<u32>::new(7).unwrap();
1165        assert_eq!(*o.as_ref(), 7);
1166        let ev = Even::<u32>::new(8).unwrap();
1167        assert_eq!(*ev.as_ref(), 8);
1168    }
1169
1170    #[test]
1171    fn try_from_checked_constructors() {
1172        // Odd / Even (generic over Parity)
1173        assert_eq!(Odd::<u32>::try_from(7).map(|o| o.get()), Ok(7));
1174        assert_eq!(Odd::<u32>::try_from(8), Err(TypestateError));
1175        assert_eq!(Even::<u32>::try_from(8).map(|e| e.get()), Ok(8));
1176        // via the TryInto sugar (the point of using the std trait)
1177        let o: Odd<i32> = (-3i32).try_into().unwrap();
1178        assert_eq!(o.get(), -3);
1179        // sign types + NonMin (per-primitive)
1180        assert_eq!(NonNegative::<i32>::try_from(0).map(|n| n.get()), Ok(0));
1181        assert_eq!(NonNegative::<i32>::try_from(-1), Err(TypestateError));
1182        assert_eq!(Positive::<i32>::try_from(0), Err(TypestateError));
1183        assert_eq!(Positive::<i32>::try_from(5).map(|p| p.get()), Ok(5));
1184        assert_eq!(NonMin::<i8>::try_from(i8::MIN), Err(TypestateError));
1185        assert_eq!(NonMin::<i8>::try_from(5).map(|n| n.get()), Ok(5));
1186        // PowerOfTwo / BitIndex (no Debug/PartialEq on the proof — project first)
1187        assert_eq!(PowerOfTwo::<u32>::try_from(64).map(|p| p.exp()), Ok(6));
1188        assert!(PowerOfTwo::<u32>::try_from(63).is_err());
1189        assert_eq!(BitIndex::<u64>::try_from(40u32).map(|i| i.get()), Ok(40));
1190        assert!(BitIndex::<u8>::try_from(8u32).is_err());
1191        // Finite (derives Debug; manual PartialEq)
1192        let x: Finite<f64> = 1.5f64.try_into().unwrap();
1193        assert_eq!(x.get(), 1.5);
1194        assert_eq!(Finite::<f64>::try_from(f64::NAN), Err(TypestateError));
1195    }
1196
1197    #[test]
1198    fn bit_index_ops() {
1199        assert!(BitIndex::<u8>::new(8).is_none()); // == BITS
1200        assert!(BitIndex::<u8>::new(7).is_some());
1201        assert!(BitIndex::<u32>::new(32).is_none());
1202        let i = BitIndex::<u8>::new(3).unwrap();
1203        assert_eq!(i.get(), 3);
1204        assert_eq!(1u8.shl_index(i), 8);
1205        assert_eq!(0x80u8.shr_index(i), 0x10);
1206        // signed shifts too (arithmetic shr)
1207        let j = BitIndex::<i32>::new(2).unwrap();
1208        assert_eq!((-16i32).shr_index(j), -4);
1209        assert_eq!(3i32.shl_index(j), 12);
1210        // exhaustive vs raw shift for u8
1211        for n in 0..8u32 {
1212            let bi = BitIndex::<u8>::new(n).unwrap();
1213            for x in 0..=u8::MAX {
1214                assert_eq!(x.shl_index(bi), x << n);
1215                assert_eq!(x.shr_index(bi), x >> n);
1216            }
1217        }
1218    }
1219
1220    #[test]
1221    fn nonmin_ops() {
1222        assert!(NonMin::<i32>::new(i32::MIN).is_none());
1223        assert!(NonMin::<i8>::new(i8::MIN).is_none());
1224        let a = NonMin::<i32>::new(-7).unwrap();
1225        assert_eq!(a.get(), -7);
1226        assert_eq!(a.abs(), 7);
1227        assert_eq!(a.neg(), 7);
1228        let d = core::num::NonZero::new(2i32).unwrap();
1229        assert_eq!(a.div_nonzero(d), -7 / 2);
1230        assert_eq!(a.rem_nonzero(d), -7 % 2);
1231        // the dangerous case is now well-typed: MIN+1 / -1 is fine, MIN is unrepresentable
1232        let near = NonMin::<i32>::new(i32::MIN + 1).unwrap();
1233        let neg1 = core::num::NonZero::new(-1i32).unwrap();
1234        assert_eq!(near.div_nonzero(neg1), i32::MAX);
1235        // borrowed proof
1236        assert!(NonMin::<i32>::from_ref(&i32::MIN).is_none());
1237        assert!(NonMin::<i32>::from_ref(&5).is_some());
1238        // lattice: Positive / NonNegative narrow into NonMin for free
1239        let p = Positive::<i32>::new(9).unwrap();
1240        assert_eq!(p.into_nonmin().abs(), 9);
1241        let nn = NonNegative::<i32>::new(0).unwrap();
1242        assert_eq!(nn.into_nonmin().neg(), 0);
1243    }
1244
1245    #[test]
1246    fn finite_total_order() {
1247        assert!(Finite::<f64>::new(f64::NAN).is_none());
1248        assert!(Finite::<f64>::new(f64::INFINITY).is_none());
1249        assert!(Finite::<f64>::new(f64::NEG_INFINITY).is_none());
1250        assert!(Finite::<f32>::new(f32::NAN).is_none());
1251        assert!(Finite::<f64>::new(1.5).is_some());
1252        assert!(Finite::<f64>::new(0.0).is_some());
1253
1254        let a = Finite::<f64>::new(1.0).unwrap();
1255        let b = Finite::<f64>::new(2.0).unwrap();
1256        assert!(a < b);
1257        assert_eq!(a.max(b).get(), 2.0);
1258        assert_eq!(a.min(b).get(), 1.0);
1259        assert_eq!(a.cmp(&b), core::cmp::Ordering::Less);
1260        // -0.0 and 0.0 compare equal under the total order
1261        let z = Finite::<f64>::new(0.0).unwrap();
1262        let nz = Finite::<f64>::new(-0.0).unwrap();
1263        assert_eq!(z, nz);
1264        assert_eq!(z.cmp(&nz), core::cmp::Ordering::Equal);
1265        // sortability is the payoff
1266        let mut v = [b, a, z];
1267        v.sort();
1268        assert_eq!([v[0].get(), v[1].get(), v[2].get()], [0.0, 1.0, 2.0]);
1269    }
1270
1271    #[test]
1272    fn const_typestate_constructors_on_stable() {
1273        const I: Option<BitIndex<u32>> = BitIndex::<u32>::new(5);
1274        const NM: Option<NonMin<i32>> = NonMin::<i32>::new(-3);
1275        const F: Option<Finite<f64>> = Finite::<f64>::new(1.0);
1276        assert!(I.is_some() && NM.is_some() && F.is_some());
1277    }
1278
1279    #[test]
1280    #[cfg(feature = "ct")]
1281    fn ct_constructors_mask_correctly() {
1282        // PowerOfTwo
1283        assert!(bool::from(PowerOfTwo::<u32>::new_ct(16).is_some()));
1284        assert!(bool::from(PowerOfTwo::<u32>::new_ct(15).is_none()));
1285        assert!(bool::from(PowerOfTwo::<u32>::new_ct(0).is_none()));
1286        assert_eq!(PowerOfTwo::<u32>::new_ct(16).unwrap().get(), 16);
1287        // sign
1288        assert!(bool::from(NonNegative::<i32>::new_ct(0).is_some()));
1289        assert!(bool::from(NonNegative::<i32>::new_ct(-1).is_none()));
1290        assert!(bool::from(Positive::<i32>::new_ct(0).is_none()));
1291        assert!(bool::from(Positive::<i32>::new_ct(5).is_some()));
1292        // Odd / Even
1293        assert!(bool::from(Odd::<u32>::new_ct(7).is_some()));
1294        assert!(bool::from(Odd::<u32>::new_ct(8).is_none()));
1295        assert!(bool::from(Even::<u32>::new_ct(8).is_some()));
1296        assert!(bool::from(Even::<u32>::new_ct(7).is_none()));
1297        // NonZero bridge
1298        assert!(bool::from(17u32.into_nonzero_ct().is_some()));
1299        assert!(bool::from(0u32.into_nonzero_ct().is_none()));
1300        assert_eq!(17u32.into_nonzero_ct().unwrap().get(), 17);
1301        // NonMin
1302        assert!(bool::from(NonMin::<i32>::new_ct(5).is_some()));
1303        assert!(bool::from(NonMin::<i32>::new_ct(i32::MIN).is_none()));
1304        assert_eq!(NonMin::<i32>::new_ct(-9).unwrap().get(), -9);
1305    }
1306}