unc_gas/
lib.rs

1//! A `UncGas` type to represent a value of Gas.
2//!
3//! Each `UncGas` is composed of a whole number of Gases.
4//! `UncGas` is implementing the common trait `FromStr`. Also, have utils function to parse from `str` into `u64`.
5//!
6//! # Examples
7//! ```
8//! use unc_gas::*;
9//!
10//! let one_tera_gas = UncGas::from_gas(10_u64.pow(12));
11//! assert_eq!(one_tera_gas, UncGas::from_tgas(1));
12//! assert_eq!(one_tera_gas, UncGas::from_ggas(1000));
13//! ```
14//!
15//! # Crate features
16//!
17//! * **borsh** (optional) -
18//!   When enabled allows `UncGas` to serialized and deserialized by `borsh`.
19//!
20//! * **serde** (optional) -
21//!   When enabled allows `UncGas` to serialized and deserialized by `serde`.
22//!
23//! * **schemars** (optional) -
24//!  Implements `schemars::JsonSchema` for `UncGas`.
25//!
26//! * **interactive-clap** (optional) -
27//!  Implements `interactive_clap::ToCli` for `UncGas`.
28mod error;
29mod trait_impls;
30mod utils;
31
32pub use self::error::UncGasError;
33pub use self::utils::DecimalNumberParsingError;
34
35#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
36#[cfg_attr(
37    feature = "borsh",
38    derive(borsh::BorshDeserialize, borsh::BorshSerialize)
39)]
40#[cfg_attr(feature = "abi", derive(borsh::BorshSchema))]
41#[repr(transparent)]
42pub struct UncGas {
43    inner: u64,
44}
45
46const ONE_TERA_GAS: u64 = 10u64.pow(12);
47const ONE_GIGA_GAS: u64 = 10u64.pow(9);
48
49impl UncGas {
50    /// Creates a new `UncGas` from the specified number of whole tera Gas.
51    ///
52    /// # Examples
53    /// ```
54    /// use unc_gas::UncGas;
55    ///
56    /// let tera_gas = UncGas::from_tgas(5);
57    ///
58    /// assert_eq!(tera_gas.as_gas(), 5 * 1_000_000_000_000);
59    /// ```
60    pub const fn from_tgas(mut inner: u64) -> Self {
61        inner *= ONE_TERA_GAS;
62        Self { inner }
63    }
64
65    /// Creates a new `UncGas` from the specified number of whole giga Gas.
66    ///
67    /// # Examples
68    /// ```
69    /// use unc_gas::UncGas;
70    ///
71    /// let giga_gas = UncGas::from_ggas(5);
72    ///
73    /// assert_eq!(giga_gas.as_gas(), 5 * 1_000_000_000);
74    /// ```
75    pub const fn from_ggas(mut inner: u64) -> Self {
76        inner *= ONE_GIGA_GAS;
77        Self { inner }
78    }
79
80    /// Creates a new `UncGas` from the specified number of whole Gas.
81    ///
82    /// # Examples
83    /// ```
84    /// use unc_gas::UncGas;
85    ///
86    /// let gas = UncGas::from_gas(5 * 1_000_000_000_000);
87    ///
88    /// assert_eq!(gas.as_tgas(), 5);
89    /// ```
90    pub const fn from_gas(inner: u64) -> Self {
91        Self { inner }
92    }
93
94    /// Returns the total number of whole Gas contained by this `UncGas`.
95    ///
96    /// # Examples
97    /// ```
98    /// use unc_gas::UncGas;
99    /// let UncGas = UncGas::from_gas(12345);
100    /// assert_eq!(UncGas.as_gas(), 12345);
101    /// ```
102    pub const fn as_gas(self) -> u64 {
103        self.inner
104    }
105
106    /// Returns the total number of a whole part of giga Gas contained by this `UncGas`.
107    ///
108    /// # Examples
109    /// ```
110    /// use unc_gas::UncGas;
111    /// let UncGas = UncGas::from_gas(1 * 1_000_000_000);
112    /// assert_eq!(UncGas.as_ggas(), 1);
113    /// ```
114    pub const fn as_ggas(self) -> u64 {
115        self.inner / ONE_GIGA_GAS
116    }
117
118    /// Returns the total number of a whole part of tera Gas contained by this `UncGas`.
119    ///
120    /// # Examples
121    /// ```
122    /// use unc_gas::UncGas;
123    /// let UncGas = UncGas::from_gas(1 * 1_000_000_000_000);
124    /// assert_eq!(UncGas.as_tgas(), 1);
125    /// ```
126    pub const fn as_tgas(self) -> u64 {
127        self.inner / ONE_TERA_GAS
128    }
129
130    /// Checked integer addition. Computes self + rhs, returning None if overflow occurred.
131    ///
132    /// # Examples
133    /// ```
134    /// use unc_gas::UncGas;
135    /// use std::u64;
136    /// assert_eq!(UncGas::from_gas(u64::MAX -2).checked_add(UncGas::from_gas(2)), Some(UncGas::from_gas(u64::MAX)));
137    /// assert_eq!(UncGas::from_gas(u64::MAX -2).checked_add(UncGas::from_gas(3)), None);
138    /// ```
139    pub const fn checked_add(self, rhs: UncGas) -> Option<Self> {
140        if let Some(gas) = self.as_gas().checked_add(rhs.as_gas()) {
141            Some(Self::from_gas(gas))
142        } else {
143            None
144        }
145    }
146
147    /// Checked integer subtraction. Computes self - rhs, returning None if overflow occurred.
148    ///
149    /// # Examples
150    /// ```
151    /// use unc_gas::UncGas;
152    /// assert_eq!(UncGas::from_gas(2).checked_sub(UncGas::from_gas(2)), Some(UncGas::from_gas(0)));
153    /// assert_eq!(UncGas::from_gas(2).checked_sub(UncGas::from_gas(3)), None);
154    /// ```
155    pub const fn checked_sub(self, rhs: UncGas) -> Option<Self> {
156        if let Some(gas) = self.as_gas().checked_sub(rhs.as_gas()) {
157            Some(Self::from_gas(gas))
158        } else {
159            None
160        }
161    }
162
163    /// Checked integer multiplication. Computes self * rhs, returning None if overflow occurred.
164    ///
165    /// # Examples
166    /// ```
167    /// use unc_gas::UncGas;
168    /// use std::u64;
169    /// assert_eq!(UncGas::from_gas(2).checked_mul(2), Some(UncGas::from_gas(4)));
170    /// assert_eq!(UncGas::from_gas(u64::MAX).checked_mul(2), None)
171    pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
172        if let Some(gas) = self.as_gas().checked_mul(rhs) {
173            Some(Self::from_gas(gas))
174        } else {
175            None
176        }
177    }
178
179    /// Checked integer division. Computes self / rhs, returning None if rhs == 0.
180    ///
181    /// # Examples
182    /// ```
183    /// use unc_gas::UncGas;
184    /// assert_eq!(UncGas::from_gas(10).checked_div(2), Some(UncGas::from_gas(5)));
185    /// assert_eq!(UncGas::from_gas(2).checked_div(0), None);
186    /// ```
187    pub const fn checked_div(self, rhs: u64) -> Option<Self> {
188        if let Some(gas) = self.as_gas().checked_div(rhs) {
189            Some(Self::from_gas(gas))
190        } else {
191            None
192        }
193    }
194
195    /// Saturating integer addition. Computes self + rhs, saturating at the numeric bounds instead of overflowing.
196    ///
197    /// # Examples
198    /// ```
199    /// use unc_gas::UncGas;
200    /// assert_eq!(UncGas::from_gas(5).saturating_add(UncGas::from_gas(5)), UncGas::from_gas(10));
201    /// assert_eq!(UncGas::from_gas(u64::MAX).saturating_add(UncGas::from_gas(1)), UncGas::from_gas(u64::MAX));
202    /// ```
203    pub const fn saturating_add(self, rhs: UncGas) -> UncGas {
204        UncGas::from_gas(self.as_gas().saturating_add(rhs.as_gas()))
205    }
206
207    /// Saturating integer subtraction. Computes self - rhs, saturating at the numeric bounds instead of overflowing.
208    ///
209    /// # Examples
210    /// ```
211    /// use unc_gas::UncGas;
212    /// assert_eq!(UncGas::from_gas(5).saturating_sub(UncGas::from_gas(2)), UncGas::from_gas(3));
213    /// assert_eq!(UncGas::from_gas(1).saturating_sub(UncGas::from_gas(2)), UncGas::from_gas(0));
214    /// ```
215    pub const fn saturating_sub(self, rhs: UncGas) -> UncGas {
216        UncGas::from_gas(self.as_gas().saturating_sub(rhs.as_gas()))
217    }
218
219    /// Saturating integer multiplication. Computes self * rhs, saturating at the numeric bounds instead of overflowing.
220    ///
221    /// # Examples
222    /// ```
223    /// use unc_gas::UncGas;
224    /// use std::u64;
225    /// assert_eq!(UncGas::from_gas(2).saturating_mul(5), UncGas::from_gas(10));
226    /// assert_eq!(UncGas::from_gas(u64::MAX).saturating_mul(2), UncGas::from_gas(u64::MAX));
227    /// ```
228    pub const fn saturating_mul(self, rhs: u64) -> UncGas {
229        UncGas::from_gas(self.as_gas().saturating_mul(rhs))
230    }
231
232    /// Saturating integer division. Computes self / rhs, saturating at the numeric bounds instead of overflowing.
233    ///
234    /// # Examples
235    /// ```
236    /// use unc_gas::UncGas;
237    /// assert_eq!(UncGas::from_gas(10).saturating_div(2), UncGas::from_gas(5));
238    /// assert_eq!(UncGas::from_gas(10).saturating_div(0), UncGas::from_gas(0))
239    /// ```
240    pub const fn saturating_div(self, rhs: u64) -> UncGas {
241        if rhs == 0 {
242            return UncGas::from_gas(0);
243        }
244        UncGas::from_gas(self.as_gas().saturating_div(rhs))
245    }
246}
247
248#[cfg(test)]
249mod test {
250    use crate::UncGas;
251
252    #[test]
253    fn checked_add_gas() {
254        let gas = UncGas::from_gas(u64::MAX - 3);
255        let any_gas = UncGas::from_gas(3);
256        let more_gas = UncGas::from_gas(4);
257        assert_eq!(gas.checked_add(any_gas), Some(UncGas::from_gas(u64::MAX)));
258        assert_eq!(gas.checked_add(more_gas), None);
259    }
260
261    #[test]
262    fn checked_sub_gas() {
263        let gas = UncGas::from_gas(3);
264        let any_gas = UncGas::from_gas(1);
265        let more_gas = UncGas::from_gas(4);
266        assert_eq!(gas.checked_sub(any_gas), Some(UncGas::from_gas(2)));
267        assert_eq!(gas.checked_sub(more_gas), None);
268    }
269
270    #[test]
271    fn checked_mul_gas() {
272        let gas = UncGas::from_gas(u64::MAX / 10);
273        assert_eq!(
274            gas.checked_mul(10),
275            Some(UncGas::from_gas(u64::MAX / 10 * 10))
276        );
277        assert_eq!(gas.checked_mul(11), None);
278    }
279
280    #[test]
281    fn checked_div_gas() {
282        let gas = UncGas::from_gas(10);
283        assert_eq!(gas.checked_div(2), Some(UncGas::from_gas(5)));
284        assert_eq!(gas.checked_div(11), Some(UncGas::from_gas(0)));
285        assert_eq!(gas.checked_div(0), None);
286    }
287
288    #[test]
289    fn saturating_add_gas() {
290        let gas = UncGas::from_gas(100);
291        let added_gas = UncGas::from_gas(1);
292        let another_gas = UncGas::from_gas(u64::MAX);
293        assert_eq!(
294            gas.saturating_add(added_gas.clone()),
295            UncGas::from_gas(101)
296        );
297        assert_eq!(
298            another_gas.saturating_add(added_gas),
299            UncGas::from_gas(u64::MAX)
300        );
301    }
302
303    #[test]
304    fn saturating_sub_gas() {
305        let gas = UncGas::from_gas(100);
306        let rhs_gas = UncGas::from_gas(1);
307        let another_gas = UncGas::from_gas(u64::MIN);
308        assert_eq!(gas.saturating_sub(rhs_gas.clone()), UncGas::from_gas(99));
309        assert_eq!(
310            another_gas.saturating_sub(rhs_gas),
311            UncGas::from_gas(u64::MIN)
312        );
313    }
314
315    #[test]
316    fn saturating_mul_gas() {
317        let gas = UncGas::from_gas(2);
318        let rhs = 10;
319        let another_gas = u64::MAX;
320        assert_eq!(gas.saturating_mul(rhs), UncGas::from_gas(20));
321        assert_eq!(gas.saturating_mul(another_gas), UncGas::from_gas(u64::MAX));
322    }
323
324    #[test]
325    fn saturating_div_gas() {
326        let gas = UncGas::from_gas(10);
327        let rhs = 2;
328        let another_gas = 20;
329        assert_eq!(gas.saturating_div(rhs), UncGas::from_gas(5));
330        assert_eq!(gas.saturating_div(another_gas), UncGas::from_gas(0));
331    }
332}