pub mod constants;
mod error;
pub use error::AmountError;
use std::cmp::Ordering;
use std::fmt::{self};
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Denomination {
AmountMegaCoin,
AmountKiloCoin,
AmountCoin,
AmountMilliCoin,
AmountMicroCoin,
AmountAtom,
}
impl Denomination {
pub fn precision(self) -> i32 {
match self {
Denomination::AmountMegaCoin => 6,
Denomination::AmountKiloCoin => 3,
Denomination::AmountCoin => 0,
Denomination::AmountMilliCoin => -3,
Denomination::AmountMicroCoin => -6,
Denomination::AmountAtom => -8,
}
}
}
impl fmt::Display for Denomination {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
Denomination::AmountMegaCoin => "MDCR",
Denomination::AmountKiloCoin => "kDCR",
Denomination::AmountCoin => "DCR",
Denomination::AmountMilliCoin => "mDCR",
Denomination::AmountMicroCoin => "μDCR",
Denomination::AmountAtom => "Atom",
})
}
}
fn round(f: f64) -> Amount {
if f < 0.0 {
return Amount((f - 0.5) as i64);
}
Amount((f + 0.5) as i64)
}
pub fn new(amount: f64) -> Result<Amount, AmountError> {
if amount.is_nan() || amount.is_infinite() {
return Err(AmountError::InvalidCoinAmount);
}
Ok(round(amount * constants::ATOMS_PER_COIN))
}
pub struct Amount(i64);
impl Amount {
pub fn to_unit(&self, denom: Denomination) -> f64 {
self.0 as f64 / 10.0f64.powi(denom.precision() + 8)
}
pub fn to_coin(&self) -> f64 {
self.to_unit(Denomination::AmountCoin)
}
pub fn format(&self, denomination: Denomination) -> String {
format!("{} {}", self.to_unit(denomination), denomination)
}
pub fn mul_f64(&self, f: f64) -> Amount {
round(self.0 as f64 * f)
}
}
impl ToString for Amount {
fn to_string(&self) -> String {
self.format(Denomination::AmountCoin)
}
}
impl std::cmp::PartialOrd for Amount {
fn partial_cmp(&self, other: &Amount) -> Option<Ordering> {
let amount = self.to_coin();
let other_amount = other.to_coin();
if amount > other_amount {
Some(Ordering::Greater)
} else if amount < other_amount {
Some(Ordering::Less)
} else {
Some(Ordering::Equal)
}
}
}
impl std::cmp::PartialEq for Amount {
fn eq(&self, other: &Self) -> bool {
self.to_coin() == other.to_coin()
}
}
impl std::cmp::Eq for Amount {}
impl std::cmp::Ord for Amount {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
pub struct AmountSorter(Vec<Amount>);
impl AmountSorter {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn swap(&mut self, i: usize, j: usize) {
self.0.swap(i, j)
}
pub fn less(&self, i: usize, j: usize) -> bool {
self.0[i] < self.0[j]
}
}