gprimitives/
nonzero_u256.rs

1// This file is part of Gear.
2
3// Copyright (C) 2021-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Definitions of integer that is known not to equal zero.
20
21use crate::U256;
22use core::{
23    cmp::Ordering,
24    fmt,
25    hash::{Hash, Hasher},
26    mem::transmute,
27    num::NonZero,
28};
29#[cfg(feature = "codec")]
30use scale_info::{
31    TypeInfo,
32    prelude::vec::Vec,
33    scale::{Decode, Encode, EncodeLike, Error, Input, Output},
34};
35
36/// A value that is known not to equal zero.
37#[derive(Clone, Copy)]
38#[cfg_attr(feature = "codec", derive(TypeInfo))]
39#[repr(transparent)]
40pub struct NonZeroU256(U256);
41
42macro_rules! impl_nonzero_fmt {
43    ($Trait:ident) => {
44        impl fmt::$Trait for NonZeroU256 {
45            #[inline]
46            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47                self.get().fmt(f)
48            }
49        }
50    };
51}
52
53impl_nonzero_fmt!(Debug);
54impl_nonzero_fmt!(Display);
55impl_nonzero_fmt!(LowerHex);
56impl_nonzero_fmt!(UpperHex);
57
58impl PartialEq for NonZeroU256 {
59    #[inline]
60    fn eq(&self, other: &Self) -> bool {
61        self.get() == other.get()
62    }
63}
64
65impl Eq for NonZeroU256 {}
66
67impl PartialOrd for NonZeroU256 {
68    #[inline]
69    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
70        Some(self.cmp(other))
71    }
72
73    #[inline]
74    fn lt(&self, other: &Self) -> bool {
75        self.get() < other.get()
76    }
77
78    #[inline]
79    fn le(&self, other: &Self) -> bool {
80        self.get() <= other.get()
81    }
82
83    #[inline]
84    fn gt(&self, other: &Self) -> bool {
85        self.get() > other.get()
86    }
87
88    #[inline]
89    fn ge(&self, other: &Self) -> bool {
90        self.get() >= other.get()
91    }
92}
93
94impl Ord for NonZeroU256 {
95    #[inline]
96    fn cmp(&self, other: &Self) -> Ordering {
97        self.get().cmp(&other.get())
98    }
99
100    #[inline]
101    fn max(self, other: Self) -> Self {
102        // SAFETY: The maximum of two non-zero values is still non-zero.
103        Self(self.get().max(other.get()))
104    }
105
106    #[inline]
107    fn min(self, other: Self) -> Self {
108        // SAFETY: The minimum of two non-zero values is still non-zero.
109        Self(self.get().min(other.get()))
110    }
111
112    #[inline]
113    fn clamp(self, min: Self, max: Self) -> Self {
114        // SAFETY: A non-zero value clamped between two non-zero values is still non-zero.
115        Self(self.get().clamp(min.get(), max.get()))
116    }
117}
118
119impl Hash for NonZeroU256 {
120    #[inline]
121    fn hash<H>(&self, state: &mut H)
122    where
123        H: Hasher,
124    {
125        self.get().hash(state)
126    }
127}
128
129/// Get a reference to the underlying little-endian words.
130impl AsRef<[u64]> for NonZeroU256 {
131    #[inline]
132    fn as_ref(&self) -> &[u64] {
133        self.0.as_ref()
134    }
135}
136
137impl<'a> From<&'a NonZeroU256> for NonZeroU256 {
138    fn from(x: &'a NonZeroU256) -> NonZeroU256 {
139        *x
140    }
141}
142
143impl NonZeroU256 {
144    /// The smallest value that can be represented by this non-zero
145    pub const MIN: NonZeroU256 = unsafe { NonZeroU256::new_unchecked(U256::one()) };
146    /// The largest value that can be represented by this non-zero
147    pub const MAX: NonZeroU256 = unsafe { NonZeroU256::new_unchecked(U256::MAX) };
148
149    /// Creates a non-zero if the given value is not zero.
150    #[must_use]
151    #[inline]
152    pub const fn new(n: U256) -> Option<Self> {
153        if n.is_zero() { None } else { Some(Self(n)) }
154    }
155
156    /// Creates a non-zero without checking whether the value is non-zero.
157    /// This results in undefined behaviour if the value is zero.
158    ///
159    /// # Safety
160    ///
161    /// The value must not be zero.
162    #[must_use]
163    #[inline]
164    pub const unsafe fn new_unchecked(n: U256) -> Self {
165        // SAFETY: The caller guarantees that `n` is non-zero
166        unsafe { transmute(n) }
167    }
168
169    /// Returns the contained value as a primitive type.
170    #[inline]
171    pub const fn get(self) -> U256 {
172        // FIXME: This can be changed to simply `self.0` once LLVM supports `!range` metadata
173        // for function arguments: https://github.com/llvm/llvm-project/issues/76628
174        //
175        // Rustc can set range metadata only if it loads `self` from
176        // memory somewhere. If the value of `self` was from by-value argument
177        // of some not-inlined function, LLVM don't have range metadata
178        // to understand that the value cannot be zero.
179        match Self::new(self.0) {
180            Some(Self(n)) => n,
181            None => {
182                // SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable.
183                unreachable!()
184            }
185        }
186    }
187
188    /// Adds an unsigned integer to a non-zero value.
189    /// Checks for overflow and returns [`None`] on overflow.
190    /// As a consequence, the result cannot wrap to zero.
191    #[inline]
192    pub fn checked_add(self, other: U256) -> Option<Self> {
193        // SAFETY:
194        // - `checked_add` returns `None` on overflow
195        // - `self` is non-zero
196        // - the only way to get zero from an addition without overflow is for both
197        //   sides to be zero
198        //
199        // So the result cannot be zero.
200        self.get()
201            .checked_add(other)
202            .map(|result| unsafe { Self::new_unchecked(result) })
203    }
204
205    /// Adds an unsigned integer to a non-zero value.
206    #[inline]
207    pub fn saturating_add(self, other: U256) -> Self {
208        // SAFETY:
209        // - `saturating_add` returns `u*::MAX` on overflow, which is non-zero
210        // - `self` is non-zero
211        // - the only way to get zero from an addition without overflow is for both
212        //   sides to be zero
213        //
214        // So the result cannot be zero.
215        unsafe { Self::new_unchecked(self.get().saturating_add(other)) }
216    }
217
218    /// Addition which overflows and returns a flag if it does.
219    #[inline(always)]
220    pub fn overflowing_add(self, other: U256) -> (Self, bool) {
221        let result = self.get().overflowing_add(other);
222        if result.0.is_zero() {
223            (Self::MIN, true)
224        } else {
225            unsafe { (Self::new_unchecked(result.0), result.1) }
226        }
227    }
228
229    /// Checked subtraction. Returns `None` if overflow occurred.
230    pub fn checked_sub(self, other: U256) -> Option<Self> {
231        match self.get().overflowing_sub(other) {
232            (_, true) => None,
233            (val, _) => Self::new(val),
234        }
235    }
236
237    /// Subtraction which saturates at MIN.
238    pub fn saturating_sub(self, other: U256) -> Self {
239        match self.get().overflowing_sub(other) {
240            (_, true) => Self::MIN,
241            (val, false) => Self::new(val).unwrap_or(Self::MIN),
242        }
243    }
244
245    /// Subtraction which underflows and returns a flag if it does.
246    #[inline(always)]
247    pub fn overflowing_sub(self, other: U256) -> (Self, bool) {
248        let result = self.get().overflowing_sub(other);
249        if result.0.is_zero() {
250            (Self::MAX, true)
251        } else {
252            unsafe { (Self::new_unchecked(result.0), result.1) }
253        }
254    }
255
256    /// Multiplies two non-zero integers together.
257    /// Checks for overflow and returns [`None`] on overflow.
258    /// As a consequence, the result cannot wrap to zero.
259    #[inline]
260    pub fn checked_mul(self, other: Self) -> Option<Self> {
261        // SAFETY:
262        // - `checked_mul` returns `None` on overflow
263        // - `self` and `other` are non-zero
264        // - the only way to get zero from a multiplication without overflow is for one
265        //   of the sides to be zero
266        //
267        // So the result cannot be zero.
268        self.get()
269            .checked_mul(other.get())
270            .map(|result| unsafe { Self::new_unchecked(result) })
271    }
272
273    /// Multiplies two non-zero integers together.
274    #[inline]
275    pub fn saturating_mul(self, other: Self) -> Self {
276        // SAFETY:
277        // - `saturating_mul` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow,
278        //   all of which are non-zero
279        // - `self` and `other` are non-zero
280        // - the only way to get zero from a multiplication without overflow is for one
281        //   of the sides to be zero
282        //
283        // So the result cannot be zero.
284        unsafe { Self::new_unchecked(self.get().saturating_mul(other.get())) }
285    }
286
287    /// Multiply with overflow, returning a flag if it does.
288    #[inline(always)]
289    pub fn overflowing_mul(self, other: Self) -> (Self, bool) {
290        let result = self.get().overflowing_mul(other.get());
291        if result.0.is_zero() {
292            (Self::MAX, true)
293        } else {
294            unsafe { (Self::new_unchecked(result.0), result.1) }
295        }
296    }
297
298    /// Raises non-zero value to an integer power.
299    /// Checks for overflow and returns [`None`] on overflow.
300    /// As a consequence, the result cannot wrap to zero.
301    #[inline]
302    pub fn checked_pow(self, other: U256) -> Option<Self> {
303        // SAFETY:
304        // - `checked_pow` returns `None` on overflow/underflow
305        // - `self` is non-zero
306        // - the only way to get zero from an exponentiation without overflow is
307        //   for base to be zero
308        //
309        // So the result cannot be zero.
310        self.get()
311            .checked_pow(other)
312            .map(|result| unsafe { Self::new_unchecked(result) })
313    }
314
315    /// Raise non-zero value to an integer power.
316    #[inline]
317    pub fn overflowing_pow(self, other: U256) -> (Self, bool) {
318        let result = self.get().overflowing_pow(other);
319        if result.0.is_zero() {
320            (Self::MAX, true)
321        } else {
322            unsafe { (Self::new_unchecked(result.0), result.1) }
323        }
324    }
325
326    /// Fast exponentiation by squaring
327    /// <https://en.wikipedia.org/wiki/Exponentiation_by_squaring>
328    ///
329    /// # Panics
330    ///
331    /// Panics if the result overflows the type.
332    #[inline]
333    pub fn pow(self, other: U256) -> Self {
334        // SAFETY:
335        // - `pow` panics on overflow/underflow
336        // - `self` is non-zero
337        // - the only way to get zero from an exponentiation without overflow is
338        //   for base to be zero
339        //
340        // So the result cannot be zero.
341        unsafe { Self::new_unchecked(self.get().pow(other)) }
342    }
343}
344
345impl From<NonZeroU256> for U256 {
346    #[inline]
347    fn from(nonzero: NonZeroU256) -> Self {
348        // Call `get` method to keep range information.
349        nonzero.get()
350    }
351}
352
353macro_rules! impl_map_from {
354    ($from:ty) => {
355        impl From<$from> for NonZeroU256 {
356            fn from(value: $from) -> Self {
357                unsafe { Self::new_unchecked(U256::from(value.get())) }
358            }
359        }
360    };
361}
362
363impl_map_from!(NonZero<u8>);
364impl_map_from!(NonZero<u16>);
365impl_map_from!(NonZero<u32>);
366impl_map_from!(NonZero<u64>);
367impl_map_from!(NonZero<u128>);
368
369macro_rules! impl_try_from {
370    ($from:ty) => {
371        impl TryFrom<$from> for NonZeroU256 {
372            type Error = &'static str;
373
374            #[inline]
375            fn try_from(value: $from) -> Result<NonZeroU256, &'static str> {
376                NonZeroU256::new(U256::from(value)).ok_or("integer value is zero")
377            }
378        }
379    };
380}
381
382impl_try_from!(u8);
383impl_try_from!(u16);
384impl_try_from!(u32);
385impl_try_from!(u64);
386impl_try_from!(u128);
387
388#[doc(hidden)]
389macro_rules! panic_on_overflow {
390    ($name: expr) => {
391        if $name {
392            panic!("arithmetic operation overflow")
393        }
394    };
395}
396
397impl<T> core::ops::Add<T> for NonZeroU256
398where
399    T: Into<U256>,
400{
401    type Output = NonZeroU256;
402
403    fn add(self, other: T) -> NonZeroU256 {
404        let (result, overflow) = self.overflowing_add(other.into());
405        panic_on_overflow!(overflow);
406        result
407    }
408}
409
410impl<T> core::ops::Add<T> for &NonZeroU256
411where
412    T: Into<U256>,
413{
414    type Output = NonZeroU256;
415
416    fn add(self, other: T) -> NonZeroU256 {
417        *self + other
418    }
419}
420
421impl<T> core::ops::AddAssign<T> for NonZeroU256
422where
423    T: Into<U256>,
424{
425    fn add_assign(&mut self, other: T) {
426        let (result, overflow) = self.overflowing_add(other.into());
427        panic_on_overflow!(overflow);
428        *self = result
429    }
430}
431
432impl<T> core::ops::Sub<T> for NonZeroU256
433where
434    T: Into<U256>,
435{
436    type Output = NonZeroU256;
437
438    #[inline]
439    fn sub(self, other: T) -> NonZeroU256 {
440        let (result, overflow) = self.overflowing_sub(other.into());
441        panic_on_overflow!(overflow);
442        result
443    }
444}
445
446impl<T> core::ops::Sub<T> for &NonZeroU256
447where
448    T: Into<U256>,
449{
450    type Output = NonZeroU256;
451
452    fn sub(self, other: T) -> NonZeroU256 {
453        *self - other
454    }
455}
456
457impl<T> core::ops::SubAssign<T> for NonZeroU256
458where
459    T: Into<U256>,
460{
461    fn sub_assign(&mut self, other: T) {
462        let (result, overflow) = self.overflowing_sub(other.into());
463        panic_on_overflow!(overflow);
464        *self = result
465    }
466}
467
468impl core::ops::Mul<NonZeroU256> for NonZeroU256 {
469    type Output = NonZeroU256;
470
471    fn mul(self, other: NonZeroU256) -> NonZeroU256 {
472        let (result, overflow) = self.overflowing_mul(other);
473        panic_on_overflow!(overflow);
474        result
475    }
476}
477
478impl<'a> core::ops::Mul<&'a NonZeroU256> for NonZeroU256 {
479    type Output = NonZeroU256;
480
481    fn mul(self, other: &'a NonZeroU256) -> NonZeroU256 {
482        let (result, overflow) = self.overflowing_mul(*other);
483        panic_on_overflow!(overflow);
484        result
485    }
486}
487
488impl<'a> core::ops::Mul<&'a NonZeroU256> for &'a NonZeroU256 {
489    type Output = NonZeroU256;
490
491    fn mul(self, other: &'a NonZeroU256) -> NonZeroU256 {
492        let (result, overflow) = self.overflowing_mul(*other);
493        panic_on_overflow!(overflow);
494        result
495    }
496}
497
498impl core::ops::Mul<NonZeroU256> for &NonZeroU256 {
499    type Output = NonZeroU256;
500
501    fn mul(self, other: NonZeroU256) -> NonZeroU256 {
502        let (result, overflow) = self.overflowing_mul(other);
503        panic_on_overflow!(overflow);
504        result
505    }
506}
507
508impl core::ops::MulAssign<NonZeroU256> for NonZeroU256 {
509    fn mul_assign(&mut self, other: NonZeroU256) {
510        let result = *self * other;
511        *self = result
512    }
513}
514
515#[cfg(feature = "codec")]
516macro_rules! impl_for_non_zero {
517    ( $( $name:ty ),* $(,)? ) => {
518        $(
519            impl Encode for $name {
520                fn size_hint(&self) -> usize {
521                    self.get().size_hint()
522                }
523
524                fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
525                    self.get().encode_to(dest)
526                }
527
528                fn encode(&self) -> Vec<u8> {
529                    self.get().encode()
530                }
531
532                fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
533                    self.get().using_encoded(f)
534                }
535            }
536
537            impl EncodeLike for $name {}
538
539            impl Decode for $name {
540                fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
541                    Self::new(Decode::decode(input)?)
542                        .ok_or_else(|| Error::from("cannot create non-zero number from 0"))
543                }
544            }
545        )*
546    }
547}
548
549#[cfg(feature = "codec")]
550impl_for_non_zero!(NonZeroU256);
551
552#[cfg(test)]
553mod tests {
554    extern crate alloc;
555
556    use super::*;
557    use alloc::format;
558
559    #[test]
560    fn nonzero_u256_from_to_u256() {
561        let u256 = U256::from(42u64);
562        let nz = NonZeroU256::new(u256).unwrap();
563        assert_eq!(u256, nz.into());
564        assert_eq!(format!("{u256}"), format!("{nz}"));
565        assert_eq!(format!("{u256:?}"), format!("{nz:?}"));
566    }
567
568    #[test]
569    fn nonzero_u256_from_nz64() {
570        let nzu64 = NonZero::<u64>::new(42u64).unwrap();
571        let nz: NonZeroU256 = nzu64.into();
572        assert_eq!(U256::from(nzu64.get()), nz.get());
573    }
574
575    #[test]
576    fn nonzero_u256_from_zero() {
577        let zero = 0u64;
578        let opt = NonZeroU256::new(U256::from(zero));
579        assert_eq!(None, opt);
580        let res = TryInto::<NonZeroU256>::try_into(zero);
581        assert_eq!(Err("integer value is zero"), res);
582    }
583
584    #[test]
585    fn nonzero_u256_overflowing_add() {
586        let nzu256 = NonZeroU256::MAX;
587        let result = nzu256.overflowing_add(1u64.into());
588        assert_eq!((NonZeroU256::MIN, true), result);
589    }
590
591    #[test]
592    fn nonzero_u256_overflowing_sub() {
593        let nzu256 = NonZeroU256::MIN;
594        let result = nzu256.overflowing_sub(1u64.into());
595        assert_eq!((NonZeroU256::MAX, true), result);
596    }
597
598    #[test]
599    fn nonzero_u256_overflowing_mul() {
600        let mut nzu256 = NonZeroU256::from(NonZero::<u128>::MAX);
601        nzu256 += 1;
602        let result = nzu256.overflowing_mul(nzu256);
603        assert_eq!((NonZeroU256::MAX, true), result);
604    }
605
606    #[test]
607    fn nonzero_u256_overflowing_pow() {
608        let mut nzu256 = NonZeroU256::from(NonZero::<u128>::MAX);
609        nzu256 += 1;
610        let result: (NonZeroU256, bool) = nzu256.overflowing_pow(2.into());
611        assert_eq!((NonZeroU256::MAX, true), result);
612    }
613}