sui_graphql_rpc/types/
big_int.rs1use std::str::FromStr;
5
6use async_graphql::*;
7use move_core_types::u256::U256;
8use serde::{Deserialize, Serialize};
9
10#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
11#[serde(transparent)]
12pub(crate) struct BigInt(String);
13
14#[derive(thiserror::Error, Debug, PartialEq, Eq)]
15#[error("The provided string is not a number")]
16pub(crate) struct NotANumber;
17
18#[Scalar(use_type_description = true)]
19impl ScalarType for BigInt {
20 fn parse(value: Value) -> InputValueResult<Self> {
21 match value {
22 Value::String(s) => BigInt::from_str(&s)
23 .map_err(|_| InputValueError::custom("Not a number".to_string())),
24 _ => Err(InputValueError::expected_type(value)),
25 }
26 }
27
28 fn to_value(&self) -> Value {
29 Value::String(self.0.clone())
30 }
31}
32
33impl Description for BigInt {
34 fn description() -> &'static str {
35 "String representation of an arbitrary width, possibly signed integer."
36 }
37}
38
39impl FromStr for BigInt {
40 type Err = NotANumber;
41
42 fn from_str(s: &str) -> Result<Self, Self::Err> {
43 let mut r = s;
44 let mut signed = false;
45 if let Some(suffix) = s.strip_prefix('-') {
47 r = suffix;
48 signed = true;
49 }
50 r = r.trim_start_matches('0');
51
52 if r.is_empty() {
53 Ok(BigInt("0".to_string()))
54 } else if r.chars().all(|c| c.is_ascii_digit()) {
55 Ok(BigInt(format!("{}{}", if signed { "-" } else { "" }, r)))
56 } else {
57 Err(NotANumber)
58 }
59 }
60}
61
62macro_rules! impl_From {
63 ($($t:ident),*) => {
64 $(impl From<$t> for BigInt {
65 fn from(value: $t) -> Self {
66 BigInt(value.to_string())
67 }
68 })*
69 }
70}
71
72impl_From!(u8, u16, u32, i64, u64, i128, u128, U256);
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn from_value() {
80 assert_eq!(BigInt::from_str("123").unwrap(), BigInt("123".to_string()));
81 assert_eq!(
82 BigInt::from_str("-123").unwrap(),
83 BigInt("-123".to_string())
84 );
85 assert_eq!(
86 BigInt::from_str("00233").unwrap(),
87 BigInt("233".to_string())
88 );
89 assert_eq!(BigInt::from_str("0").unwrap(), BigInt("0".to_string()));
90 assert_eq!(BigInt::from_str("-0").unwrap(), BigInt("0".to_string()));
91 assert_eq!(BigInt::from_str("000").unwrap(), BigInt("0".to_string()));
92 assert_eq!(BigInt::from_str("-000").unwrap(), BigInt("0".to_string()));
93
94 assert!(BigInt::from_str("123a").is_err());
95 assert!(BigInt::from_str("a123").is_err());
96 assert!(BigInt::from_str("123-").is_err());
97 assert!(BigInt::from_str(" 123").is_err());
98 }
99
100 #[test]
101 fn from_primitives() {
102 assert_eq!(BigInt::from(123u8), BigInt("123".to_string()));
103
104 assert_eq!(BigInt::from(12_345u16), BigInt("12345".to_string()));
105
106 assert_eq!(BigInt::from(123_456u32), BigInt("123456".to_string()));
107
108 assert_eq!(
109 BigInt::from(-12_345_678_901i64),
110 BigInt("-12345678901".to_string()),
111 );
112
113 assert_eq!(
114 BigInt::from(12_345_678_901u64),
115 BigInt("12345678901".to_string()),
116 );
117
118 assert_eq!(
119 BigInt::from(-123_456_789_012_345_678_901i128),
120 BigInt("-123456789012345678901".to_string()),
121 );
122
123 assert_eq!(
124 BigInt::from(123_456_789_012_345_678_901u128),
125 BigInt("123456789012345678901".to_string()),
126 );
127
128 assert_eq!(
129 BigInt::from(U256::from_str("12345678901234567890123456789012345678901").unwrap()),
130 BigInt("12345678901234567890123456789012345678901".to_string())
131 );
132
133 assert_eq!(BigInt::from(1000i64 - 1200i64), BigInt("-200".to_string()));
134 assert_eq!(BigInt::from(-1200i64), BigInt("-1200".to_string()));
135 }
136}