1use std::str::FromStr;
2
3use af_sui_types::{Address as SuiAddress, encoding};
4use cynic::impl_scalar;
5use derive_more::with_trait::{AsRef, Deref, Display, From, Into};
6use serde::{Deserialize, Serialize};
7use serde_json::Value as Json;
8use serde_with::{Bytes, DisplayFromStr, base64, serde_as};
9
10use crate::schema;
11
12macro_rules! scalar_with_generics {
13 (
14 impl<$($T:ident),+> $schema:ident::$scalar:ident for $type_:ty $(where { $($bounds:tt)+ })?
15 ) => {
16 impl<$($T),+> cynic::schema::IsScalar<$schema::$scalar> for $type_
17 $(where $($bounds)+)?
18 {
19 type SchemaType = $schema::$scalar;
20 }
21
22 impl<$($T),+> cynic::coercions::CoercesTo<$schema::$scalar> for $type_
23 $(where $($bounds)+)?
24 {
25 }
26
27 impl<$($T),+> $schema::variable::Variable for $type_
28 $(where $($bounds)+)?
29 {
30 const TYPE: cynic::variables::VariableType = cynic::variables::VariableType::Named(
31 <$schema::$scalar as cynic::schema::NamedType>::NAME,
32 );
33 }
34 };
35}
36
37#[serde_as]
45#[derive(AsRef, Clone, Deref, Deserialize, Serialize)]
46#[as_ref(forward)]
47pub struct Base64<T>(#[serde_as(as = "base64::Base64")] T)
48where
49 T: AsRef<[u8]> + From<Vec<u8>>;
50
51impl<T> Base64<T>
52where
53 T: AsRef<[u8]> + From<Vec<u8>>,
54{
55 pub const fn new(value: T) -> Self {
56 Self(value)
57 }
58
59 pub fn into_inner(self) -> T {
60 self.0
61 }
62}
63
64impl<T> std::fmt::Debug for Base64<T>
65where
66 T: AsRef<[u8]> + From<Vec<u8>>,
67{
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(
70 f,
71 "Base64({})",
72 af_sui_types::encode_base64_default(&self.0)
73 )
74 }
75}
76
77scalar_with_generics! {
78 impl<T> schema::Base64 for Base64<T> where {
79 T: AsRef<[u8]> + From<Vec<u8>>,
80 }
81}
82
83#[serde_as]
84#[derive(AsRef, Clone, Debug, Deref, Deserialize, Serialize)]
85#[as_ref(forward)]
86#[serde(bound(deserialize = "T: for<'a> Deserialize<'a>"))]
87#[serde(bound(serialize = "T: Serialize"))]
88pub struct Base64Bcs<T>(#[serde_as(as = "encoding::Base64Bcs")] T);
89
90impl<T> Base64Bcs<T> {
91 pub fn into_inner(self) -> T {
92 self.0
93 }
94}
95
96scalar_with_generics! {
97 impl<T> schema::Base64 for Base64Bcs<T>
98}
99
100#[serde_as]
108#[derive(Clone, Debug, Display, Deserialize, Serialize)]
109pub struct BigInt<T>(#[serde_as(as = "DisplayFromStr")] T)
110where
111 T: Display + FromStr,
112 T::Err: Display;
113
114impl<T> BigInt<T>
115where
116 T: Display + FromStr,
117 T::Err: Display,
118{
119 pub fn into_inner(self) -> T {
120 self.0
121 }
122}
123
124scalar_with_generics! {
125 impl<T> schema::BigInt for BigInt<T>
126 where {
127 T: Display + FromStr,
128 T::Err: Display,
129 }
130}
131
132impl_scalar!(DateTime, schema::DateTime);
137
138#[serde_as]
141#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq, Into, Display, Deref)]
142pub struct DateTime(#[serde_as(as = "DisplayFromStr")] chrono::DateTime<chrono::Utc>);
143
144impl_scalar!(Json, schema::JSON);
149
150impl_scalar!(MoveData, schema::MoveData);
155
156#[serde_as]
173#[derive(Deserialize, Serialize, Clone, Debug)]
174pub enum MoveData {
175 Address(#[serde_as(as = "Bytes")] [u8; 32]),
176 #[serde(rename = "UID")]
177 Uid(#[serde_as(as = "Bytes")] [u8; 32]),
178 #[serde(rename = "ID")]
179 Id(#[serde_as(as = "Bytes")] [u8; 32]),
180 Bool(bool),
181 Number(String),
182 String(String),
183 Vector(Vec<MoveData>),
184 Option(Option<Box<MoveData>>),
185 Struct(Vec<MoveField>),
186 Variant(MoveVariant),
187}
188
189#[derive(Deserialize, Serialize, Clone, Debug)]
190pub struct MoveVariant {
191 name: String,
192 fields: Vec<MoveField>,
193}
194
195#[derive(Deserialize, Serialize, Clone, Debug)]
196pub struct MoveField {
197 pub name: String,
198 pub value: MoveData,
199}
200
201impl_scalar!(MoveTypeLayout, schema::MoveTypeLayout);
206
207#[doc = r#"The shape of a concrete Move Type (a type with all its type parameters instantiated with
208concrete types), corresponding to the following recursive type:
209
210type MoveTypeLayout =
211 "address"
212 | "bool"
213 | "u8" | "u16" | ... | "u256"
214 | { vector: MoveTypeLayout }
215 | {
216 struct: {
217 type: string,
218 fields: [{ name: string, layout: MoveTypeLayout }],
219 }
220 }
221 | { enum: [{
222 type: string,
223 variants: [{
224 name: string,
225 fields: [{ name: string, layout: MoveTypeLayout }],
226 }]
227 }]
228 }"#]
229#[derive(Clone, Debug, Deserialize, Serialize)]
230#[serde(rename_all = "camelCase")]
231pub enum MoveTypeLayout {
232 Address,
233 Bool,
234 U8,
235 U16,
236 U32,
237 U64,
238 U128,
239 U256,
240 Vector(Box<MoveTypeLayout>),
241 Struct(MoveStructLayout),
242 Enum(MoveEnumLayout),
243}
244
245#[derive(Clone, Debug, Deserialize, Serialize)]
246pub struct MoveEnumLayout {
247 pub variants: Vec<MoveVariantLayout>,
248}
249
250#[derive(Clone, Debug, Deserialize, Serialize)]
251pub struct MoveVariantLayout {
252 pub name: String,
253 pub layout: Vec<MoveFieldLayout>,
254}
255
256#[derive(Clone, Debug, Deserialize, Serialize)]
257pub struct MoveStructLayout {
258 #[serde(rename = "type")]
259 type_: String,
260 fields: Vec<MoveFieldLayout>,
261}
262
263#[derive(Clone, Debug, Deserialize, Serialize)]
264pub struct MoveFieldLayout {
265 name: String,
266 layout: MoveTypeLayout,
267}
268
269impl_scalar!(MoveTypeSignature, schema::MoveTypeSignature);
274
275#[doc = r#"The signature of a concrete Move Type (a type with all its type parameters instantiated
276with concrete types, that contains no references), corresponding to the following recursive type:
277
278type MoveTypeSignature =
279 "address"
280 | "bool"
281 | "u8" | "u16" | ... | "u256"
282 | { vector: MoveTypeSignature }
283 | {
284 datatype: {
285 package: string,
286 module: string,
287 type: string,
288 typeParameters: [MoveTypeSignature],
289 }
290 }"#]
291#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
292#[serde(rename_all = "camelCase")]
293pub enum MoveTypeSignature {
294 Address,
295 Bool,
296 U8,
297 U16,
298 U32,
299 U64,
300 U128,
301 U256,
302 Vector(Box<MoveTypeSignature>),
303 Datatype {
304 package: String,
305 module: String,
306 #[serde(rename = "type")]
307 type_: String,
308 #[serde(rename = "typeParameters")]
309 type_parameters: Vec<MoveTypeSignature>,
310 },
311}
312
313impl_scalar!(OpenMoveTypeSignature, schema::OpenMoveTypeSignature);
318
319#[doc = r#"The shape of an abstract Move Type (a type that can contain free type parameters, and can
320optionally be taken by reference), corresponding to the following recursive type:
321
322type OpenMoveTypeSignature = {
323 ref: ("&" | "&mut")?,
324 body: OpenMoveTypeSignatureBody,
325}
326
327type OpenMoveTypeSignatureBody =
328 "address"
329 | "bool"
330 | "u8" | "u16" | ... | "u256"
331 | { vector: OpenMoveTypeSignatureBody }
332 | {
333 datatype {
334 package: string,
335 module: string,
336 type: string,
337 typeParameters: [OpenMoveTypeSignatureBody]
338 }
339 }
340 | { typeParameter: number }"#]
341#[derive(Serialize, Deserialize, Clone, Debug)]
342pub struct OpenMoveTypeSignature {
343 #[serde(rename = "ref")]
344 ref_: Option<OpenMoveTypeReference>,
345 body: OpenMoveTypeSignatureBody,
346}
347
348#[derive(Serialize, Deserialize, Clone, Debug)]
349pub enum OpenMoveTypeReference {
350 #[serde(rename = "&")]
351 Immutable,
352
353 #[serde(rename = "&mut")]
354 Mutable,
355}
356
357#[derive(Serialize, Deserialize, Clone, Debug)]
358#[serde(rename_all = "camelCase")]
359pub enum OpenMoveTypeSignatureBody {
360 TypeParameter(u16),
361 Address,
362 Bool,
363 U8,
364 U16,
365 U32,
366 U64,
367 U128,
368 U256,
369 Vector(Box<OpenMoveTypeSignatureBody>),
370 Datatype {
371 package: String,
372 module: String,
373 #[serde(rename = "type")]
374 type_: String,
375 #[serde(rename = "typeParameters")]
376 type_parameters: Vec<OpenMoveTypeSignatureBody>,
377 },
378}
379
380impl_scalar!(SuiAddress, schema::SuiAddress);
388
389impl_scalar!(Digest, schema::String);
394impl_scalar!(TypeTag, schema::String);
395
396#[derive(Clone, Debug, Deserialize)]
397pub struct Digest(pub af_sui_types::Digest);
398
399#[serde_as]
401#[derive(Clone, Debug, Deserialize, Serialize)]
402pub struct TypeTag(#[serde_as(as = "DisplayFromStr")] pub af_sui_types::TypeTag);
403
404impl_scalar!(af_sui_types::Version, schema::UInt53);
409
410#[cfg(test)]
415mod tests {
416 use color_eyre::Result;
417
418 use super::*;
419
420 const MOVE_TYPE_SIGNATURE_JSON: &str = r#"{
450 "datatype": {
451 "package": "0xfd6f306bb2f8dce24dd3d4a9bdc51a46e7c932b15007d73ac0cfb38c15de0fea",
452 "module": "events",
453 "type": "DepositedCollateral",
454 "typeParameters": []
455 }
456 }"#;
457
458 #[test]
459 fn move_type_signature_serde() -> Result<()> {
460 let sig: MoveTypeSignature = serde_json::from_str(MOVE_TYPE_SIGNATURE_JSON)?;
461 assert_eq!(
462 sig,
463 MoveTypeSignature::Datatype {
464 package: "0xfd6f306bb2f8dce24dd3d4a9bdc51a46e7c932b15007d73ac0cfb38c15de0fea"
465 .into(),
466 module: "events".into(),
467 type_: "DepositedCollateral".into(),
468 type_parameters: vec![],
469 }
470 );
471 Ok(())
472 }
473}