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}