1pub mod block;
18pub mod block_sums;
19pub mod committed;
20pub mod compact_block;
21pub mod hash;
22pub mod id;
23pub mod merkle_proof;
24pub mod pmmr;
25pub mod transaction;
26
27use crate::consensus::AIGC_BASE;
28use util::secp::pedersen::Commitment;
29
30pub use self::block::*;
31pub use self::block_sums::*;
32pub use self::committed::Committed;
33pub use self::compact_block::*;
34pub use self::id::ShortId;
35pub use self::pmmr::segment::*;
36pub use self::transaction::*;
37
38#[derive(Fail, Debug)]
40pub enum Error {
41 #[fail(display = "Amount string was invalid")]
43 InvalidAmountString,
44}
45
46pub fn amount_from_hr_string(amount: &str) -> Result<u64, Error> {
50 if amount.find(',').is_some() {
52 return Err(Error::InvalidAmountString);
53 }
54 let (aigcs, naigcs) = match amount.find('.') {
55 None => (parse_aigcs(amount)?, 0),
56 Some(pos) => {
57 let (gs, tail) = amount.split_at(pos);
58 (parse_aigcs(gs)?, parse_naigcs(&tail[1..])?)
59 }
60 };
61 Ok(aigcs * AIGC_BASE + naigcs)
62}
63
64fn parse_aigcs(amount: &str) -> Result<u64, Error> {
65 if amount == "" {
66 Ok(0)
67 } else {
68 amount
69 .parse::<u64>()
70 .map_err(|_| Error::InvalidAmountString)
71 }
72}
73
74lazy_static! {
75 static ref WIDTH: usize = (AIGC_BASE as f64).log(10.0) as usize + 1;
76}
77
78fn parse_naigcs(amount: &str) -> Result<u64, Error> {
79 let amount = if amount.len() > *WIDTH {
80 &amount[..*WIDTH]
81 } else {
82 amount
83 };
84 format!("{:0<width$}", amount, width = WIDTH)
85 .parse::<u64>()
86 .map_err(|_| Error::InvalidAmountString)
87}
88
89pub fn amount_to_hr_string(amount: u64, truncate: bool) -> String {
92 let amount = (amount as f64 / AIGC_BASE as f64) as f64;
93 let hr = format!("{:.*}", WIDTH, amount);
94 if truncate {
95 let nzeros = hr.chars().rev().take_while(|x| x == &'0').count();
96 if nzeros < *WIDTH {
97 return hr.trim_end_matches('0').to_string();
98 } else {
99 return format!("{}0", hr.trim_end_matches('0'));
100 }
101 }
102 hr
103}
104
105#[cfg(test)]
106mod test {
107 use super::*;
108
109 #[test]
110 pub fn test_amount_from_hr() {
111 assert!(50123456789 == amount_from_hr_string("50.123456789").unwrap());
112 assert!(50123456789 == amount_from_hr_string("50.1234567899").unwrap());
113 assert!(50 == amount_from_hr_string(".000000050").unwrap());
114 assert!(1 == amount_from_hr_string(".000000001").unwrap());
115 assert!(0 == amount_from_hr_string(".0000000009").unwrap());
116 assert!(500_000_000_000 == amount_from_hr_string("500").unwrap());
117 assert!(
118 5_000_000_000_000_000_000 == amount_from_hr_string("5000000000.00000000000").unwrap()
119 );
120 assert!(66_600_000_000 == amount_from_hr_string("66.6").unwrap());
121 assert!(66_000_000_000 == amount_from_hr_string("66.").unwrap());
122 }
123
124 #[test]
125 pub fn test_amount_to_hr() {
126 assert!("50.123456789" == amount_to_hr_string(50123456789, false));
127 assert!("50.123456789" == amount_to_hr_string(50123456789, true));
128 assert!("0.000000050" == amount_to_hr_string(50, false));
129 assert!("0.00000005" == amount_to_hr_string(50, true));
130 assert!("0.000000001" == amount_to_hr_string(1, false));
131 assert!("0.000000001" == amount_to_hr_string(1, true));
132 assert!("500.000000000" == amount_to_hr_string(500_000_000_000, false));
133 assert!("500.0" == amount_to_hr_string(500_000_000_000, true));
134 assert!("5000000000.000000000" == amount_to_hr_string(5_000_000_000_000_000_000, false));
135 assert!("5000000000.0" == amount_to_hr_string(5_000_000_000_000_000_000, true));
136 assert!("66.6" == amount_to_hr_string(66600000000, true));
137 }
138}