1use num_bigint::BigInt;
16use num_traits::Num;
17use serde_json::Value;
18
19use crate::error::{Error, Result};
20
21pub trait ValueExt {
26 fn to_u64(&self) -> Result<u64>;
29
30 fn to_big_int(&self) -> Result<BigInt>;
33
34 fn to_str(&self) -> Result<&str>;
36}
37
38impl ValueExt for Value {
39 fn to_u64(&self) -> Result<u64> {
40 match self {
41 Value::String(s) => parse_uint_auto(s),
42 Value::Number(n) => n
43 .as_u64()
44 .ok_or_else(|| Error::Other(format!("value {n} is not a u64"))),
45 other => Err(Error::Other(format!("cannot decode {other} as u64"))),
46 }
47 }
48
49 fn to_big_int(&self) -> Result<BigInt> {
50 match self {
51 Value::String(s) => {
52 let (radix, digits) = split_radix(s);
53 BigInt::from_str_radix(digits, radix)
54 .map_err(|_| Error::Other("invalid integer value".to_string()))
55 }
56 Value::Number(n) => {
57 if let Some(i) = n.as_i64() {
58 Ok(BigInt::from(i))
59 } else if let Some(u) = n.as_u64() {
60 Ok(BigInt::from(u))
61 } else {
62 BigInt::from_str_radix(&n.to_string(), 10)
65 .map_err(|_| Error::Other("invalid integer value".to_string()))
66 }
67 }
68 other => Err(Error::Other(format!("cannot decode {other} as integer"))),
69 }
70 }
71
72 fn to_str(&self) -> Result<&str> {
73 self.as_str()
74 .ok_or_else(|| Error::Other(format!("cannot decode {self} as string")))
75 }
76}
77
78fn parse_uint_auto(s: &str) -> Result<u64> {
82 let (radix, digits) = split_radix(s);
83 u64::from_str_radix(digits, radix).map_err(|e| Error::Other(e.to_string()))
84}
85
86fn split_radix(s: &str) -> (u32, &str) {
90 let bytes = s.as_bytes();
91 if bytes.len() >= 2 && bytes[0] == b'0' {
92 match bytes[1] {
93 b'x' | b'X' => return (16, &s[2..]),
94 b'o' | b'O' => return (8, &s[2..]),
95 b'b' | b'B' => return (2, &s[2..]),
96 b'0'..=b'7' => return (8, &s[1..]),
98 _ => {}
99 }
100 }
101 (10, s)
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use num_bigint::BigInt;
108 use serde_json::json;
109
110 #[test]
111 fn u64_variants() {
112 assert_eq!(json!("0x1b4").to_u64().unwrap(), 436);
113 assert_eq!(json!("100").to_u64().unwrap(), 100);
114 assert_eq!(json!(42).to_u64().unwrap(), 42);
115 assert_eq!(json!("0x0").to_u64().unwrap(), 0);
116 assert!(json!("notanumber").to_u64().is_err());
117 assert!(json!({}).to_u64().is_err());
118 }
119
120 #[test]
121 fn big_int_variants() {
122 assert_eq!(json!("0x1b4").to_big_int().unwrap(), BigInt::from(436));
123 assert_eq!(json!("100").to_big_int().unwrap(), BigInt::from(100));
124 assert_eq!(json!(42).to_big_int().unwrap(), BigInt::from(42));
125 assert_eq!(
126 json!("0xDE0B6B3A7640000").to_big_int().unwrap(),
127 BigInt::from(1_000_000_000_000_000_000u64)
128 );
129 assert!(json!("notanumber").to_big_int().is_err());
130 }
131
132 #[test]
133 fn str_variants() {
134 assert_eq!(json!("hello").to_str().unwrap(), "hello");
135 assert_eq!(json!("").to_str().unwrap(), "");
136 assert_eq!(json!("0xdead").to_str().unwrap(), "0xdead");
137 assert!(json!(123).to_str().is_err());
138 }
139}