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}