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_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 whether the gas value is zero.
95    ///
96    /// # Examples
97    /// ```
98    /// # use near_gas::NearGas;
99    /// assert!(NearGas::from_gas(0).is_zero());
100    /// assert!(!NearGas::from_gas(1).is_zero());
101    /// ```
102    pub const fn is_zero(&self) -> bool {
103        self.as_gas() == 0
104    }
105
106    /// Returns the total number of whole Gas contained by this `NearGas`.
107    ///
108    /// # Examples
109    /// ```
110    /// use near_gas::NearGas;
111    /// let neargas = NearGas::from_gas(12345);
112    /// assert_eq!(neargas.as_gas(), 12345);
113    /// ```
114    pub const fn as_gas(self) -> u64 {
115        self.inner
116    }
117
118    /// Returns the total number of a whole part of giga 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);
124    /// assert_eq!(neargas.as_ggas(), 1);
125    /// ```
126    pub const fn as_ggas(self) -> u64 {
127        self.inner / ONE_GIGA_GAS
128    }
129
130    /// Returns the total number of a whole part of tera Gas contained by this `NearGas`.
131    ///
132    /// # Examples
133    /// ```
134    /// use near_gas::NearGas;
135    /// let neargas = NearGas::from_gas(1 * 1_000_000_000_000);
136    /// assert_eq!(neargas.as_tgas(), 1);
137    /// ```
138    pub const fn as_tgas(self) -> u64 {
139        self.inner / ONE_TERA_GAS
140    }
141
142    /// Checked integer addition. Computes self + rhs, returning None if overflow occurred.
143    ///
144    /// # Examples
145    /// ```
146    /// use near_gas::NearGas;
147    /// use std::u64;
148    /// assert_eq!(NearGas::from_gas(u64::MAX -2).checked_add(NearGas::from_gas(2)), Some(NearGas::from_gas(u64::MAX)));
149    /// assert_eq!(NearGas::from_gas(u64::MAX -2).checked_add(NearGas::from_gas(3)), None);
150    /// ```
151    pub const fn checked_add(self, rhs: NearGas) -> Option<Self> {
152        if let Some(gas) = self.as_gas().checked_add(rhs.as_gas()) {
153            Some(Self::from_gas(gas))
154        } else {
155            None
156        }
157    }
158
159    /// Checked integer subtraction. Computes self - rhs, returning None if overflow occurred.
160    ///
161    /// # Examples
162    /// ```
163    /// use near_gas::NearGas;
164    /// assert_eq!(NearGas::from_gas(2).checked_sub(NearGas::from_gas(2)), Some(NearGas::from_gas(0)));
165    /// assert_eq!(NearGas::from_gas(2).checked_sub(NearGas::from_gas(3)), None);
166    /// ```
167    pub const fn checked_sub(self, rhs: NearGas) -> Option<Self> {
168        if let Some(gas) = self.as_gas().checked_sub(rhs.as_gas()) {
169            Some(Self::from_gas(gas))
170        } else {
171            None
172        }
173    }
174
175    /// Checked integer multiplication. Computes self * rhs, returning None if overflow occurred.
176    ///
177    /// # Examples
178    /// ```
179    /// use near_gas::NearGas;
180    /// use std::u64;
181    /// assert_eq!(NearGas::from_gas(2).checked_mul(2), Some(NearGas::from_gas(4)));
182    /// assert_eq!(NearGas::from_gas(u64::MAX).checked_mul(2), None)
183    pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
184        if let Some(gas) = self.as_gas().checked_mul(rhs) {
185            Some(Self::from_gas(gas))
186        } else {
187            None
188        }
189    }
190
191    /// Checked integer division. Computes self / rhs, returning None if rhs == 0.
192    ///
193    /// # Examples
194    /// ```
195    /// use near_gas::NearGas;
196    /// assert_eq!(NearGas::from_gas(10).checked_div(2), Some(NearGas::from_gas(5)));
197    /// assert_eq!(NearGas::from_gas(2).checked_div(0), None);
198    /// ```
199    pub const fn checked_div(self, rhs: u64) -> Option<Self> {
200        if let Some(gas) = self.as_gas().checked_div(rhs) {
201            Some(Self::from_gas(gas))
202        } else {
203            None
204        }
205    }
206
207    /// Saturating integer addition. 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_add(NearGas::from_gas(5)), NearGas::from_gas(10));
213    /// assert_eq!(NearGas::from_gas(u64::MAX).saturating_add(NearGas::from_gas(1)), NearGas::from_gas(u64::MAX));
214    /// ```
215    pub const fn saturating_add(self, rhs: NearGas) -> NearGas {
216        NearGas::from_gas(self.as_gas().saturating_add(rhs.as_gas()))
217    }
218
219    /// Saturating integer subtraction. Computes self - rhs, saturating at the numeric bounds instead of overflowing.
220    ///
221    /// # Examples
222    /// ```
223    /// use near_gas::NearGas;
224    /// assert_eq!(NearGas::from_gas(5).saturating_sub(NearGas::from_gas(2)), NearGas::from_gas(3));
225    /// assert_eq!(NearGas::from_gas(1).saturating_sub(NearGas::from_gas(2)), NearGas::from_gas(0));
226    /// ```
227    pub const fn saturating_sub(self, rhs: NearGas) -> NearGas {
228        NearGas::from_gas(self.as_gas().saturating_sub(rhs.as_gas()))
229    }
230
231    /// Saturating integer multiplication. Computes self * rhs, saturating at the numeric bounds instead of overflowing.
232    ///
233    /// # Examples
234    /// ```
235    /// use near_gas::NearGas;
236    /// use std::u64;
237    /// assert_eq!(NearGas::from_gas(2).saturating_mul(5), NearGas::from_gas(10));
238    /// assert_eq!(NearGas::from_gas(u64::MAX).saturating_mul(2), NearGas::from_gas(u64::MAX));
239    /// ```
240    pub const fn saturating_mul(self, rhs: u64) -> NearGas {
241        NearGas::from_gas(self.as_gas().saturating_mul(rhs))
242    }
243
244    /// Saturating integer division. Computes self / rhs, saturating at the numeric bounds instead of overflowing.
245    ///
246    /// # Examples
247    /// ```
248    /// use near_gas::NearGas;
249    /// assert_eq!(NearGas::from_gas(10).saturating_div(2), NearGas::from_gas(5));
250    /// assert_eq!(NearGas::from_gas(10).saturating_div(0), NearGas::from_gas(0))
251    /// ```
252    pub const fn saturating_div(self, rhs: u64) -> NearGas {
253        if rhs == 0 {
254            return NearGas::from_gas(0);
255        }
256        NearGas::from_gas(self.as_gas().saturating_div(rhs))
257    }
258}
259
260#[cfg(test)]
261mod test {
262    use crate::NearGas;
263
264    #[test]
265    fn checked_add_gas() {
266        let gas = NearGas::from_gas(u64::MAX - 3);
267        let any_gas = NearGas::from_gas(3);
268        let more_gas = NearGas::from_gas(4);
269        assert_eq!(gas.checked_add(any_gas), Some(NearGas::from_gas(u64::MAX)));
270        assert_eq!(gas.checked_add(more_gas), None);
271    }
272
273    #[test]
274    fn checked_sub_gas() {
275        let gas = NearGas::from_gas(3);
276        let any_gas = NearGas::from_gas(1);
277        let more_gas = NearGas::from_gas(4);
278        assert_eq!(gas.checked_sub(any_gas), Some(NearGas::from_gas(2)));
279        assert_eq!(gas.checked_sub(more_gas), None);
280    }
281
282    #[test]
283    fn checked_mul_gas() {
284        let gas = NearGas::from_gas(u64::MAX / 10);
285        assert_eq!(
286            gas.checked_mul(10),
287            Some(NearGas::from_gas(u64::MAX / 10 * 10))
288        );
289        assert_eq!(gas.checked_mul(11), None);
290    }
291
292    #[test]
293    fn checked_div_gas() {
294        let gas = NearGas::from_gas(10);
295        assert_eq!(gas.checked_div(2), Some(NearGas::from_gas(5)));
296        assert_eq!(gas.checked_div(11), Some(NearGas::from_gas(0)));
297        assert_eq!(gas.checked_div(0), None);
298    }
299
300    #[test]
301    fn saturating_add_gas() {
302        let gas = NearGas::from_gas(100);
303        let added_gas = NearGas::from_gas(1);
304        let another_gas = NearGas::from_gas(u64::MAX);
305        assert_eq!(gas.saturating_add(added_gas), NearGas::from_gas(101));
306        assert_eq!(
307            another_gas.saturating_add(added_gas),
308            NearGas::from_gas(u64::MAX)
309        );
310    }
311
312    #[test]
313    fn saturating_sub_gas() {
314        let gas = NearGas::from_gas(100);
315        let rhs_gas = NearGas::from_gas(1);
316        let another_gas = NearGas::from_gas(u64::MIN);
317        assert_eq!(gas.saturating_sub(rhs_gas), NearGas::from_gas(99));
318        assert_eq!(
319            another_gas.saturating_sub(rhs_gas),
320            NearGas::from_gas(u64::MIN)
321        );
322    }
323
324    #[test]
325    fn saturating_mul_gas() {
326        let gas = NearGas::from_gas(2);
327        let rhs = 10;
328        let another_gas = u64::MAX;
329        assert_eq!(gas.saturating_mul(rhs), NearGas::from_gas(20));
330        assert_eq!(gas.saturating_mul(another_gas), NearGas::from_gas(u64::MAX));
331    }
332
333    #[test]
334    fn saturating_div_gas() {
335        let gas = NearGas::from_gas(10);
336        let rhs = 2;
337        let another_gas = 20;
338        assert_eq!(gas.saturating_div(rhs), NearGas::from_gas(5));
339        assert_eq!(gas.saturating_div(another_gas), NearGas::from_gas(0));
340    }
341}