1use std::fmt::Display;
2use std::str::FromStr;
3
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_with::{DeserializeAs, DisplayFromStr, SerializeAs, serde_as};
6use sui_sdk_types::GasCostSummary;
7
8fn decode_base58(base58: &str) -> Result<Vec<u8>, bs58::decode::Error> {
9 bs58::decode(base58).into_vec()
10}
11
12fn decode_base64_default(base64: &str) -> Result<Vec<u8>, base64ct::Error> {
14 <base64ct::Base64 as base64ct::Encoding>::decode_vec(base64)
21}
22
23pub(crate) fn encode_base64_default(bytes: impl AsRef<[u8]>) -> String {
25 <base64ct::Base64 as base64ct::Encoding>::encode_string(bytes.as_ref())
26}
27
28#[serde_as]
33#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy)]
34pub struct BigInt<T>(#[serde_as(as = "serde_with::DisplayFromStr")] T)
35where
36 T: Display + FromStr,
37 <T as FromStr>::Err: Display;
38
39impl<T> BigInt<T>
40where
41 T: Display + FromStr,
42 <T as FromStr>::Err: Display,
43{
44 pub fn into_inner(self) -> T {
45 self.0
46 }
47}
48
49impl<T> SerializeAs<T> for BigInt<T>
50where
51 T: Display + FromStr + Copy,
52 <T as FromStr>::Err: Display,
53{
54 fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
55 where
56 S: Serializer,
57 {
58 Self(*value).serialize(serializer)
59 }
60}
61
62impl<'de, T> DeserializeAs<'de, T> for BigInt<T>
63where
64 T: Display + FromStr + Copy,
65 <T as FromStr>::Err: Display,
66{
67 fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
68 where
69 D: Deserializer<'de>,
70 {
71 Ok(*Self::deserialize(deserializer)?)
72 }
73}
74
75impl<T> From<T> for BigInt<T>
76where
77 T: Display + FromStr,
78 <T as FromStr>::Err: Display,
79{
80 fn from(v: T) -> Self {
81 Self(v)
82 }
83}
84
85impl<T> std::ops::Deref for BigInt<T>
86where
87 T: Display + FromStr,
88 <T as FromStr>::Err: Display,
89{
90 type Target = T;
91
92 fn deref(&self) -> &Self::Target {
93 &self.0
94 }
95}
96
97impl<T> Display for BigInt<T>
98where
99 T: Display + FromStr,
100 <T as FromStr>::Err: Display,
101{
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 write!(f, "{}", self.0)
104 }
105}
106
107pub(crate) struct Base64orBase58;
113
114impl<T> SerializeAs<T> for Base64orBase58
115where
116 T: AsRef<[u8]>,
117{
118 fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
119 where
120 S: Serializer,
121 {
122 let encoded_string = encode_base64_default(value);
123 encoded_string.serialize(serializer)
124 }
125}
126
127impl<'de> DeserializeAs<'de, Vec<u8>> for Base64orBase58 {
128 fn deserialize_as<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
129 where
130 D: Deserializer<'de>,
131 {
132 let s = String::deserialize(deserializer)?;
133
134 decode_base64_default(&s)
135 .or_else(|_| decode_base58(&s))
136 .map_err(|_| serde::de::Error::custom("Deserialization failed"))
137 }
138}
139
140#[serde_as]
141#[derive(Serialize, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub(crate) struct GasCostSummaryJson {
144 #[serde_as(as = "DisplayFromStr")]
145 computation_cost: u64,
146 #[serde_as(as = "DisplayFromStr")]
147 storage_cost: u64,
148 #[serde_as(as = "DisplayFromStr")]
149 storage_rebate: u64,
150 #[serde_as(as = "DisplayFromStr")]
151 non_refundable_storage_fee: u64,
152}
153
154impl From<GasCostSummaryJson> for GasCostSummary {
155 fn from(
156 GasCostSummaryJson {
157 computation_cost,
158 storage_cost,
159 storage_rebate,
160 non_refundable_storage_fee,
161 }: GasCostSummaryJson,
162 ) -> Self {
163 Self {
164 computation_cost,
165 storage_cost,
166 storage_rebate,
167 non_refundable_storage_fee,
168 }
169 }
170}
171
172impl From<GasCostSummary> for GasCostSummaryJson {
173 fn from(
174 GasCostSummary {
175 computation_cost,
176 storage_cost,
177 storage_rebate,
178 non_refundable_storage_fee,
179 }: GasCostSummary,
180 ) -> Self {
181 Self {
182 computation_cost,
183 storage_cost,
184 storage_rebate,
185 non_refundable_storage_fee,
186 }
187 }
188}
189
190#[cfg(test)]
191mod test {
192 use super::*;
193
194 #[serde_as]
195 #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
196 #[serde(rename_all = "camelCase")]
197 struct Bcs {
198 #[serde_as(as = "Base64orBase58")]
199 bcs: Vec<u8>,
200 }
201
202 #[test]
203 fn new_bcs_format() {
204 let bytes = vec![0, 1, 2, 3, 4];
205 let untagged_base58 = r#"{"bcs":"12VfUX"}"#;
206 let tagged_base58 = r#"{"bcsEncoding":"base58","bcs":"12VfUX"}"#;
207 let tagged_base64 = r#"{"bcsEncoding":"base64","bcs":"AAECAwQ="}"#;
208
209 println!(
210 "{}",
211 serde_json::to_string(&Bcs { bcs: bytes.clone() }).unwrap()
212 );
213
214 assert_eq!(
215 bytes,
216 serde_json::from_str::<Bcs>(untagged_base58).unwrap().bcs
217 );
218 assert_eq!(
219 bytes,
220 serde_json::from_str::<Bcs>(tagged_base58).unwrap().bcs
221 );
222 assert_eq!(
223 bytes,
224 serde_json::from_str::<Bcs>(tagged_base64).unwrap().bcs
225 );
226
227 let name = serde_json::from_str::<Bcs>(tagged_base64).unwrap();
229 let json = serde_json::to_string(&name).unwrap();
230 let from_json = serde_json::from_str::<Bcs>(&json).unwrap();
231 assert_eq!(name, from_json);
232
233 let name = serde_json::from_str::<Bcs>(tagged_base58).unwrap();
235 let json = serde_json::to_string(&name).unwrap();
236 let from_json = serde_json::from_str::<Bcs>(&json).unwrap();
237 assert_eq!(name, from_json);
238 }
239}