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}