1use std::fmt::Debug;
16use std::hash::Hash;
17use std::str::FromStr;
18
19pub use af_move_type_derive::MoveStruct;
20use af_sui_types::u256::U256;
21use af_sui_types::{Address, Identifier, StructTag, TypeTag};
22use serde::{Deserialize, Serialize};
23
24pub mod any;
25#[doc(hidden)]
26pub mod external;
27pub mod otw;
28mod primitives;
29mod string;
30pub mod vector;
31
32pub use self::primitives::{
33 AddressTypeTag, BoolTypeTag, U8TypeTag, U16TypeTag, U32TypeTag, U64TypeTag, U128TypeTag,
34 U256TypeTag,
35};
36pub use self::string::StringTypeTag;
37
38pub trait MoveType:
44 Clone
45 + std::fmt::Debug
46 + std::fmt::Display
47 + for<'de> Deserialize<'de>
48 + Serialize
49 + PartialEq
50 + Eq
51 + std::hash::Hash
52{
53 type TypeTag: MoveTypeTag;
54
55 fn from_bcs(bytes: &[u8]) -> bcs::Result<Self> {
57 bcs::from_bytes(bytes)
58 }
59
60 fn into_bcs(self) -> bcs::Result<Vec<u8>> {
62 bcs::to_bytes(&self)
63 }
64
65 fn to_bcs(&self) -> bcs::Result<Vec<u8>> {
67 bcs::to_bytes(self)
68 }
69
70 fn into_json(self) -> serde_json::Value {
72 let mut value = serde_json::json!(self);
73 number_to_string_value_recursive(&mut value);
75 value
76 }
77
78 fn to_json(&self) -> serde_json::Value {
85 let mut value = serde_json::json!(self);
86 number_to_string_value_recursive(&mut value);
88 value
89 }
90}
91
92pub trait MoveTypeTag:
93 Into<TypeTag>
94 + TryFrom<TypeTag, Error = TypeTagError>
95 + FromStr
96 + Clone
97 + Debug
98 + PartialEq
99 + Eq
100 + Hash
101 + for<'de> Deserialize<'de>
102 + PartialOrd
103 + Ord
104 + Serialize
105{
106}
107
108impl<T> MoveTypeTag for T where
109 T: Into<TypeTag>
110 + TryFrom<TypeTag, Error = TypeTagError>
111 + FromStr
112 + Clone
113 + Debug
114 + PartialEq
115 + Eq
116 + Hash
117 + for<'de> Deserialize<'de>
118 + PartialOrd
119 + Ord
120 + Serialize
121{
122}
123
124pub trait MoveStruct: MoveType<TypeTag = Self::StructTag> {
130 type StructTag: MoveStructTag;
131}
132
133pub trait MoveStructTag:
134 Into<StructTag> + TryFrom<StructTag, Error = StructTagError> + MoveTypeTag
135{
136}
137
138impl<T> MoveStructTag for T where
139 T: Into<StructTag> + TryFrom<StructTag, Error = StructTagError> + MoveTypeTag
140{
141}
142
143pub trait HasKey: MoveStruct {
148 fn object_id(&self) -> Address;
149}
150
151pub trait HasCopy: MoveStruct + Copy {}
152
153pub trait HasStore: MoveStruct {}
154
155pub trait HasDrop: MoveStruct {}
156
157pub trait StaticTypeTag: MoveType {
163 fn type_() -> Self::TypeTag;
164
165 fn type_tag() -> TypeTag {
166 Self::type_().into()
167 }
168}
169
170pub trait StaticAddress: MoveStruct {
172 fn address() -> Address;
173}
174
175pub trait StaticModule: MoveStruct {
177 fn module() -> Identifier;
178}
179
180pub trait StaticName: MoveStruct {
182 fn name() -> Identifier;
183}
184
185pub trait StaticTypeParams: MoveStruct {
187 fn type_params() -> Vec<TypeTag>;
188}
189
190pub trait StaticStructTag: MoveStruct {
192 fn struct_tag() -> StructTag;
193}
194
195impl<T> StaticStructTag for T
196where
197 T: StaticAddress + StaticModule + StaticName + StaticTypeParams,
198{
199 fn struct_tag() -> StructTag {
200 StructTag::new(
201 Self::address(),
202 Self::module(),
203 Self::name(),
204 Self::type_params(),
205 )
206 }
207}
208
209#[derive(Clone, Debug, PartialEq, Eq, Hash)]
218pub struct MoveInstance<T: MoveType> {
219 pub type_: T::TypeTag,
220 pub value: T,
221}
222
223impl<T: StaticTypeTag> From<T> for MoveInstance<T> {
224 fn from(value: T) -> Self {
225 Self {
226 type_: T::type_(),
227 value,
228 }
229 }
230}
231
232impl<T: MoveStruct + tabled::Tabled> std::fmt::Display for MoveInstance<T> {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 use tabled::Table;
235 use tabled::settings::panel::Header;
236 use tabled::settings::{Rotate, Settings, Style};
237
238 let stag: StructTag = self.type_.clone().into();
239 let settings = Settings::default()
240 .with(Rotate::Left)
241 .with(Rotate::Top)
242 .with(Style::rounded())
243 .with(Header::new(stag.to_string()));
244 let mut table = Table::new([&self.value]);
245 table.with(settings);
246 write!(f, "{table}")
247 }
248}
249
250impl std::fmt::Display for MoveInstance<Address> {
251 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
252 write!(f, "{}", self.value)
253 }
254}
255
256macro_rules! impl_primitive_move_instance_display {
257 ($($type:ty)+) => {$(
258 impl std::fmt::Display for MoveInstance<$type> {
259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 write!(f, "{}", self.value)
261 }
262 }
263 )+};
264}
265
266impl_primitive_move_instance_display! {
267 bool
268 u8
269 u16
270 u32
271 u64
272 u128
273 U256
274}
275
276impl<T: MoveType> MoveInstance<T> {
277 pub fn from_raw_type(tag: TypeTag, bytes: &[u8]) -> Result<Self, FromRawTypeError> {
279 Ok(Self {
280 type_: tag.try_into()?,
281 value: T::from_bcs(bytes)?,
282 })
283 }
284}
285
286impl<T: MoveStruct> MoveInstance<T> {
287 pub fn from_raw_struct(stag: StructTag, bytes: &[u8]) -> Result<Self, FromRawStructError> {
289 Ok(Self {
290 type_: stag.try_into()?,
291 value: T::from_bcs(bytes)?,
292 })
293 }
294}
295
296fn number_to_string_value_recursive(value: &mut serde_json::Value) {
297 match value {
298 serde_json::Value::Array(a) => {
299 for v in a {
300 number_to_string_value_recursive(v)
301 }
302 }
303 serde_json::Value::Number(n) => *value = serde_json::Value::String(n.to_string()),
304 serde_json::Value::Object(o) => {
305 for v in o.values_mut() {
306 number_to_string_value_recursive(v)
307 }
308 }
309 _ => (),
310 }
311}
312
313pub trait ObjectExt {
319 fn struct_instance<T: MoveStruct>(&self) -> Result<MoveInstance<T>, ObjectError>;
321}
322
323impl ObjectExt for sui_sdk_types::Object {
324 fn struct_instance<T: MoveStruct>(&self) -> Result<MoveInstance<T>, ObjectError> {
325 let sui_sdk_types::ObjectData::Struct(s) = self.data() else {
326 return Err(ObjectError::NotStruct);
327 };
328 MoveInstance::from_raw_struct(s.object_type().clone(), s.contents()).map_err(From::from)
329 }
330}
331
332#[derive(thiserror::Error, Debug)]
334pub enum ObjectError {
335 #[error("Object is not a Move struct")]
336 NotStruct,
337 #[error(transparent)]
338 FromRawStruct(#[from] FromRawStructError),
339}
340
341#[derive(thiserror::Error, Debug)]
346pub enum TypeTagError {
347 #[error("Wrong TypeTag variant: expected {expected}, got {got}")]
348 Variant { expected: String, got: TypeTag },
349 #[error("StructTag params: {0}")]
350 StructTag(#[from] StructTagError),
351}
352
353#[derive(thiserror::Error, Debug)]
354pub enum StructTagError {
355 #[error("Wrong address: expected {expected}, got {got}")]
356 Address { expected: Address, got: Address },
357 #[error("Wrong module: expected {expected}, got {got}")]
358 Module {
359 expected: Identifier,
360 got: Identifier,
361 },
362 #[error("Wrong name: expected {expected}, got {got}")]
363 Name {
364 expected: Identifier,
365 got: Identifier,
366 },
367 #[error("Wrong type parameters: {0}")]
368 TypeParams(#[from] TypeParamsError),
369}
370
371#[derive(thiserror::Error, Debug)]
372pub enum TypeParamsError {
373 #[error("Wrong number of generics: expected {expected}, got {got}")]
374 Number { expected: usize, got: usize },
375 #[error("Wrong type for generic: {0}")]
376 TypeTag(Box<TypeTagError>),
377}
378
379impl From<TypeTagError> for TypeParamsError {
380 fn from(value: TypeTagError) -> Self {
381 Self::TypeTag(Box::new(value))
382 }
383}
384
385#[derive(thiserror::Error, Debug)]
386pub enum ParseTypeTagError {
387 #[error("Parsing TypeTag: {0}")]
388 FromStr(#[from] sui_sdk_types::TypeParseError),
389 #[error("Converting from TypeTag: {0}")]
390 TypeTag(#[from] TypeTagError),
391}
392
393#[derive(thiserror::Error, Debug)]
394pub enum ParseStructTagError {
395 #[error("Parsing StructTag: {0}")]
396 FromStr(#[from] sui_sdk_types::TypeParseError),
397 #[error("Converting from StructTag: {0}")]
398 StructTag(#[from] StructTagError),
399}
400
401#[derive(thiserror::Error, Debug)]
402pub enum FromRawTypeError {
403 #[error("Converting from TypeTag: {0}")]
404 TypeTag(#[from] TypeTagError),
405 #[error("Deserializing BCS: {0}")]
406 Bcs(#[from] bcs::Error),
407}
408
409#[derive(thiserror::Error, Debug)]
410pub enum FromRawStructError {
411 #[error("Converting from StructTag: {0}")]
412 StructTag(#[from] StructTagError),
413 #[error("Deserializing BCS: {0}")]
414 Bcs(#[from] bcs::Error),
415}