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}