mod error;
mod utils;
mod trait_impls;
pub use self::error::UncTokenError;
pub use self::utils::DecimalNumberParsingError;
#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshDeserialize, borsh::BorshSerialize)
)]
#[cfg_attr(feature = "abi", derive(borsh::BorshSchema))]
#[repr(transparent)]
pub struct UncToken {
inner: u128,
}
const ONE_UNC: u128 = 10_u128.pow(24);
const ONE_MILLIUNC: u128 = 10_u128.pow(21);
impl UncToken {
pub const fn from_attounc(inner: u128) -> Self {
Self { inner }
}
pub const fn from_milliunc(inner: u128) -> Self {
Self {
inner: inner * ONE_MILLIUNC,
}
}
pub const fn from_unc(inner: u128) -> Self {
Self {
inner: inner * ONE_UNC,
}
}
pub const fn as_unc(&self) -> u128 {
self.inner / ONE_UNC
}
pub const fn as_milliunc(&self) -> u128 {
self.inner / ONE_MILLIUNC
}
pub const fn as_attounc(&self) -> u128 {
self.inner
}
pub const fn is_zero(&self) -> bool {
self.inner == 0
}
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
if let Some(unc) = self.as_attounc().checked_add(rhs.as_attounc()) {
Some(Self::from_attounc(unc))
} else {
None
}
}
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
if let Some(unc) = self.as_attounc().checked_sub(rhs.as_attounc()) {
Some(Self::from_attounc(unc))
} else {
None
}
}
pub const fn checked_mul(self, rhs: u128) -> Option<Self> {
if let Some(unc) = self.as_attounc().checked_mul(rhs) {
Some(Self::from_attounc(unc))
} else {
None
}
}
pub const fn checked_div(self, rhs: u128) -> Option<Self> {
if let Some(unc) = self.as_attounc().checked_div(rhs) {
Some(Self::from_attounc(unc))
} else {
None
}
}
pub const fn saturating_add(self, rhs: Self) -> Self {
UncToken::from_attounc(self.as_attounc().saturating_add(rhs.as_attounc()))
}
pub const fn saturating_sub(self, rhs: Self) -> Self {
UncToken::from_attounc(self.as_attounc().saturating_sub(rhs.as_attounc()))
}
pub const fn saturating_mul(self, rhs: u128) -> Self {
UncToken::from_attounc(self.as_attounc().saturating_mul(rhs))
}
pub const fn saturating_div(self, rhs: u128) -> Self {
if rhs == 0 {
return UncToken::from_attounc(0);
}
UncToken::from_attounc(self.as_attounc().saturating_div(rhs))
}
}
#[cfg(test)]
mod test {
use crate::UncToken;
#[test]
fn checked_add_tokens() {
let tokens = UncToken::from_attounc(u128::MAX - 3);
let any_tokens = UncToken::from_attounc(3);
let more_tokens = UncToken::from_attounc(4);
assert_eq!(
tokens.checked_add(any_tokens),
Some(UncToken::from_attounc(u128::MAX))
);
assert_eq!(tokens.checked_add(more_tokens), None);
}
#[test]
fn checked_sub_tokens() {
let tokens = UncToken::from_attounc(3);
let any_tokens = UncToken::from_attounc(1);
let more_tokens = UncToken::from_attounc(4);
assert_eq!(
tokens.checked_sub(any_tokens),
Some(UncToken::from_attounc(2))
);
assert_eq!(tokens.checked_sub(more_tokens), None);
}
#[test]
fn checked_mul_tokens() {
let tokens = UncToken::from_attounc(u128::MAX / 10);
assert_eq!(
tokens.checked_mul(10),
Some(UncToken::from_attounc(u128::MAX / 10 * 10))
);
assert_eq!(tokens.checked_mul(11), None);
}
#[test]
fn checked_div_tokens() {
let tokens = UncToken::from_attounc(10);
assert_eq!(tokens.checked_div(2), Some(UncToken::from_attounc(5)));
assert_eq!(tokens.checked_div(11), Some(UncToken::from_attounc(0)));
assert_eq!(tokens.checked_div(0), None);
}
#[test]
fn saturating_add_tokens() {
let tokens = UncToken::from_attounc(100);
let added_tokens = UncToken::from_attounc(1);
let another_tokens = UncToken::from_attounc(u128::MAX);
assert_eq!(
tokens.saturating_add(added_tokens.clone()),
UncToken::from_attounc(101)
);
assert_eq!(
another_tokens.saturating_add(added_tokens),
UncToken::from_attounc(u128::MAX)
);
}
#[test]
fn saturating_sub_tokens() {
let tokens = UncToken::from_attounc(100);
let rhs_tokens = UncToken::from_attounc(1);
let another_tokens = UncToken::from_attounc(u128::MIN);
assert_eq!(
tokens.saturating_sub(rhs_tokens.clone()),
UncToken::from_attounc(99)
);
assert_eq!(
another_tokens.saturating_sub(rhs_tokens),
UncToken::from_attounc(u128::MIN)
);
}
#[test]
fn saturating_mul_tokens() {
let tokens = UncToken::from_attounc(2);
let rhs = 10;
let another_tokens = u128::MAX;
assert_eq!(tokens.saturating_mul(rhs), UncToken::from_attounc(20));
assert_eq!(
tokens.saturating_mul(another_tokens),
UncToken::from_attounc(u128::MAX)
);
}
#[test]
fn saturating_div_tokens() {
let tokens = UncToken::from_attounc(10);
let rhs = 2;
let another_tokens = 20;
assert_eq!(tokens.saturating_div(rhs), UncToken::from_attounc(5));
assert_eq!(
tokens.saturating_div(another_tokens),
UncToken::from_attounc(0)
);
}
}