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