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    prelude::vec::Vec,
32    scale::{Decode, Encode, EncodeLike, Error, Input, Output},
33    TypeInfo,
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() {
154            None
155        } else {
156            Some(Self(n))
157        }
158    }
159
160    /// Creates a non-zero without checking whether the value is non-zero.
161    /// This results in undefined behaviour if the value is zero.
162    ///
163    /// # Safety
164    ///
165    /// The value must not be zero.
166    #[must_use]
167    #[inline]
168    pub const unsafe fn new_unchecked(n: U256) -> Self {
169        // SAFETY: The caller guarantees that `n` is non-zero
170        unsafe { transmute(n) }
171    }
172
173    /// Returns the contained value as a primitive type.
174    #[inline]
175    pub const fn get(self) -> U256 {
176        // FIXME: This can be changed to simply `self.0` once LLVM supports `!range` metadata
177        // for function arguments: https://github.com/llvm/llvm-project/issues/76628
178        //
179        // Rustc can set range metadata only if it loads `self` from
180        // memory somewhere. If the value of `self` was from by-value argument
181        // of some not-inlined function, LLVM don't have range metadata
182        // to understand that the value cannot be zero.
183        match Self::new(self.0) {
184            Some(Self(n)) => n,
185            None => {
186                // SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable.
187                unreachable!()
188            }
189        }
190    }
191
192    /// Adds an unsigned integer to a non-zero value.
193    /// Checks for overflow and returns [`None`] on overflow.
194    /// As a consequence, the result cannot wrap to zero.
195    #[inline]
196    pub fn checked_add(self, other: U256) -> Option<Self> {
197        // SAFETY:
198        // - `checked_add` returns `None` on overflow
199        // - `self` is non-zero
200        // - the only way to get zero from an addition without overflow is for both
201        //   sides to be zero
202        //
203        // So the result cannot be zero.
204        self.get()
205            .checked_add(other)
206            .map(|result| unsafe { Self::new_unchecked(result) })
207    }
208
209    /// Adds an unsigned integer to a non-zero value.
210    #[inline]
211    pub fn saturating_add(self, other: U256) -> Self {
212        // SAFETY:
213        // - `saturating_add` returns `u*::MAX` on overflow, which is non-zero
214        // - `self` is non-zero
215        // - the only way to get zero from an addition without overflow is for both
216        //   sides to be zero
217        //
218        // So the result cannot be zero.
219        unsafe { Self::new_unchecked(self.get().saturating_add(other)) }
220    }
221
222    /// Addition which overflows and returns a flag if it does.
223    #[inline(always)]
224    pub fn overflowing_add(self, other: U256) -> (Self, bool) {
225        let result = self.get().overflowing_add(other);
226        if result.0.is_zero() {
227            (Self::MIN, true)
228        } else {
229            unsafe { (Self::new_unchecked(result.0), result.1) }
230        }
231    }
232
233    /// Checked subtraction. Returns `None` if overflow occurred.
234    pub fn checked_sub(self, other: U256) -> Option<Self> {
235        match self.get().overflowing_sub(other) {
236            (_, true) => None,
237            (val, _) => Self::new(val),
238        }
239    }
240
241    /// Subtraction which saturates at MIN.
242    pub fn saturating_sub(self, other: U256) -> Self {
243        match self.get().overflowing_sub(other) {
244            (_, true) => Self::MIN,
245            (val, false) => Self::new(val).unwrap_or(Self::MIN),
246        }
247    }
248
249    /// Subtraction which underflows and returns a flag if it does.
250    #[inline(always)]
251    pub fn overflowing_sub(self, other: U256) -> (Self, bool) {
252        let result = self.get().overflowing_sub(other);
253        if result.0.is_zero() {
254            (Self::MAX, true)
255        } else {
256            unsafe { (Self::new_unchecked(result.0), result.1) }
257        }
258    }
259
260    /// Multiplies two non-zero integers together.
261    /// Checks for overflow and returns [`None`] on overflow.
262    /// As a consequence, the result cannot wrap to zero.
263    #[inline]
264    pub fn checked_mul(self, other: Self) -> Option<Self> {
265        // SAFETY:
266        // - `checked_mul` returns `None` on overflow
267        // - `self` and `other` are non-zero
268        // - the only way to get zero from a multiplication without overflow is for one
269        //   of the sides to be zero
270        //
271        // So the result cannot be zero.
272        self.get()
273            .checked_mul(other.get())
274            .map(|result| unsafe { Self::new_unchecked(result) })
275    }
276
277    /// Multiplies two non-zero integers together.
278    #[inline]
279    pub fn saturating_mul(self, other: Self) -> Self {
280        // SAFETY:
281        // - `saturating_mul` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow,
282        //   all of which are non-zero
283        // - `self` and `other` are non-zero
284        // - the only way to get zero from a multiplication without overflow is for one
285        //   of the sides to be zero
286        //
287        // So the result cannot be zero.
288        unsafe { Self::new_unchecked(self.get().saturating_mul(other.get())) }
289    }
290
291    /// Multiply with overflow, returning a flag if it does.
292    #[inline(always)]
293    pub fn overflowing_mul(self, other: Self) -> (Self, bool) {
294        let result = self.get().overflowing_mul(other.get());
295        if result.0.is_zero() {
296            (Self::MAX, true)
297        } else {
298            unsafe { (Self::new_unchecked(result.0), result.1) }
299        }
300    }
301
302    /// Raises non-zero value to an integer power.
303    /// Checks for overflow and returns [`None`] on overflow.
304    /// As a consequence, the result cannot wrap to zero.
305    #[inline]
306    pub fn checked_pow(self, other: U256) -> Option<Self> {
307        // SAFETY:
308        // - `checked_pow` returns `None` on overflow/underflow
309        // - `self` is non-zero
310        // - the only way to get zero from an exponentiation without overflow is
311        //   for base to be zero
312        //
313        // So the result cannot be zero.
314        self.get()
315            .checked_pow(other)
316            .map(|result| unsafe { Self::new_unchecked(result) })
317    }
318
319    /// Raise non-zero value to an integer power.
320    #[inline]
321    pub fn overflowing_pow(self, other: U256) -> (Self, bool) {
322        let result = self.get().overflowing_pow(other);
323        if result.0.is_zero() {
324            (Self::MAX, true)
325        } else {
326            unsafe { (Self::new_unchecked(result.0), result.1) }
327        }
328    }
329
330    /// Fast exponentiation by squaring
331    /// <https://en.wikipedia.org/wiki/Exponentiation_by_squaring>
332    ///
333    /// # Panics
334    ///
335    /// Panics if the result overflows the type.
336    #[inline]
337    pub fn pow(self, other: U256) -> Self {
338        // SAFETY:
339        // - `pow` panics on overflow/underflow
340        // - `self` is non-zero
341        // - the only way to get zero from an exponentiation without overflow is
342        //   for base to be zero
343        //
344        // So the result cannot be zero.
345        unsafe { Self::new_unchecked(self.get().pow(other)) }
346    }
347}
348
349impl From<NonZeroU256> for U256 {
350    #[inline]
351    fn from(nonzero: NonZeroU256) -> Self {
352        // Call `get` method to keep range information.
353        nonzero.get()
354    }
355}
356
357macro_rules! impl_map_from {
358    ($from:ty) => {
359        impl From<$from> for NonZeroU256 {
360            fn from(value: $from) -> Self {
361                unsafe { Self::new_unchecked(U256::from(value.get())) }
362            }
363        }
364    };
365}
366
367impl_map_from!(NonZero<u8>);
368impl_map_from!(NonZero<u16>);
369impl_map_from!(NonZero<u32>);
370impl_map_from!(NonZero<u64>);
371impl_map_from!(NonZero<u128>);
372
373macro_rules! impl_try_from {
374    ($from:ty) => {
375        impl TryFrom<$from> for NonZeroU256 {
376            type Error = &'static str;
377
378            #[inline]
379            fn try_from(value: $from) -> Result<NonZeroU256, &'static str> {
380                NonZeroU256::new(U256::from(value)).ok_or("integer value is zero")
381            }
382        }
383    };
384}
385
386impl_try_from!(u8);
387impl_try_from!(u16);
388impl_try_from!(u32);
389impl_try_from!(u64);
390impl_try_from!(u128);
391
392#[doc(hidden)]
393macro_rules! panic_on_overflow {
394    ($name: expr) => {
395        if $name {
396            panic!("arithmetic operation overflow")
397        }
398    };
399}
400
401impl<T> core::ops::Add<T> for NonZeroU256
402where
403    T: Into<U256>,
404{
405    type Output = NonZeroU256;
406
407    fn add(self, other: T) -> NonZeroU256 {
408        let (result, overflow) = self.overflowing_add(other.into());
409        panic_on_overflow!(overflow);
410        result
411    }
412}
413
414impl<T> core::ops::Add<T> for &NonZeroU256
415where
416    T: Into<U256>,
417{
418    type Output = NonZeroU256;
419
420    fn add(self, other: T) -> NonZeroU256 {
421        *self + other
422    }
423}
424
425impl<T> core::ops::AddAssign<T> for NonZeroU256
426where
427    T: Into<U256>,
428{
429    fn add_assign(&mut self, other: T) {
430        let (result, overflow) = self.overflowing_add(other.into());
431        panic_on_overflow!(overflow);
432        *self = result
433    }
434}
435
436impl<T> core::ops::Sub<T> for NonZeroU256
437where
438    T: Into<U256>,
439{
440    type Output = NonZeroU256;
441
442    #[inline]
443    fn sub(self, other: T) -> NonZeroU256 {
444        let (result, overflow) = self.overflowing_sub(other.into());
445        panic_on_overflow!(overflow);
446        result
447    }
448}
449
450impl<T> core::ops::Sub<T> for &NonZeroU256
451where
452    T: Into<U256>,
453{
454    type Output = NonZeroU256;
455
456    fn sub(self, other: T) -> NonZeroU256 {
457        *self - other
458    }
459}
460
461impl<T> core::ops::SubAssign<T> for NonZeroU256
462where
463    T: Into<U256>,
464{
465    fn sub_assign(&mut self, other: T) {
466        let (result, overflow) = self.overflowing_sub(other.into());
467        panic_on_overflow!(overflow);
468        *self = result
469    }
470}
471
472impl core::ops::Mul<NonZeroU256> for NonZeroU256 {
473    type Output = NonZeroU256;
474
475    fn mul(self, other: NonZeroU256) -> NonZeroU256 {
476        let (result, overflow) = self.overflowing_mul(other);
477        panic_on_overflow!(overflow);
478        result
479    }
480}
481
482impl<'a> core::ops::Mul<&'a NonZeroU256> for NonZeroU256 {
483    type Output = NonZeroU256;
484
485    fn mul(self, other: &'a NonZeroU256) -> NonZeroU256 {
486        let (result, overflow) = self.overflowing_mul(*other);
487        panic_on_overflow!(overflow);
488        result
489    }
490}
491
492impl<'a> core::ops::Mul<&'a NonZeroU256> for &'a NonZeroU256 {
493    type Output = NonZeroU256;
494
495    fn mul(self, other: &'a NonZeroU256) -> NonZeroU256 {
496        let (result, overflow) = self.overflowing_mul(*other);
497        panic_on_overflow!(overflow);
498        result
499    }
500}
501
502impl core::ops::Mul<NonZeroU256> for &NonZeroU256 {
503    type Output = NonZeroU256;
504
505    fn mul(self, other: NonZeroU256) -> NonZeroU256 {
506        let (result, overflow) = self.overflowing_mul(other);
507        panic_on_overflow!(overflow);
508        result
509    }
510}
511
512impl core::ops::MulAssign<NonZeroU256> for NonZeroU256 {
513    fn mul_assign(&mut self, other: NonZeroU256) {
514        let result = *self * other;
515        *self = result
516    }
517}
518
519#[cfg(feature = "codec")]
520macro_rules! impl_for_non_zero {
521    ( $( $name:ty ),* $(,)? ) => {
522        $(
523            impl Encode for $name {
524                fn size_hint(&self) -> usize {
525                    self.get().size_hint()
526                }
527
528                fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
529                    self.get().encode_to(dest)
530                }
531
532                fn encode(&self) -> Vec<u8> {
533                    self.get().encode()
534                }
535
536                fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
537                    self.get().using_encoded(f)
538                }
539            }
540
541            impl EncodeLike for $name {}
542
543            impl Decode for $name {
544                fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
545                    Self::new(Decode::decode(input)?)
546                        .ok_or_else(|| Error::from("cannot create non-zero number from 0"))
547                }
548            }
549        )*
550    }
551}
552
553#[cfg(feature = "codec")]
554impl_for_non_zero!(NonZeroU256);
555
556#[cfg(test)]
557mod tests {
558    extern crate alloc;
559
560    use super::*;
561    use alloc::format;
562
563    #[test]
564    fn nonzero_u256_from_to_u256() {
565        let u256 = U256::from(42u64);
566        let nz = NonZeroU256::new(u256).unwrap();
567        assert_eq!(u256, nz.into());
568        assert_eq!(format!("{u256}"), format!("{nz}"));
569        assert_eq!(format!("{u256:?}"), format!("{nz:?}"));
570    }
571
572    #[test]
573    fn nonzero_u256_from_nz64() {
574        let nzu64 = NonZero::<u64>::new(42u64).unwrap();
575        let nz: NonZeroU256 = nzu64.into();
576        assert_eq!(U256::from(nzu64.get()), nz.get());
577    }
578
579    #[test]
580    fn nonzero_u256_from_zero() {
581        let zero = 0u64;
582        let opt = NonZeroU256::new(U256::from(zero));
583        assert_eq!(None, opt);
584        let res = TryInto::<NonZeroU256>::try_into(zero);
585        assert_eq!(Err("integer value is zero"), res);
586    }
587
588    #[test]
589    fn nonzero_u256_overflowing_add() {
590        let nzu256 = NonZeroU256::MAX;
591        let result = nzu256.overflowing_add(1u64.into());
592        assert_eq!((NonZeroU256::MIN, true), result);
593    }
594
595    #[test]
596    fn nonzero_u256_overflowing_sub() {
597        let nzu256 = NonZeroU256::MIN;
598        let result = nzu256.overflowing_sub(1u64.into());
599        assert_eq!((NonZeroU256::MAX, true), result);
600    }
601
602    #[test]
603    fn nonzero_u256_overflowing_mul() {
604        let mut nzu256 = NonZeroU256::from(NonZero::<u128>::MAX);
605        nzu256 += 1;
606        let result = nzu256.overflowing_mul(nzu256);
607        assert_eq!((NonZeroU256::MAX, true), result);
608    }
609
610    #[test]
611    fn nonzero_u256_overflowing_pow() {
612        let mut nzu256 = NonZeroU256::from(NonZero::<u128>::MAX);
613        nzu256 += 1;
614        let result: (NonZeroU256, bool) = nzu256.overflowing_pow(2.into());
615        assert_eq!((NonZeroU256::MAX, true), result);
616    }
617}