1use crate::{
4 Bounded, Choice, ConstOne, Constants, CtAssign, CtEq, CtOption, CtSelect, Encoding, Int, Limb,
5 Mul, Odd, One, ToUnsigned, Uint, UintRef, Zero,
6};
7use core::{
8 fmt,
9 num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128},
10 ops::Deref,
11 ptr,
12};
13use ctutils::{CtAssignSlice, CtEqSlice};
14
15#[cfg(feature = "alloc")]
16use crate::BoxedUint;
17
18#[cfg(feature = "hybrid-array")]
19use crate::{ArrayEncoding, ByteArray};
20
21#[cfg(feature = "rand_core")]
22use {crate::Random, rand_core::TryRng};
23
24#[cfg(feature = "serde")]
25use serdect::serde::{
26 Deserialize, Deserializer, Serialize, Serializer,
27 de::{Error, Unexpected},
28};
29
30pub type NonZeroLimb = NonZero<Limb>;
32
33pub type NonZeroUint<const LIMBS: usize> = NonZero<Uint<LIMBS>>;
35
36pub type NonZeroUintRef = NonZero<UintRef>;
38
39pub type NonZeroInt<const LIMBS: usize> = NonZero<Int<LIMBS>>;
41
42#[cfg(feature = "alloc")]
44pub type NonZeroBoxedUint = NonZero<BoxedUint>;
45
46#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
48#[repr(transparent)]
49pub struct NonZero<T: ?Sized>(T);
50
51impl<T> NonZero<T> {
52 #[inline]
54 pub fn new(mut n: T) -> CtOption<Self>
55 where
56 T: Zero + One + CtAssign,
57 {
58 let is_zero = n.is_zero();
59
60 n.ct_assign(&T::one_like(&n), is_zero);
64 CtOption::new(Self(n), !is_zero)
65 }
66
67 #[inline]
76 #[must_use]
77 pub(crate) const fn new_unchecked(n: T) -> NonZero<T> {
78 Self(n)
79 }
80
81 #[inline]
83 pub fn get(self) -> T {
84 self.0
85 }
86
87 #[inline]
92 pub const fn get_copy(self) -> T
93 where
94 T: Copy,
95 {
96 self.0
97 }
98}
99
100impl<T: ?Sized> NonZero<T> {
101 #[inline]
103 pub const fn as_ref(&self) -> &T {
104 &self.0
105 }
106
107 #[inline]
116 #[must_use]
117 #[allow(unsafe_code)]
118 pub(crate) const fn new_ref_unchecked(refval: &T) -> &NonZero<T> {
119 unsafe { &*(ptr::from_ref(refval) as *const NonZero<T>) }
121 }
122}
123
124impl<T> NonZero<T>
125where
126 T: Bounded + ?Sized,
127{
128 pub const BITS: u32 = T::BITS;
130
131 pub const BYTES: usize = T::BYTES;
133}
134
135impl<T> NonZero<T>
136where
137 T: Constants,
138{
139 pub const ONE: Self = Self(T::ONE);
141
142 pub const MAX: Self = Self(T::MAX);
144}
145
146impl<T> NonZero<T>
147where
148 T: Zero + One + CtAssign + Encoding,
149{
150 pub fn from_be_bytes(bytes: T::Repr) -> CtOption<Self> {
152 Self::new(T::from_be_bytes(bytes))
153 }
154
155 pub fn from_le_bytes(bytes: T::Repr) -> CtOption<Self> {
157 Self::new(T::from_le_bytes(bytes))
158 }
159}
160
161impl<T> ConstOne for NonZero<T>
162where
163 T: ConstOne + One,
164{
165 const ONE: Self = Self(T::ONE);
166}
167
168impl<T> One for NonZero<T>
169where
170 T: One,
171 Self: CtEq,
172{
173 #[inline]
174 fn one() -> Self {
175 Self(T::one())
176 }
177}
178
179impl<T> num_traits::One for NonZero<T>
180where
181 T: One + Mul<T, Output = T>,
182{
183 #[inline]
184 fn one() -> Self {
185 Self(T::one())
186 }
187
188 fn is_one(&self) -> bool {
189 self.0.is_one().into()
190 }
191}
192
193impl<T> Mul<Self> for NonZero<T>
195where
196 T: Mul<T, Output = T>,
197{
198 type Output = Self;
199
200 fn mul(self, rhs: Self) -> Self {
201 Self(self.0 * rhs.0)
202 }
203}
204
205impl NonZero<Limb> {
206 #[inline]
216 #[must_use]
217 #[track_caller]
218 pub const fn new_unwrap(n: Limb) -> Self {
219 assert!(n.is_nonzero().to_bool_vartime(), "invalid value: zero");
220 Self(n)
221 }
222
223 #[must_use]
226 pub const fn from_u8(n: NonZeroU8) -> Self {
227 Self(Limb::from_u8(n.get()))
228 }
229
230 #[must_use]
233 pub const fn from_u16(n: NonZeroU16) -> Self {
234 Self(Limb::from_u16(n.get()))
235 }
236
237 #[must_use]
240 pub const fn from_u32(n: NonZeroU32) -> Self {
241 Self(Limb::from_u32(n.get()))
242 }
243
244 cpubits::cpubits! {
245 64 => {
246 #[must_use]
249 pub const fn from_u64(n: NonZeroU64) -> Self {
250 Self(Limb::from_u64(n.get()))
251 }
252 }
253 }
254}
255
256impl<const LIMBS: usize> NonZeroUint<LIMBS> {
257 #[inline]
266 #[track_caller]
267 #[must_use]
268 pub const fn new_unwrap(n: Uint<LIMBS>) -> Self {
269 assert!(n.is_nonzero().to_bool_vartime(), "invalid value: zero");
270 Self(n)
271 }
272
273 #[track_caller]
278 #[must_use]
279 pub const fn from_be_hex(hex: &str) -> Self {
280 Self::new_unwrap(Uint::from_be_hex(hex))
281 }
282
283 #[track_caller]
288 #[must_use]
289 pub const fn from_le_hex(hex: &str) -> Self {
290 Self::new_unwrap(Uint::from_le_hex(hex))
291 }
292
293 #[must_use]
296 pub const fn from_u8(n: NonZeroU8) -> Self {
297 Self(Uint::from_u8(n.get()))
298 }
299
300 #[must_use]
303 pub const fn from_u16(n: NonZeroU16) -> Self {
304 Self(Uint::from_u16(n.get()))
305 }
306
307 #[must_use]
310 pub const fn from_u32(n: NonZeroU32) -> Self {
311 Self(Uint::from_u32(n.get()))
312 }
313
314 #[must_use]
317 pub const fn from_u64(n: NonZeroU64) -> Self {
318 Self(Uint::from_u64(n.get()))
319 }
320
321 #[must_use]
324 pub const fn from_u128(n: NonZeroU128) -> Self {
325 Self(Uint::from_u128(n.get()))
326 }
327
328 #[inline]
330 #[must_use]
331 pub const fn as_uint_ref(&self) -> &NonZeroUintRef {
332 NonZero::new_ref_unchecked(self.0.as_uint_ref())
333 }
334}
335
336impl<const LIMBS: usize> AsRef<NonZeroUintRef> for NonZeroUint<LIMBS> {
337 fn as_ref(&self) -> &NonZeroUintRef {
338 self.as_uint_ref()
339 }
340}
341
342impl<const LIMBS: usize> NonZeroInt<LIMBS> {
343 #[inline]
353 #[must_use]
354 #[track_caller]
355 pub const fn new_unwrap(n: Int<LIMBS>) -> Self {
356 assert!(n.is_nonzero().to_bool_vartime(), "invalid value: zero");
357 Self(n)
358 }
359
360 #[must_use]
362 pub const fn abs_sign(&self) -> (NonZero<Uint<LIMBS>>, Choice) {
363 let (abs, sign) = self.0.abs_sign();
364 (NonZero(abs), sign)
366 }
367
368 #[must_use]
370 pub const fn abs(&self) -> NonZero<Uint<LIMBS>> {
371 self.abs_sign().0
372 }
373}
374
375#[cfg(feature = "alloc")]
376impl NonZeroBoxedUint {
377 #[inline]
379 #[must_use]
380 pub const fn as_uint_ref(&self) -> &NonZeroUintRef {
381 NonZero::new_ref_unchecked(self.0.as_uint_ref())
382 }
383}
384
385#[cfg(feature = "alloc")]
386impl AsRef<NonZeroUintRef> for NonZeroBoxedUint {
387 fn as_ref(&self) -> &NonZeroUintRef {
388 self.as_uint_ref()
389 }
390}
391
392#[cfg(feature = "alloc")]
393impl<T: AsRef<UintRef> + ?Sized> NonZero<T> {
394 pub(crate) fn lower_limb(&self) -> NonZeroLimb {
396 NonZero(self.0.as_ref().limbs[0])
397 }
398
399 pub(crate) fn to_boxed(&self) -> NonZeroBoxedUint {
401 NonZero(BoxedUint::from(self.0.as_ref()))
402 }
403}
404
405impl<T: ToUnsigned + ?Sized> NonZero<T> {
406 pub fn to_unsigned(&self) -> NonZero<T::Unsigned> {
408 NonZero(self.0.to_unsigned())
409 }
410}
411
412#[cfg(feature = "hybrid-array")]
413impl<T> NonZero<T>
414where
415 T: ArrayEncoding + Zero + One + CtAssign,
416{
417 pub fn from_be_byte_array(bytes: ByteArray<T>) -> CtOption<Self> {
419 Self::new(T::from_be_byte_array(bytes))
420 }
421
422 pub fn from_le_byte_array(bytes: ByteArray<T>) -> CtOption<Self> {
424 Self::new(T::from_le_byte_array(bytes))
425 }
426}
427
428impl<T: ?Sized> AsRef<T> for NonZero<T> {
429 fn as_ref(&self) -> &T {
430 &self.0
431 }
432}
433
434impl<T> CtAssign for NonZero<T>
435where
436 T: CtAssign,
437{
438 #[inline]
439 fn ct_assign(&mut self, other: &Self, choice: Choice) {
440 self.0.ct_assign(&other.0, choice);
441 }
442}
443impl<T> CtAssignSlice for NonZero<T> where T: CtAssign {}
444
445impl<T> CtEq for NonZero<T>
446where
447 T: CtEq + ?Sized,
448{
449 #[inline]
450 fn ct_eq(&self, other: &Self) -> Choice {
451 CtEq::ct_eq(&self.0, &other.0)
452 }
453}
454impl<T> CtEqSlice for NonZero<T> where T: CtEq {}
455
456impl<T> CtSelect for NonZero<T>
457where
458 T: CtSelect,
459{
460 #[inline]
461 fn ct_select(&self, other: &Self, choice: Choice) -> Self {
462 Self(self.0.ct_select(&other.0, choice))
463 }
464}
465
466impl<T> Default for NonZero<T>
467where
468 T: One,
469{
470 #[inline]
471 fn default() -> Self {
472 Self(T::one())
473 }
474}
475
476impl<T: ?Sized> Deref for NonZero<T> {
477 type Target = T;
478
479 fn deref(&self) -> &T {
480 &self.0
481 }
482}
483
484#[cfg(feature = "rand_core")]
485impl<T> Random for NonZero<T>
486where
487 T: Random + Zero + One + CtAssign,
488{
489 fn try_random_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
495 loop {
496 if let Some(result) = Self::new(T::try_random_from_rng(rng)?).into() {
497 break Ok(result);
498 }
499 }
500 }
501}
502
503impl From<NonZeroU8> for NonZero<Limb> {
504 fn from(integer: NonZeroU8) -> Self {
505 Self::from_u8(integer)
506 }
507}
508
509impl From<NonZeroU16> for NonZero<Limb> {
510 fn from(integer: NonZeroU16) -> Self {
511 Self::from_u16(integer)
512 }
513}
514
515impl From<NonZeroU32> for NonZero<Limb> {
516 fn from(integer: NonZeroU32) -> Self {
517 Self::from_u32(integer)
518 }
519}
520
521cpubits::cpubits! {
522 64 => {
523 impl From<NonZeroU64> for NonZero<Limb> {
524 fn from(integer: NonZeroU64) -> Self {
525 Self::from_u64(integer)
526 }
527 }
528 }
529}
530
531impl<const LIMBS: usize> From<NonZeroU8> for NonZero<Uint<LIMBS>> {
532 fn from(integer: NonZeroU8) -> Self {
533 Self::from_u8(integer)
534 }
535}
536
537impl<const LIMBS: usize> From<NonZeroU16> for NonZero<Uint<LIMBS>> {
538 fn from(integer: NonZeroU16) -> Self {
539 Self::from_u16(integer)
540 }
541}
542
543impl<const LIMBS: usize> From<NonZeroU32> for NonZero<Uint<LIMBS>> {
544 fn from(integer: NonZeroU32) -> Self {
545 Self::from_u32(integer)
546 }
547}
548
549impl<const LIMBS: usize> From<NonZeroU64> for NonZero<Uint<LIMBS>> {
550 fn from(integer: NonZeroU64) -> Self {
551 Self::from_u64(integer)
552 }
553}
554
555impl<const LIMBS: usize> From<NonZeroU128> for NonZero<Uint<LIMBS>> {
556 fn from(integer: NonZeroU128) -> Self {
557 Self::from_u128(integer)
558 }
559}
560
561impl<T> From<Odd<T>> for NonZero<T> {
562 fn from(odd: Odd<T>) -> NonZero<T> {
563 NonZero(odd.get())
564 }
565}
566
567impl<T> fmt::Display for NonZero<T>
568where
569 T: fmt::Display + ?Sized,
570{
571 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
572 fmt::Display::fmt(&self.0, f)
573 }
574}
575
576impl<T> fmt::Binary for NonZero<T>
577where
578 T: fmt::Binary + ?Sized,
579{
580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581 fmt::Binary::fmt(&self.0, f)
582 }
583}
584
585impl<T> fmt::Octal for NonZero<T>
586where
587 T: fmt::Octal + ?Sized,
588{
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 fmt::Octal::fmt(&self.0, f)
591 }
592}
593
594impl<T> fmt::LowerHex for NonZero<T>
595where
596 T: fmt::LowerHex + ?Sized,
597{
598 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599 fmt::LowerHex::fmt(&self.0, f)
600 }
601}
602
603impl<T> fmt::UpperHex for NonZero<T>
604where
605 T: fmt::UpperHex + ?Sized,
606{
607 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
608 fmt::UpperHex::fmt(&self.0, f)
609 }
610}
611
612#[cfg(feature = "serde")]
613impl<'de, T: Deserialize<'de> + Zero> Deserialize<'de> for NonZero<T> {
614 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
615 where
616 D: Deserializer<'de>,
617 {
618 let value: T = T::deserialize(deserializer)?;
619
620 if bool::from(value.is_zero()) {
621 Err(D::Error::invalid_value(
622 Unexpected::Other("zero"),
623 &"a non-zero value",
624 ))
625 } else {
626 Ok(Self(value))
627 }
628 }
629}
630
631#[cfg(feature = "serde")]
632impl<T: Serialize + Zero> Serialize for NonZero<T> {
633 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
634 where
635 S: Serializer,
636 {
637 self.0.serialize(serializer)
638 }
639}
640
641#[cfg(feature = "subtle")]
642impl<T> subtle::ConditionallySelectable for NonZero<T>
643where
644 T: Copy,
645 Self: CtSelect,
646{
647 fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
648 CtSelect::ct_select(a, b, choice.into())
649 }
650}
651
652#[cfg(feature = "subtle")]
653impl<T> subtle::ConstantTimeEq for NonZero<T>
654where
655 T: ?Sized,
656 Self: CtEq,
657{
658 #[inline]
659 fn ct_eq(&self, other: &Self) -> subtle::Choice {
660 CtEq::ct_eq(self, other).into()
661 }
662}
663
664#[cfg(feature = "zeroize")]
665impl<T: zeroize::Zeroize + One> zeroize::Zeroize for NonZero<T> {
666 fn zeroize(&mut self) {
667 self.0.zeroize();
668 self.0 = T::one_like(&self.0);
669 }
670}
671
672#[cfg(test)]
673mod tests {
674 use super::NonZero;
675 use crate::{I128, One, U128};
676 use hex_literal::hex;
677
678 #[cfg(all(feature = "alloc", feature = "zeroize"))]
679 use crate::BoxedUint;
680
681 #[cfg(feature = "zeroize")]
682 use zeroize::Zeroize;
683
684 #[test]
685 fn default() {
686 assert!(!NonZero::<U128>::default().is_zero().to_bool());
687 }
688
689 #[test]
690 fn from_be_bytes() {
691 assert_eq!(
692 NonZero::<U128>::from_be_bytes(hex!("00000000000000000000000000000001").into())
693 .unwrap(),
694 NonZero::<U128>::ONE
695 );
696
697 assert_eq!(
698 NonZero::<U128>::from_be_bytes(hex!("00000000000000000000000000000000").into())
699 .into_option(),
700 None
701 );
702 }
703
704 #[test]
705 fn from_le_bytes() {
706 assert_eq!(
707 NonZero::<U128>::from_le_bytes(hex!("01000000000000000000000000000000").into())
708 .unwrap(),
709 NonZero::<U128>::ONE
710 );
711
712 assert_eq!(
713 NonZero::<U128>::from_le_bytes(hex!("00000000000000000000000000000000").into())
714 .into_option(),
715 None
716 );
717 }
718
719 #[cfg(feature = "zeroize")]
720 #[test]
721 fn zeroize_preserves_invariant() {
722 let mut value = NonZero::new(U128::from(0x1234u64)).unwrap();
723
724 value.zeroize();
725
726 assert_eq!(*value.as_ref(), U128::ONE);
727 }
728
729 #[cfg(all(feature = "alloc", feature = "zeroize"))]
730 #[test]
731 fn boxed_zeroize_preserves_invariant_and_precision() {
732 let mut value =
733 NonZero::new(BoxedUint::from_be_slice(&[0x12, 0x34], 128).unwrap()).unwrap();
734
735 value.zeroize();
736
737 assert_eq!(value.as_ref(), &BoxedUint::one_with_precision(128));
738 assert_eq!(value.bits_precision(), 128);
739 }
740
741 #[test]
742 fn from_be_hex_when_nonzero() {
743 assert_eq!(
744 NonZero::<U128>::from_be_hex("00000000000000000000000000000001"),
745 NonZero::<U128>::ONE
746 );
747 }
748
749 #[test]
750 #[should_panic]
751 fn from_be_hex_when_zero() {
752 let _ = NonZero::<U128>::from_be_hex("00000000000000000000000000000000");
753 }
754
755 #[test]
756 fn from_le_hex_when_nonzero() {
757 assert_eq!(
758 NonZero::<U128>::from_le_hex("01000000000000000000000000000000"),
759 NonZero::<U128>::ONE
760 );
761 }
762
763 #[test]
764 #[should_panic]
765 fn from_le_hex_when_zero() {
766 let _ = NonZero::<U128>::from_le_hex("00000000000000000000000000000000");
767 }
768
769 #[test]
770 fn int_abs_sign() {
771 let x = I128::from(-55).to_nz().unwrap();
772 let (abs, sgn) = x.abs_sign();
773 assert_eq!(abs, U128::from(55u32).to_nz().unwrap());
774 assert!(sgn.to_bool());
775 }
776
777 #[test]
778 fn one() {
779 assert_eq!(
780 NonZero::<U128>::from_le_bytes(hex!("01000000000000000000000000000000").into())
781 .unwrap(),
782 NonZero::<U128>::one()
783 );
784 }
785
786 #[cfg(feature = "hybrid-array")]
787 #[test]
788 fn from_le_byte_array() {
789 assert_eq!(
790 NonZero::<U128>::from_le_byte_array(hex!("01000000000000000000000000000000").into())
791 .unwrap(),
792 NonZero::<U128>::ONE
793 );
794 }
795}