unc_gas/lib.rs
1//! A `UncGas` type to represent a value of Gas.
2//!
3//! Each `UncGas` is composed of a whole number of Gases.
4//! `UncGas` is implementing the common trait `FromStr`. Also, have utils function to parse from `str` into `u64`.
5//!
6//! # Examples
7//! ```
8//! use unc_gas::*;
9//!
10//! let one_tera_gas = UncGas::from_gas(10_u64.pow(12));
11//! assert_eq!(one_tera_gas, UncGas::from_tgas(1));
12//! assert_eq!(one_tera_gas, UncGas::from_ggas(1000));
13//! ```
14//!
15//! # Crate features
16//!
17//! * **borsh** (optional) -
18//! When enabled allows `UncGas` to serialized and deserialized by `borsh`.
19//!
20//! * **serde** (optional) -
21//! When enabled allows `UncGas` to serialized and deserialized by `serde`.
22//!
23//! * **schemars** (optional) -
24//! Implements `schemars::JsonSchema` for `UncGas`.
25//!
26//! * **interactive-clap** (optional) -
27//! Implements `interactive_clap::ToCli` for `UncGas`.
28mod error;
29mod trait_impls;
30mod utils;
31
32pub use self::error::UncGasError;
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 UncGas {
43 inner: u64,
44}
45
46const ONE_TERA_GAS: u64 = 10u64.pow(12);
47const ONE_GIGA_GAS: u64 = 10u64.pow(9);
48
49impl UncGas {
50 /// Creates a new `UncGas` from the specified number of whole tera Gas.
51 ///
52 /// # Examples
53 /// ```
54 /// use unc_gas::UncGas;
55 ///
56 /// let tera_gas = UncGas::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 `UncGas` from the specified number of whole giga Gas.
66 ///
67 /// # Examples
68 /// ```
69 /// use unc_gas::UncGas;
70 ///
71 /// let giga_gas = UncGas::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 `UncGas` from the specified number of whole Gas.
81 ///
82 /// # Examples
83 /// ```
84 /// use unc_gas::UncGas;
85 ///
86 /// let gas = UncGas::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 the total number of whole Gas contained by this `UncGas`.
95 ///
96 /// # Examples
97 /// ```
98 /// use unc_gas::UncGas;
99 /// let UncGas = UncGas::from_gas(12345);
100 /// assert_eq!(UncGas.as_gas(), 12345);
101 /// ```
102 pub const fn as_gas(self) -> u64 {
103 self.inner
104 }
105
106 /// Returns the total number of a whole part of giga Gas contained by this `UncGas`.
107 ///
108 /// # Examples
109 /// ```
110 /// use unc_gas::UncGas;
111 /// let UncGas = UncGas::from_gas(1 * 1_000_000_000);
112 /// assert_eq!(UncGas.as_ggas(), 1);
113 /// ```
114 pub const fn as_ggas(self) -> u64 {
115 self.inner / ONE_GIGA_GAS
116 }
117
118 /// Returns the total number of a whole part of tera Gas contained by this `UncGas`.
119 ///
120 /// # Examples
121 /// ```
122 /// use unc_gas::UncGas;
123 /// let UncGas = UncGas::from_gas(1 * 1_000_000_000_000);
124 /// assert_eq!(UncGas.as_tgas(), 1);
125 /// ```
126 pub const fn as_tgas(self) -> u64 {
127 self.inner / ONE_TERA_GAS
128 }
129
130 /// Checked integer addition. Computes self + rhs, returning None if overflow occurred.
131 ///
132 /// # Examples
133 /// ```
134 /// use unc_gas::UncGas;
135 /// use std::u64;
136 /// assert_eq!(UncGas::from_gas(u64::MAX -2).checked_add(UncGas::from_gas(2)), Some(UncGas::from_gas(u64::MAX)));
137 /// assert_eq!(UncGas::from_gas(u64::MAX -2).checked_add(UncGas::from_gas(3)), None);
138 /// ```
139 pub const fn checked_add(self, rhs: UncGas) -> Option<Self> {
140 if let Some(gas) = self.as_gas().checked_add(rhs.as_gas()) {
141 Some(Self::from_gas(gas))
142 } else {
143 None
144 }
145 }
146
147 /// Checked integer subtraction. Computes self - rhs, returning None if overflow occurred.
148 ///
149 /// # Examples
150 /// ```
151 /// use unc_gas::UncGas;
152 /// assert_eq!(UncGas::from_gas(2).checked_sub(UncGas::from_gas(2)), Some(UncGas::from_gas(0)));
153 /// assert_eq!(UncGas::from_gas(2).checked_sub(UncGas::from_gas(3)), None);
154 /// ```
155 pub const fn checked_sub(self, rhs: UncGas) -> Option<Self> {
156 if let Some(gas) = self.as_gas().checked_sub(rhs.as_gas()) {
157 Some(Self::from_gas(gas))
158 } else {
159 None
160 }
161 }
162
163 /// Checked integer multiplication. Computes self * rhs, returning None if overflow occurred.
164 ///
165 /// # Examples
166 /// ```
167 /// use unc_gas::UncGas;
168 /// use std::u64;
169 /// assert_eq!(UncGas::from_gas(2).checked_mul(2), Some(UncGas::from_gas(4)));
170 /// assert_eq!(UncGas::from_gas(u64::MAX).checked_mul(2), None)
171 pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
172 if let Some(gas) = self.as_gas().checked_mul(rhs) {
173 Some(Self::from_gas(gas))
174 } else {
175 None
176 }
177 }
178
179 /// Checked integer division. Computes self / rhs, returning None if rhs == 0.
180 ///
181 /// # Examples
182 /// ```
183 /// use unc_gas::UncGas;
184 /// assert_eq!(UncGas::from_gas(10).checked_div(2), Some(UncGas::from_gas(5)));
185 /// assert_eq!(UncGas::from_gas(2).checked_div(0), None);
186 /// ```
187 pub const fn checked_div(self, rhs: u64) -> Option<Self> {
188 if let Some(gas) = self.as_gas().checked_div(rhs) {
189 Some(Self::from_gas(gas))
190 } else {
191 None
192 }
193 }
194
195 /// Saturating integer addition. Computes self + rhs, saturating at the numeric bounds instead of overflowing.
196 ///
197 /// # Examples
198 /// ```
199 /// use unc_gas::UncGas;
200 /// assert_eq!(UncGas::from_gas(5).saturating_add(UncGas::from_gas(5)), UncGas::from_gas(10));
201 /// assert_eq!(UncGas::from_gas(u64::MAX).saturating_add(UncGas::from_gas(1)), UncGas::from_gas(u64::MAX));
202 /// ```
203 pub const fn saturating_add(self, rhs: UncGas) -> UncGas {
204 UncGas::from_gas(self.as_gas().saturating_add(rhs.as_gas()))
205 }
206
207 /// Saturating integer subtraction. Computes self - rhs, saturating at the numeric bounds instead of overflowing.
208 ///
209 /// # Examples
210 /// ```
211 /// use unc_gas::UncGas;
212 /// assert_eq!(UncGas::from_gas(5).saturating_sub(UncGas::from_gas(2)), UncGas::from_gas(3));
213 /// assert_eq!(UncGas::from_gas(1).saturating_sub(UncGas::from_gas(2)), UncGas::from_gas(0));
214 /// ```
215 pub const fn saturating_sub(self, rhs: UncGas) -> UncGas {
216 UncGas::from_gas(self.as_gas().saturating_sub(rhs.as_gas()))
217 }
218
219 /// Saturating integer multiplication. Computes self * rhs, saturating at the numeric bounds instead of overflowing.
220 ///
221 /// # Examples
222 /// ```
223 /// use unc_gas::UncGas;
224 /// use std::u64;
225 /// assert_eq!(UncGas::from_gas(2).saturating_mul(5), UncGas::from_gas(10));
226 /// assert_eq!(UncGas::from_gas(u64::MAX).saturating_mul(2), UncGas::from_gas(u64::MAX));
227 /// ```
228 pub const fn saturating_mul(self, rhs: u64) -> UncGas {
229 UncGas::from_gas(self.as_gas().saturating_mul(rhs))
230 }
231
232 /// Saturating integer division. Computes self / rhs, saturating at the numeric bounds instead of overflowing.
233 ///
234 /// # Examples
235 /// ```
236 /// use unc_gas::UncGas;
237 /// assert_eq!(UncGas::from_gas(10).saturating_div(2), UncGas::from_gas(5));
238 /// assert_eq!(UncGas::from_gas(10).saturating_div(0), UncGas::from_gas(0))
239 /// ```
240 pub const fn saturating_div(self, rhs: u64) -> UncGas {
241 if rhs == 0 {
242 return UncGas::from_gas(0);
243 }
244 UncGas::from_gas(self.as_gas().saturating_div(rhs))
245 }
246}
247
248#[cfg(test)]
249mod test {
250 use crate::UncGas;
251
252 #[test]
253 fn checked_add_gas() {
254 let gas = UncGas::from_gas(u64::MAX - 3);
255 let any_gas = UncGas::from_gas(3);
256 let more_gas = UncGas::from_gas(4);
257 assert_eq!(gas.checked_add(any_gas), Some(UncGas::from_gas(u64::MAX)));
258 assert_eq!(gas.checked_add(more_gas), None);
259 }
260
261 #[test]
262 fn checked_sub_gas() {
263 let gas = UncGas::from_gas(3);
264 let any_gas = UncGas::from_gas(1);
265 let more_gas = UncGas::from_gas(4);
266 assert_eq!(gas.checked_sub(any_gas), Some(UncGas::from_gas(2)));
267 assert_eq!(gas.checked_sub(more_gas), None);
268 }
269
270 #[test]
271 fn checked_mul_gas() {
272 let gas = UncGas::from_gas(u64::MAX / 10);
273 assert_eq!(
274 gas.checked_mul(10),
275 Some(UncGas::from_gas(u64::MAX / 10 * 10))
276 );
277 assert_eq!(gas.checked_mul(11), None);
278 }
279
280 #[test]
281 fn checked_div_gas() {
282 let gas = UncGas::from_gas(10);
283 assert_eq!(gas.checked_div(2), Some(UncGas::from_gas(5)));
284 assert_eq!(gas.checked_div(11), Some(UncGas::from_gas(0)));
285 assert_eq!(gas.checked_div(0), None);
286 }
287
288 #[test]
289 fn saturating_add_gas() {
290 let gas = UncGas::from_gas(100);
291 let added_gas = UncGas::from_gas(1);
292 let another_gas = UncGas::from_gas(u64::MAX);
293 assert_eq!(
294 gas.saturating_add(added_gas.clone()),
295 UncGas::from_gas(101)
296 );
297 assert_eq!(
298 another_gas.saturating_add(added_gas),
299 UncGas::from_gas(u64::MAX)
300 );
301 }
302
303 #[test]
304 fn saturating_sub_gas() {
305 let gas = UncGas::from_gas(100);
306 let rhs_gas = UncGas::from_gas(1);
307 let another_gas = UncGas::from_gas(u64::MIN);
308 assert_eq!(gas.saturating_sub(rhs_gas.clone()), UncGas::from_gas(99));
309 assert_eq!(
310 another_gas.saturating_sub(rhs_gas),
311 UncGas::from_gas(u64::MIN)
312 );
313 }
314
315 #[test]
316 fn saturating_mul_gas() {
317 let gas = UncGas::from_gas(2);
318 let rhs = 10;
319 let another_gas = u64::MAX;
320 assert_eq!(gas.saturating_mul(rhs), UncGas::from_gas(20));
321 assert_eq!(gas.saturating_mul(another_gas), UncGas::from_gas(u64::MAX));
322 }
323
324 #[test]
325 fn saturating_div_gas() {
326 let gas = UncGas::from_gas(10);
327 let rhs = 2;
328 let another_gas = 20;
329 assert_eq!(gas.saturating_div(rhs), UncGas::from_gas(5));
330 assert_eq!(gas.saturating_div(another_gas), UncGas::from_gas(0));
331 }
332}