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}