near_gas/
lib.rs

1//! A `NearGas` type to represent a value of Gas.
2//!
3//! Each `NearGas` is composed of a whole number of Gases.
4//! `NearGas` is implementing the common trait `FromStr`. Also, have utils function to parse from `str` into `u64`.
5//!
6//! # Examples
7//! ```
8//! use near_gas::*;
9//!
10//! let one_tera_gas = NearGas::from_gas(10_u64.pow(12));
11//! assert_eq!(one_tera_gas, NearGas::from_tgas(1));
12//! assert_eq!(one_tera_gas, NearGas::from_ggas(1000));
13//! ```
14//!
15//! # Crate features
16//!
17//! * **borsh** (optional) -
18//!   When enabled allows `NearGas` to serialized and deserialized by `borsh`.
19//!
20//! * **serde** (optional) -
21//!   When enabled allows `NearGas` to serialized and deserialized by `serde`.
22//!
23//! * **schemars** (optional) -
24//!   Implements `schemars::JsonSchema` for `NearGas`.
25//!
26//! * **interactive-clap** (optional) -
27//!   Implements `interactive_clap::ToCli` for `NearGas`.
28mod error;
29mod trait_impls;
30mod utils;
31
32pub use self::error::NearGasError;
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 NearGas {
43    inner: u64,
44}
45
46const ONE_TERA_GAS: u64 = 10u64.pow(12);
47const ONE_GIGA_GAS: u64 = 10u64.pow(9);
48
49impl NearGas {
50    /// Creates a new `NearGas` from the specified number of whole tera Gas.
51    ///
52    /// # Examples
53    /// ```
54    /// use near_gas::NearGas;
55    ///
56    /// let tera_gas = NearGas::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 `NearGas` from the specified number of whole giga Gas.
66    ///
67    /// # Examples
68    /// ```
69    /// use near_gas::NearGas;
70    ///
71    /// let giga_gas = NearGas::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 `NearGas` from the specified number of whole Gas.
81    ///
82    /// # Examples
83    /// ```
84    /// use near_gas::NearGas;
85    ///
86    /// let gas = NearGas::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 `NearGas`.
95    ///
96    /// # Examples
97    /// ```
98    /// use near_gas::NearGas;
99    /// let neargas = NearGas::from_gas(12345);
100    /// assert_eq!(neargas.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 `NearGas`.
107    ///
108    /// # Examples
109    /// ```
110    /// use near_gas::NearGas;
111    /// let neargas = NearGas::from_gas(1 * 1_000_000_000);
112    /// assert_eq!(neargas.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 `NearGas`.
119    ///
120    /// # Examples
121    /// ```
122    /// use near_gas::NearGas;
123    /// let neargas = NearGas::from_gas(1 * 1_000_000_000_000);
124    /// assert_eq!(neargas.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 near_gas::NearGas;
135    /// use std::u64;
136    /// assert_eq!(NearGas::from_gas(u64::MAX -2).checked_add(NearGas::from_gas(2)), Some(NearGas::from_gas(u64::MAX)));
137    /// assert_eq!(NearGas::from_gas(u64::MAX -2).checked_add(NearGas::from_gas(3)), None);
138    /// ```
139    pub const fn checked_add(self, rhs: NearGas) -> 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 near_gas::NearGas;
152    /// assert_eq!(NearGas::from_gas(2).checked_sub(NearGas::from_gas(2)), Some(NearGas::from_gas(0)));
153    /// assert_eq!(NearGas::from_gas(2).checked_sub(NearGas::from_gas(3)), None);
154    /// ```
155    pub const fn checked_sub(self, rhs: NearGas) -> 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 near_gas::NearGas;
168    /// use std::u64;
169    /// assert_eq!(NearGas::from_gas(2).checked_mul(2), Some(NearGas::from_gas(4)));
170    /// assert_eq!(NearGas::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 near_gas::NearGas;
184    /// assert_eq!(NearGas::from_gas(10).checked_div(2), Some(NearGas::from_gas(5)));
185    /// assert_eq!(NearGas::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 near_gas::NearGas;
200    /// assert_eq!(NearGas::from_gas(5).saturating_add(NearGas::from_gas(5)), NearGas::from_gas(10));
201    /// assert_eq!(NearGas::from_gas(u64::MAX).saturating_add(NearGas::from_gas(1)), NearGas::from_gas(u64::MAX));
202    /// ```
203    pub const fn saturating_add(self, rhs: NearGas) -> NearGas {
204        NearGas::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 near_gas::NearGas;
212    /// assert_eq!(NearGas::from_gas(5).saturating_sub(NearGas::from_gas(2)), NearGas::from_gas(3));
213    /// assert_eq!(NearGas::from_gas(1).saturating_sub(NearGas::from_gas(2)), NearGas::from_gas(0));
214    /// ```
215    pub const fn saturating_sub(self, rhs: NearGas) -> NearGas {
216        NearGas::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 near_gas::NearGas;
224    /// use std::u64;
225    /// assert_eq!(NearGas::from_gas(2).saturating_mul(5), NearGas::from_gas(10));
226    /// assert_eq!(NearGas::from_gas(u64::MAX).saturating_mul(2), NearGas::from_gas(u64::MAX));
227    /// ```
228    pub const fn saturating_mul(self, rhs: u64) -> NearGas {
229        NearGas::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 near_gas::NearGas;
237    /// assert_eq!(NearGas::from_gas(10).saturating_div(2), NearGas::from_gas(5));
238    /// assert_eq!(NearGas::from_gas(10).saturating_div(0), NearGas::from_gas(0))
239    /// ```
240    pub const fn saturating_div(self, rhs: u64) -> NearGas {
241        if rhs == 0 {
242            return NearGas::from_gas(0);
243        }
244        NearGas::from_gas(self.as_gas().saturating_div(rhs))
245    }
246}
247
248#[cfg(test)]
249mod test {
250    use crate::NearGas;
251
252    #[test]
253    fn checked_add_gas() {
254        let gas = NearGas::from_gas(u64::MAX - 3);
255        let any_gas = NearGas::from_gas(3);
256        let more_gas = NearGas::from_gas(4);
257        assert_eq!(gas.checked_add(any_gas), Some(NearGas::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 = NearGas::from_gas(3);
264        let any_gas = NearGas::from_gas(1);
265        let more_gas = NearGas::from_gas(4);
266        assert_eq!(gas.checked_sub(any_gas), Some(NearGas::from_gas(2)));
267        assert_eq!(gas.checked_sub(more_gas), None);
268    }
269
270    #[test]
271    fn checked_mul_gas() {
272        let gas = NearGas::from_gas(u64::MAX / 10);
273        assert_eq!(
274            gas.checked_mul(10),
275            Some(NearGas::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 = NearGas::from_gas(10);
283        assert_eq!(gas.checked_div(2), Some(NearGas::from_gas(5)));
284        assert_eq!(gas.checked_div(11), Some(NearGas::from_gas(0)));
285        assert_eq!(gas.checked_div(0), None);
286    }
287
288    #[test]
289    fn saturating_add_gas() {
290        let gas = NearGas::from_gas(100);
291        let added_gas = NearGas::from_gas(1);
292        let another_gas = NearGas::from_gas(u64::MAX);
293        assert_eq!(gas.saturating_add(added_gas), NearGas::from_gas(101));
294        assert_eq!(
295            another_gas.saturating_add(added_gas),
296            NearGas::from_gas(u64::MAX)
297        );
298    }
299
300    #[test]
301    fn saturating_sub_gas() {
302        let gas = NearGas::from_gas(100);
303        let rhs_gas = NearGas::from_gas(1);
304        let another_gas = NearGas::from_gas(u64::MIN);
305        assert_eq!(gas.saturating_sub(rhs_gas), NearGas::from_gas(99));
306        assert_eq!(
307            another_gas.saturating_sub(rhs_gas),
308            NearGas::from_gas(u64::MIN)
309        );
310    }
311
312    #[test]
313    fn saturating_mul_gas() {
314        let gas = NearGas::from_gas(2);
315        let rhs = 10;
316        let another_gas = u64::MAX;
317        assert_eq!(gas.saturating_mul(rhs), NearGas::from_gas(20));
318        assert_eq!(gas.saturating_mul(another_gas), NearGas::from_gas(u64::MAX));
319    }
320
321    #[test]
322    fn saturating_div_gas() {
323        let gas = NearGas::from_gas(10);
324        let rhs = 2;
325        let another_gas = 20;
326        assert_eq!(gas.saturating_div(rhs), NearGas::from_gas(5));
327        assert_eq!(gas.saturating_div(another_gas), NearGas::from_gas(0));
328    }
329}