unc_token/
lib.rs

1//! A `UncToken` type to represent a value of Near.
2//!
3//! Each `UncTokens` is composed of a floating point number of tokens where each integer unit is equal to one atto-Near.
4//! `UncToken` is implementing the common trait `FromStr`. Also, have utils function to parse from `str` into `u128`.
5//!
6//! # Examples
7//! ```
8//! use unc_token::UncToken;
9//!
10//! let one_unc = UncToken::from_attounc(10_u128.pow(24));
11//! assert_eq!(one_unc, UncToken::from_unc(1));
12//! assert_eq!(one_unc, UncToken::from_milliunc(1000));
13//! ```
14//!
15//! # Crate features
16//!
17//! * **borsh** (optional) -
18//!   When enabled allows `UncToken` to serialized and deserialized by `borsh`.
19//!
20//! * **serde** (optional) -
21//!   When enabled allows `UncToken` to serialized and deserialized by `serde`.
22//!
23//! * **schemars** (optional) -
24//!  Implements `schemars::JsonSchema` for `UncToken`.
25//!
26//! * **interactive-clap** (optional) -
27//!  Implements `interactive_clap::ToCli` for `UncToken`.
28mod error;
29
30mod utils;
31
32mod trait_impls;
33
34pub use self::error::UncTokenError;
35pub use self::utils::DecimalNumberParsingError;
36
37#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
38#[cfg_attr(
39    feature = "borsh",
40    derive(borsh::BorshDeserialize, borsh::BorshSerialize)
41)]
42#[cfg_attr(feature = "abi", derive(borsh::BorshSchema))]
43#[repr(transparent)]
44pub struct UncToken {
45    inner: u128,
46}
47
48const ONE_UNC: u128 = 10_u128.pow(24);
49const ONE_MILLIUNC: u128 = 10_u128.pow(21);
50
51impl UncToken {
52    /// `from_attounc` is a function that takes value by a number of atto-unc.
53    /// # Examples
54    /// ```
55    /// use unc_token::UncToken;
56    /// assert_eq!( UncToken::from_attounc(10u128.pow(21)), UncToken::from_milliunc(1))
57    /// ```
58    pub const fn from_attounc(inner: u128) -> Self {
59        Self { inner }
60    }
61
62    /// `from_milliunc` is a function that takes value by a number of mili-unc and converts it to an equivalent to the atto-unc.
63    /// # Examples
64    /// ```
65    /// use unc_token::UncToken;
66    /// assert_eq!(UncToken::from_milliunc(1), UncToken::from_attounc(10u128.pow(21)))
67    /// ```
68    pub const fn from_milliunc(inner: u128) -> Self {
69        Self {
70            inner: inner * ONE_MILLIUNC,
71        }
72    }
73
74    /// `from_unc` is a function that takes value by a number of unc and converts it to an equivalent to the atto-unc.
75    /// # Examples
76    /// ```
77    /// use unc_token::UncToken;
78    /// assert_eq!(UncToken::from_unc(1), UncToken::from_attounc(10u128.pow(24)))
79    /// ```
80    pub const fn from_unc(inner: u128) -> Self {
81        Self {
82            inner: inner * ONE_UNC,
83        }
84    }
85
86    /// `as_unc` is a function that converts number of atto-unc to an equivalent to the unc.
87    /// # Examples
88    /// ```
89    /// use unc_token::UncToken;
90    /// assert_eq!(UncToken::from_attounc(10u128.pow(24)).as_unc(), 1)
91    /// ```
92    pub const fn as_unc(&self) -> u128 {
93        self.inner / ONE_UNC
94    }
95
96    /// `as_milliunc` is a function that converts number of atto-unc to an equivalent to the mili-unc.
97    /// # Examples
98    /// ```
99    /// use unc_token::UncToken;
100    /// assert_eq!(UncToken::from_attounc(10u128.pow(21)).as_milliunc(), 1)
101    /// ```
102    pub const fn as_milliunc(&self) -> u128 {
103        self.inner / ONE_MILLIUNC
104    }
105
106    /// `as_attounc` is a function that shows a number of atto-unc.
107    /// # Examples
108    /// ```
109    /// use unc_token::UncToken;
110    /// assert_eq!(UncToken::from_attounc(10).as_attounc(), 10)
111    /// ```
112    pub const fn as_attounc(&self) -> u128 {
113        self.inner
114    }
115
116    /// `is_zero` is a boolian function that checks `UncToken`
117    /// if a `UncToken` inner is zero, returns true.
118    /// # Examples
119    /// ```
120    /// use unc_token::UncToken;
121    /// assert_eq!(UncToken::from_attounc(0).is_zero(), true)
122    /// ```
123    pub const fn is_zero(&self) -> bool {
124        self.inner == 0
125    }
126
127    /// Checked integer addition. Computes self + rhs, returning None if overflow occurred.
128    ///
129    /// # Examples
130    /// ```
131    /// use unc_token::UncToken;
132    /// use std::u128;
133    /// assert_eq!(UncToken::from_attounc(u128::MAX -2).checked_add(UncToken::from_attounc(2)), Some(UncToken::from_attounc(u128::MAX)));
134    /// assert_eq!(UncToken::from_attounc(u128::MAX -2).checked_add(UncToken::from_attounc(3)), None);
135    /// ```
136    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
137        if let Some(unc) = self.as_attounc().checked_add(rhs.as_attounc()) {
138            Some(Self::from_attounc(unc))
139        } else {
140            None
141        }
142    }
143
144    /// Checked integer subtraction. Computes self - rhs, returning None if overflow occurred.
145    ///
146    /// # Examples
147    /// ```
148    /// use unc_token::UncToken;
149    /// assert_eq!(UncToken::from_attounc(2).checked_sub(UncToken::from_attounc(2)), Some(UncToken::from_attounc(0)));
150    /// assert_eq!(UncToken::from_attounc(2).checked_sub(UncToken::from_attounc(3)), None);
151    /// ```
152    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
153        if let Some(unc) = self.as_attounc().checked_sub(rhs.as_attounc()) {
154            Some(Self::from_attounc(unc))
155        } else {
156            None
157        }
158    }
159
160    /// Checked integer multiplication. Computes self * rhs, returning None if overflow occurred.
161    ///
162    /// # Examples
163    /// ```
164    /// use unc_token::UncToken;
165    /// use std::u128;
166    /// assert_eq!(UncToken::from_attounc(2).checked_mul(2), Some(UncToken::from_attounc(4)));
167    /// assert_eq!(UncToken::from_attounc(u128::MAX).checked_mul(2), None)
168    pub const fn checked_mul(self, rhs: u128) -> Option<Self> {
169        if let Some(unc) = self.as_attounc().checked_mul(rhs) {
170            Some(Self::from_attounc(unc))
171        } else {
172            None
173        }
174    }
175
176    /// Checked integer division. Computes self / rhs, returning None if rhs == 0.
177    ///
178    /// # Examples
179    /// ```
180    /// use unc_token::UncToken;
181    /// assert_eq!(UncToken::from_attounc(10).checked_div(2), Some(UncToken::from_attounc(5)));
182    /// assert_eq!(UncToken::from_attounc(2).checked_div(0), None);
183    /// ```
184    pub const fn checked_div(self, rhs: u128) -> Option<Self> {
185        if let Some(unc) = self.as_attounc().checked_div(rhs) {
186            Some(Self::from_attounc(unc))
187        } else {
188            None
189        }
190    }
191
192    /// Saturating integer addition. Computes self + rhs, saturating at the numeric bounds instead of overflowing.
193    ///
194    /// # Examples
195    /// ```
196    /// use unc_token::UncToken;
197    /// assert_eq!(UncToken::from_attounc(5).saturating_add(UncToken::from_attounc(5)), UncToken::from_attounc(10));
198    /// assert_eq!(UncToken::from_attounc(u128::MAX).saturating_add(UncToken::from_attounc(1)), UncToken::from_attounc(u128::MAX));
199    /// ```
200    pub const fn saturating_add(self, rhs: Self) -> Self {
201        UncToken::from_attounc(self.as_attounc().saturating_add(rhs.as_attounc()))
202    }
203
204    /// Saturating integer subtraction. Computes self - rhs, saturating at the numeric bounds instead of overflowing.
205    ///
206    /// # Examples
207    /// ```
208    /// use unc_token::UncToken;
209    /// assert_eq!(UncToken::from_attounc(5).saturating_sub(UncToken::from_attounc(2)), UncToken::from_attounc(3));
210    /// assert_eq!(UncToken::from_attounc(1).saturating_sub(UncToken::from_attounc(2)), UncToken::from_attounc(0));
211    /// ```
212    pub const fn saturating_sub(self, rhs: Self) -> Self {
213        UncToken::from_attounc(self.as_attounc().saturating_sub(rhs.as_attounc()))
214    }
215
216    /// Saturating integer multiplication. Computes self * rhs, saturating at the numeric bounds instead of overflowing.
217    ///
218    /// # Examples
219    /// ```
220    /// use unc_token::UncToken;
221    /// use std::u128;
222    /// assert_eq!(UncToken::from_attounc(2).saturating_mul(5), UncToken::from_attounc(10));
223    /// assert_eq!(UncToken::from_attounc(u128::MAX).saturating_mul(2), UncToken::from_attounc(u128::MAX));
224    /// ```
225    pub const fn saturating_mul(self, rhs: u128) -> Self {
226        UncToken::from_attounc(self.as_attounc().saturating_mul(rhs))
227    }
228
229    /// Saturating integer division. Computes self / rhs, saturating at the numeric bounds instead of overflowing.
230    ///
231    /// # Examples
232    /// ```
233    /// use unc_token::UncToken;
234    /// assert_eq!(UncToken::from_attounc(10).saturating_div(2), UncToken::from_attounc(5));
235    /// assert_eq!(UncToken::from_attounc(10).saturating_div(0), UncToken::from_attounc(0))
236    /// ```
237    pub const fn saturating_div(self, rhs: u128) -> Self {
238        if rhs == 0 {
239            return UncToken::from_attounc(0);
240        }
241        UncToken::from_attounc(self.as_attounc().saturating_div(rhs))
242    }
243}
244
245#[cfg(test)]
246mod test {
247    use crate::UncToken;
248
249    #[test]
250    fn checked_add_tokens() {
251        let tokens = UncToken::from_attounc(u128::MAX - 3);
252        let any_tokens = UncToken::from_attounc(3);
253        let more_tokens = UncToken::from_attounc(4);
254        assert_eq!(
255            tokens.checked_add(any_tokens),
256            Some(UncToken::from_attounc(u128::MAX))
257        );
258        assert_eq!(tokens.checked_add(more_tokens), None);
259    }
260
261    #[test]
262    fn checked_sub_tokens() {
263        let tokens = UncToken::from_attounc(3);
264        let any_tokens = UncToken::from_attounc(1);
265        let more_tokens = UncToken::from_attounc(4);
266        assert_eq!(
267            tokens.checked_sub(any_tokens),
268            Some(UncToken::from_attounc(2))
269        );
270        assert_eq!(tokens.checked_sub(more_tokens), None);
271    }
272
273    #[test]
274    fn checked_mul_tokens() {
275        let tokens = UncToken::from_attounc(u128::MAX / 10);
276        assert_eq!(
277            tokens.checked_mul(10),
278            Some(UncToken::from_attounc(u128::MAX / 10 * 10))
279        );
280        assert_eq!(tokens.checked_mul(11), None);
281    }
282
283    #[test]
284    fn checked_div_tokens() {
285        let tokens = UncToken::from_attounc(10);
286        assert_eq!(tokens.checked_div(2), Some(UncToken::from_attounc(5)));
287        assert_eq!(tokens.checked_div(11), Some(UncToken::from_attounc(0)));
288        assert_eq!(tokens.checked_div(0), None);
289    }
290
291    #[test]
292    fn saturating_add_tokens() {
293        let tokens = UncToken::from_attounc(100);
294        let added_tokens = UncToken::from_attounc(1);
295        let another_tokens = UncToken::from_attounc(u128::MAX);
296        assert_eq!(
297            tokens.saturating_add(added_tokens.clone()),
298            UncToken::from_attounc(101)
299        );
300        assert_eq!(
301            another_tokens.saturating_add(added_tokens),
302            UncToken::from_attounc(u128::MAX)
303        );
304    }
305
306    #[test]
307    fn saturating_sub_tokens() {
308        let tokens = UncToken::from_attounc(100);
309        let rhs_tokens = UncToken::from_attounc(1);
310        let another_tokens = UncToken::from_attounc(u128::MIN);
311        assert_eq!(
312            tokens.saturating_sub(rhs_tokens.clone()),
313            UncToken::from_attounc(99)
314        );
315        assert_eq!(
316            another_tokens.saturating_sub(rhs_tokens),
317            UncToken::from_attounc(u128::MIN)
318        );
319    }
320
321    #[test]
322    fn saturating_mul_tokens() {
323        let tokens = UncToken::from_attounc(2);
324        let rhs = 10;
325        let another_tokens = u128::MAX;
326        assert_eq!(tokens.saturating_mul(rhs), UncToken::from_attounc(20));
327        assert_eq!(
328            tokens.saturating_mul(another_tokens),
329            UncToken::from_attounc(u128::MAX)
330        );
331    }
332
333    #[test]
334    fn saturating_div_tokens() {
335        let tokens = UncToken::from_attounc(10);
336        let rhs = 2;
337        let another_tokens = 20;
338        assert_eq!(tokens.saturating_div(rhs), UncToken::from_attounc(5));
339        assert_eq!(
340            tokens.saturating_div(another_tokens),
341            UncToken::from_attounc(0)
342        );
343    }
344}