ckb_sdk/types/
human_capacity.rs1use std::fmt;
2use std::ops::Deref;
3use std::str::FromStr;
4
5use crate::constants::ONE_CKB;
6
7#[derive(Default, Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
8pub struct HumanCapacity(pub u64);
9
10impl From<u64> for HumanCapacity {
11 fn from(value: u64) -> HumanCapacity {
12 HumanCapacity(value)
13 }
14}
15
16impl From<HumanCapacity> for u64 {
17 fn from(value: HumanCapacity) -> u64 {
18 value.0
19 }
20}
21
22impl Deref for HumanCapacity {
23 type Target = u64;
24 fn deref(&self) -> &u64 {
25 &self.0
26 }
27}
28
29impl FromStr for HumanCapacity {
30 type Err = String;
31 fn from_str(input: &str) -> Result<Self, Self::Err> {
32 let parts = input.trim().split('.').collect::<Vec<_>>();
33 let mut capacity = ONE_CKB
34 * parts
35 .first()
36 .ok_or_else(|| "Missing input".to_owned())?
37 .parse::<u64>()
38 .map_err(|err| err.to_string())?;
39 if let Some(shannon_str) = parts.get(1) {
40 let shannon_str = shannon_str.trim();
41 if shannon_str.len() > 8 {
42 return Err(format!("decimal part too long: {}", shannon_str.len()));
43 }
44 let mut shannon = shannon_str.parse::<u32>().map_err(|err| err.to_string())?;
45 for _ in 0..(8 - shannon_str.len()) {
46 shannon *= 10;
47 }
48 capacity += u64::from(shannon);
49 }
50 Ok(capacity.into())
51 }
52}
53
54impl fmt::Display for HumanCapacity {
55 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
56 let ckb_part = self.0 / ONE_CKB;
57 let shannon_part = self.0 % ONE_CKB;
58 let shannon_part_string = format!("{:0>8}", shannon_part);
59 let mut base = 10;
60 let mut suffix_zero = 7;
61 for i in 0..8 {
62 if shannon_part % base > 0 {
63 suffix_zero = i;
64 break;
65 }
66 base *= 10;
67 }
68 if f.alternate() {
69 write!(
70 f,
71 "{}.{} (CKB)",
72 ckb_part,
73 &shannon_part_string[..(8 - suffix_zero)]
74 )
75 } else {
76 write!(
77 f,
78 "{}.{}",
79 ckb_part,
80 &shannon_part_string[..(8 - suffix_zero)]
81 )
82 }
83 }
84}
85
86#[cfg(test)]
87mod test {
88 use super::*;
89
90 #[test]
91 fn test_human_capacity() {
92 for (input, capacity) in &[
93 ("3.0", 3 * ONE_CKB),
94 ("300.0", 300 * ONE_CKB),
95 ("3.56", 356_000_000),
96 ("3.0056", 300_560_000),
97 ("3.10056", 310_056_000),
98 ("3.10056123", 310_056_123),
99 ("0.0056", 560_000),
100 ("0.10056123", 10_056_123),
101 ("12345.234", 12345 * ONE_CKB + 23_400_000),
102 ("12345.23442222", 12345 * ONE_CKB + 23_442_222),
103 ] {
104 assert_eq!(HumanCapacity::from_str(input).unwrap(), (*capacity).into());
105 assert_eq!(HumanCapacity::from(*capacity).to_string(), *input);
106 }
107
108 assert_eq!(
110 HumanCapacity::from_str("12345"),
111 Ok(HumanCapacity::from(12345 * ONE_CKB))
112 );
113
114 assert!(HumanCapacity::from_str("12345.234422224").is_err());
116 assert!(HumanCapacity::from_str("abc.234422224").is_err());
117 assert!(HumanCapacity::from_str("abc.abc").is_err());
118 assert!(HumanCapacity::from_str("abc").is_err());
119 assert!(HumanCapacity::from_str("-234").is_err());
120 assert!(HumanCapacity::from_str("-234.3").is_err());
121 }
122}