aigc_core/
core.rs

1// Copyright 2021 The Aigc Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Core types
16
17pub 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/// Common errors
39#[derive(Fail, Debug)]
40pub enum Error {
41	/// Human readable represenation of amount is invalid
42	#[fail(display = "Amount string was invalid")]
43	InvalidAmountString,
44}
45
46/// Common method for parsing an amount from human-readable, and converting
47/// to internally-compatible u64
48
49pub fn amount_from_hr_string(amount: &str) -> Result<u64, Error> {
50	// no i18n yet, make sure we use '.' as the separator
51	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
89/// Common method for converting an amount to a human-readable string
90
91pub 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}