Skip to main content

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_PETA_GAS: u64 = 10u64.pow(15);
47const ONE_TERA_GAS: u64 = 10u64.pow(12);
48const ONE_GIGA_GAS: u64 = 10u64.pow(9);
49
50impl NearGas {
51    /// Creates a new `NearGas` from the specified number of whole peta Gas.
52    ///
53    /// # Examples
54    /// ```
55    /// use near_gas::NearGas;
56    ///
57    /// let tera_gas = NearGas::from_pgas(1);
58    ///
59    /// assert_eq!(tera_gas.as_gas(), 1_000_000_000_000_000);
60    /// ```
61    pub const fn from_pgas(mut inner: u64) -> Self {
62        inner *= ONE_PETA_GAS;
63        Self { inner }
64    }
65
66    /// Creates a new `NearGas` from the specified number of whole tera Gas.
67    ///
68    /// # Examples
69    /// ```
70    /// use near_gas::NearGas;
71    ///
72    /// let tera_gas = NearGas::from_tgas(5);
73    ///
74    /// assert_eq!(tera_gas.as_gas(), 5 * 1_000_000_000_000);
75    /// ```
76    pub const fn from_tgas(mut inner: u64) -> Self {
77        inner *= ONE_TERA_GAS;
78        Self { inner }
79    }
80
81    /// Creates a new `NearGas` from the specified number of whole giga Gas.
82    ///
83    /// # Examples
84    /// ```
85    /// use near_gas::NearGas;
86    ///
87    /// let giga_gas = NearGas::from_ggas(5);
88    ///
89    /// assert_eq!(giga_gas.as_gas(), 5 * 1_000_000_000);
90    /// ```
91    pub const fn from_ggas(mut inner: u64) -> Self {
92        inner *= ONE_GIGA_GAS;
93        Self { inner }
94    }
95
96    /// Creates a new `NearGas` from the specified number of whole Gas.
97    ///
98    /// # Examples
99    /// ```
100    /// use near_gas::NearGas;
101    ///
102    /// let gas = NearGas::from_gas(5 * 1_000_000_000_000);
103    ///
104    /// assert_eq!(gas.as_tgas(), 5);
105    /// ```
106    pub const fn from_gas(inner: u64) -> Self {
107        Self { inner }
108    }
109
110    /// Returns whether the gas value is zero.
111    ///
112    /// # Examples
113    /// ```
114    /// # use near_gas::NearGas;
115    /// assert!(NearGas::from_gas(0).is_zero());
116    /// assert!(!NearGas::from_gas(1).is_zero());
117    /// ```
118    pub const fn is_zero(&self) -> bool {
119        self.as_gas() == 0
120    }
121
122    /// Returns the total number of whole Gas contained by this `NearGas`.
123    ///
124    /// # Examples
125    /// ```
126    /// use near_gas::NearGas;
127    /// let neargas = NearGas::from_gas(12345);
128    /// assert_eq!(neargas.as_gas(), 12345);
129    /// ```
130    pub const fn as_gas(self) -> u64 {
131        self.inner
132    }
133
134    /// Returns the total number of a whole part of giga Gas contained by this `NearGas`.
135    ///
136    /// # Examples
137    /// ```
138    /// use near_gas::NearGas;
139    /// let neargas = NearGas::from_gas(1 * 1_000_000_000);
140    /// assert_eq!(neargas.as_ggas(), 1);
141    /// ```
142    pub const fn as_ggas(self) -> u64 {
143        self.inner / ONE_GIGA_GAS
144    }
145
146    /// Returns the total number of a whole part of tera Gas contained by this `NearGas`.
147    ///
148    /// # Examples
149    /// ```
150    /// use near_gas::NearGas;
151    /// let neargas = NearGas::from_gas(1 * 1_000_000_000_000);
152    /// assert_eq!(neargas.as_tgas(), 1);
153    /// ```
154    pub const fn as_tgas(self) -> u64 {
155        self.inner / ONE_TERA_GAS
156    }
157
158    /// Returns the total number of a whole part of peta Gas contained by this `NearGas`.
159    ///
160    /// # Examples
161    /// ```
162    /// use near_gas::NearGas;
163    /// let neargas = NearGas::from_gas(1 * 1_000_000_000_000_000);
164    /// assert_eq!(neargas.as_pgas(), 1);
165    /// ```
166    pub const fn as_pgas(self) -> u64 {
167        self.inner / ONE_PETA_GAS
168    }
169
170    /// Checked integer addition. Computes self + rhs, returning None if overflow occurred.
171    ///
172    /// # Examples
173    /// ```
174    /// use near_gas::NearGas;
175    /// use std::u64;
176    /// assert_eq!(NearGas::from_gas(u64::MAX -2).checked_add(NearGas::from_gas(2)), Some(NearGas::from_gas(u64::MAX)));
177    /// assert_eq!(NearGas::from_gas(u64::MAX -2).checked_add(NearGas::from_gas(3)), None);
178    /// ```
179    pub const fn checked_add(self, rhs: NearGas) -> Option<Self> {
180        if let Some(gas) = self.as_gas().checked_add(rhs.as_gas()) {
181            Some(Self::from_gas(gas))
182        } else {
183            None
184        }
185    }
186
187    /// Checked integer subtraction. Computes self - rhs, returning None if overflow occurred.
188    ///
189    /// # Examples
190    /// ```
191    /// use near_gas::NearGas;
192    /// assert_eq!(NearGas::from_gas(2).checked_sub(NearGas::from_gas(2)), Some(NearGas::from_gas(0)));
193    /// assert_eq!(NearGas::from_gas(2).checked_sub(NearGas::from_gas(3)), None);
194    /// ```
195    pub const fn checked_sub(self, rhs: NearGas) -> Option<Self> {
196        if let Some(gas) = self.as_gas().checked_sub(rhs.as_gas()) {
197            Some(Self::from_gas(gas))
198        } else {
199            None
200        }
201    }
202
203    /// Checked integer multiplication. Computes self * rhs, returning None if overflow occurred.
204    ///
205    /// # Examples
206    /// ```
207    /// use near_gas::NearGas;
208    /// use std::u64;
209    /// assert_eq!(NearGas::from_gas(2).checked_mul(2), Some(NearGas::from_gas(4)));
210    /// assert_eq!(NearGas::from_gas(u64::MAX).checked_mul(2), None)
211    pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
212        if let Some(gas) = self.as_gas().checked_mul(rhs) {
213            Some(Self::from_gas(gas))
214        } else {
215            None
216        }
217    }
218
219    /// Checked integer division. Computes self / rhs, returning None if rhs == 0.
220    ///
221    /// # Examples
222    /// ```
223    /// use near_gas::NearGas;
224    /// assert_eq!(NearGas::from_gas(10).checked_div(2), Some(NearGas::from_gas(5)));
225    /// assert_eq!(NearGas::from_gas(2).checked_div(0), None);
226    /// ```
227    pub const fn checked_div(self, rhs: u64) -> Option<Self> {
228        if let Some(gas) = self.as_gas().checked_div(rhs) {
229            Some(Self::from_gas(gas))
230        } else {
231            None
232        }
233    }
234
235    /// Saturating integer addition. Computes self + rhs, saturating at the numeric bounds instead of overflowing.
236    ///
237    /// # Examples
238    /// ```
239    /// use near_gas::NearGas;
240    /// assert_eq!(NearGas::from_gas(5).saturating_add(NearGas::from_gas(5)), NearGas::from_gas(10));
241    /// assert_eq!(NearGas::from_gas(u64::MAX).saturating_add(NearGas::from_gas(1)), NearGas::from_gas(u64::MAX));
242    /// ```
243    pub const fn saturating_add(self, rhs: NearGas) -> NearGas {
244        NearGas::from_gas(self.as_gas().saturating_add(rhs.as_gas()))
245    }
246
247    /// Saturating integer subtraction. Computes self - rhs, saturating at the numeric bounds instead of overflowing.
248    ///
249    /// # Examples
250    /// ```
251    /// use near_gas::NearGas;
252    /// assert_eq!(NearGas::from_gas(5).saturating_sub(NearGas::from_gas(2)), NearGas::from_gas(3));
253    /// assert_eq!(NearGas::from_gas(1).saturating_sub(NearGas::from_gas(2)), NearGas::from_gas(0));
254    /// ```
255    pub const fn saturating_sub(self, rhs: NearGas) -> NearGas {
256        NearGas::from_gas(self.as_gas().saturating_sub(rhs.as_gas()))
257    }
258
259    /// Saturating integer multiplication. Computes self * rhs, saturating at the numeric bounds instead of overflowing.
260    ///
261    /// # Examples
262    /// ```
263    /// use near_gas::NearGas;
264    /// use std::u64;
265    /// assert_eq!(NearGas::from_gas(2).saturating_mul(5), NearGas::from_gas(10));
266    /// assert_eq!(NearGas::from_gas(u64::MAX).saturating_mul(2), NearGas::from_gas(u64::MAX));
267    /// ```
268    pub const fn saturating_mul(self, rhs: u64) -> NearGas {
269        NearGas::from_gas(self.as_gas().saturating_mul(rhs))
270    }
271
272    /// Saturating integer division. Computes self / rhs, saturating at the numeric bounds instead of overflowing.
273    ///
274    /// # Examples
275    /// ```
276    /// use near_gas::NearGas;
277    /// assert_eq!(NearGas::from_gas(10).saturating_div(2), NearGas::from_gas(5));
278    /// assert_eq!(NearGas::from_gas(10).saturating_div(0), NearGas::from_gas(0))
279    /// ```
280    pub const fn saturating_div(self, rhs: u64) -> NearGas {
281        if rhs == 0 {
282            return NearGas::from_gas(0);
283        }
284        NearGas::from_gas(self.as_gas().saturating_div(rhs))
285    }
286}
287
288#[cfg(test)]
289mod test {
290    use crate::NearGas;
291
292    #[test]
293    fn checked_add_gas() {
294        let gas = NearGas::from_gas(u64::MAX - 3);
295        let any_gas = NearGas::from_gas(3);
296        let more_gas = NearGas::from_gas(4);
297        assert_eq!(gas.checked_add(any_gas), Some(NearGas::from_gas(u64::MAX)));
298        assert_eq!(gas.checked_add(more_gas), None);
299    }
300
301    #[test]
302    fn checked_sub_gas() {
303        let gas = NearGas::from_gas(3);
304        let any_gas = NearGas::from_gas(1);
305        let more_gas = NearGas::from_gas(4);
306        assert_eq!(gas.checked_sub(any_gas), Some(NearGas::from_gas(2)));
307        assert_eq!(gas.checked_sub(more_gas), None);
308    }
309
310    #[test]
311    fn checked_mul_gas() {
312        let gas = NearGas::from_gas(u64::MAX / 10);
313        assert_eq!(
314            gas.checked_mul(10),
315            Some(NearGas::from_gas(u64::MAX / 10 * 10))
316        );
317        assert_eq!(gas.checked_mul(11), None);
318    }
319
320    #[test]
321    fn checked_div_gas() {
322        let gas = NearGas::from_gas(10);
323        assert_eq!(gas.checked_div(2), Some(NearGas::from_gas(5)));
324        assert_eq!(gas.checked_div(11), Some(NearGas::from_gas(0)));
325        assert_eq!(gas.checked_div(0), None);
326    }
327
328    #[test]
329    fn saturating_add_gas() {
330        let gas = NearGas::from_gas(100);
331        let added_gas = NearGas::from_gas(1);
332        let another_gas = NearGas::from_gas(u64::MAX);
333        assert_eq!(gas.saturating_add(added_gas), NearGas::from_gas(101));
334        assert_eq!(
335            another_gas.saturating_add(added_gas),
336            NearGas::from_gas(u64::MAX)
337        );
338    }
339
340    #[test]
341    fn saturating_sub_gas() {
342        let gas = NearGas::from_gas(100);
343        let rhs_gas = NearGas::from_gas(1);
344        let another_gas = NearGas::from_gas(u64::MIN);
345        assert_eq!(gas.saturating_sub(rhs_gas), NearGas::from_gas(99));
346        assert_eq!(
347            another_gas.saturating_sub(rhs_gas),
348            NearGas::from_gas(u64::MIN)
349        );
350    }
351
352    #[test]
353    fn saturating_mul_gas() {
354        let gas = NearGas::from_gas(2);
355        let rhs = 10;
356        let another_gas = u64::MAX;
357        assert_eq!(gas.saturating_mul(rhs), NearGas::from_gas(20));
358        assert_eq!(gas.saturating_mul(another_gas), NearGas::from_gas(u64::MAX));
359    }
360
361    #[test]
362    fn saturating_div_gas() {
363        let gas = NearGas::from_gas(10);
364        let rhs = 2;
365        let another_gas = 20;
366        assert_eq!(gas.saturating_div(rhs), NearGas::from_gas(5));
367        assert_eq!(gas.saturating_div(another_gas), NearGas::from_gas(0));
368    }
369}