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