cs_mwc_bch/util/
amount.rs

1//! Functions to convert between different bitcoin denominations
2
3use std::fmt;
4use util::{Error, Result};
5
6/// Denomination of a bitcoin amount
7#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
8pub enum Units {
9    /// One bitcoin
10    Bch,
11    /// One millionth of a bitcoin
12    Bits,
13    /// One hundred millionth of a bitcoin
14    Sats,
15}
16
17impl Units {
18    pub fn parse(s: &str) -> Result<Units> {
19        let s = s.to_lowercase();
20        if s == "bch" || s == "bitcoin" {
21            return Ok(Units::Bch);
22        } else if s == "bit" || s == "bits" {
23            return Ok(Units::Bits);
24        } else if s == "sat" || s == "sats" {
25            return Ok(Units::Sats);
26        } else {
27            let msg = format!("Unknown units: {}", s);
28            return Err(Error::BadArgument(msg));
29        }
30    }
31}
32
33/// An amount of bitcoin in satoshis
34#[derive(PartialEq, Eq, Hash, Clone, Copy)]
35pub struct Amount(pub i64);
36
37impl Amount {
38    /// Creates from a given amount and unit
39    pub fn from(amount: f64, units: Units) -> Amount {
40        match units {
41            Units::Bch => Amount((amount * 100_000_000.) as i64),
42            Units::Bits => Amount((amount * 100.) as i64),
43            Units::Sats => Amount(amount as i64),
44        }
45    }
46
47    /// Converts the amount to a given unit
48    pub fn to(&self, units: Units) -> f64 {
49        match units {
50            Units::Bch => self.0 as f64 / 100_000_000.,
51            Units::Bits => self.0 as f64 / 100.,
52            Units::Sats => self.0 as f64,
53        }
54    }
55}
56impl fmt::Debug for Amount {
57    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58        f.write_str(&format!("{} bch", self.to(Units::Bch)))
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn from_to() {
68        assert!(Amount(0).to(Units::Bch) == 0.);
69        assert!(Amount(0).to(Units::Bits) == 0.);
70        assert!(Amount(0).to(Units::Sats) == 0.);
71
72        assert!(Amount(1).to(Units::Bch) == 0.00000001);
73        assert!(Amount(1).to(Units::Bits) == 0.01);
74        assert!(Amount(1).to(Units::Sats) == 1.);
75
76        assert!(Amount(9).to(Units::Bch) == 0.00000009);
77        assert!(Amount(9).to(Units::Bits) == 0.09);
78        assert!(Amount(9).to(Units::Sats) == 9.);
79
80        assert!(Amount::from(0., Units::Bch).0 == 0);
81        assert!(Amount::from(0., Units::Bits).0 == 0);
82        assert!(Amount::from(0., Units::Sats).0 == 0);
83
84        assert!(Amount::from(1., Units::Bch).0 == 100_000_000);
85        assert!(Amount::from(1., Units::Bits).0 == 100);
86        assert!(Amount::from(1., Units::Sats).0 == 1);
87
88        assert!(Amount::from(9., Units::Bch).0 == 900_000_000);
89        assert!(Amount::from(9., Units::Bits).0 == 900);
90        assert!(Amount::from(9., Units::Sats).0 == 9);
91
92        assert!(Amount::from(1., Units::Bch).to(Units::Bch) == 1.);
93        assert!(Amount::from(0.01, Units::Bch).to(Units::Bch) == 0.01);
94        assert!(Amount::from(99., Units::Bits).to(Units::Bits) == 99.);
95        assert!(Amount::from(1., Units::Sats).to(Units::Sats) == 1.);
96    }
97}