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 fn matches(tag: &TypeTag) -> bool {
111 Self::try_from(tag.clone()).is_ok()
112 }
113
114 fn matches_instance(&self, tag: &TypeTag) -> bool {
122 Self::matches(tag)
123 }
124}
125
126pub trait MoveStruct: MoveType<TypeTag = Self::StructTag> {
132 type StructTag: MoveStructTag;
133}
134
135pub trait MoveStructTag:
136 Into<StructTag> + TryFrom<StructTag, Error = StructTagError> + MoveTypeTag
137{
138}
139
140impl<T> MoveStructTag for T where
141 T: Into<StructTag> + TryFrom<StructTag, Error = StructTagError> + MoveTypeTag
142{
143}
144
145pub trait HasKey: MoveStruct {
150 fn object_id(&self) -> Address;
151}
152
153pub trait HasCopy: MoveStruct + Copy {}
154
155pub trait HasStore: MoveStruct {}
156
157pub trait HasDrop: MoveStruct {}
158
159pub trait StaticTypeTag: MoveType {
165 fn type_() -> Self::TypeTag;
166
167 fn type_tag() -> TypeTag {
168 Self::type_().into()
169 }
170}
171
172pub trait StaticAddress: MoveStruct {
174 fn address() -> Address;
175}
176
177pub trait StaticModule: MoveStruct {
179 fn module() -> Identifier;
180}
181
182pub trait StaticName: MoveStruct {
184 fn name() -> Identifier;
185}
186
187pub trait StaticTypeParams: MoveStruct {
189 fn type_params() -> Vec<TypeTag>;
190}
191
192pub trait StaticStructTag: MoveStruct {
194 fn struct_tag() -> StructTag;
195}
196
197impl<T> StaticStructTag for T
198where
199 T: StaticAddress + StaticModule + StaticName + StaticTypeParams,
200{
201 fn struct_tag() -> StructTag {
202 StructTag::new(
203 Self::address(),
204 Self::module(),
205 Self::name(),
206 Self::type_params(),
207 )
208 }
209}
210
211#[derive(Clone, Debug, PartialEq, Eq, Hash)]
220pub struct MoveInstance<T: MoveType> {
221 pub type_: T::TypeTag,
222 pub value: T,
223}
224
225impl<T: StaticTypeTag> From<T> for MoveInstance<T> {
226 fn from(value: T) -> Self {
227 Self {
228 type_: T::type_(),
229 value,
230 }
231 }
232}
233
234impl<T: MoveStruct + tabled::Tabled> std::fmt::Display for MoveInstance<T> {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 use tabled::Table;
237 use tabled::settings::panel::Header;
238 use tabled::settings::{Rotate, Settings, Style};
239
240 let stag: StructTag = self.type_.clone().into();
241 let settings = Settings::default()
242 .with(Rotate::Left)
243 .with(Rotate::Top)
244 .with(Style::rounded())
245 .with(Header::new(stag.to_string()));
246 let mut table = Table::new([&self.value]);
247 table.with(settings);
248 write!(f, "{table}")
249 }
250}
251
252impl std::fmt::Display for MoveInstance<Address> {
253 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 write!(f, "{}", self.value)
255 }
256}
257
258macro_rules! impl_primitive_move_instance_display {
259 ($($type:ty)+) => {$(
260 impl std::fmt::Display for MoveInstance<$type> {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262 write!(f, "{}", self.value)
263 }
264 }
265 )+};
266}
267
268impl_primitive_move_instance_display! {
269 bool
270 u8
271 u16
272 u32
273 u64
274 u128
275 U256
276}
277
278impl<T: MoveType> MoveInstance<T> {
279 pub fn from_raw_type(tag: TypeTag, bytes: &[u8]) -> Result<Self, FromRawTypeError> {
281 Ok(Self {
282 type_: tag.try_into()?,
283 value: T::from_bcs(bytes)?,
284 })
285 }
286}
287
288impl<T: MoveStruct> MoveInstance<T> {
289 pub fn from_raw_struct(stag: StructTag, bytes: &[u8]) -> Result<Self, FromRawStructError> {
291 Ok(Self {
292 type_: stag.try_into()?,
293 value: T::from_bcs(bytes)?,
294 })
295 }
296}
297
298fn number_to_string_value_recursive(value: &mut serde_json::Value) {
299 match value {
300 serde_json::Value::Array(a) => {
301 for v in a {
302 number_to_string_value_recursive(v)
303 }
304 }
305 serde_json::Value::Number(n) => *value = serde_json::Value::String(n.to_string()),
306 serde_json::Value::Object(o) => {
307 for v in o.values_mut() {
308 number_to_string_value_recursive(v)
309 }
310 }
311 _ => (),
312 }
313}
314
315pub trait ObjectExt {
321 fn struct_instance<T: MoveStruct>(&self) -> Result<MoveInstance<T>, ObjectError>;
323}
324
325impl ObjectExt for sui_sdk_types::Object {
326 fn struct_instance<T: MoveStruct>(&self) -> Result<MoveInstance<T>, ObjectError> {
327 let sui_sdk_types::ObjectData::Struct(s) = self.data() else {
328 return Err(ObjectError::NotStruct);
329 };
330 MoveInstance::from_raw_struct(s.object_type().clone(), s.contents()).map_err(From::from)
331 }
332}
333
334#[derive(thiserror::Error, Debug)]
336pub enum ObjectError {
337 #[error("Object is not a Move struct")]
338 NotStruct,
339 #[error(transparent)]
340 FromRawStruct(#[from] FromRawStructError),
341}
342
343#[derive(thiserror::Error, Debug)]
348pub enum TypeTagError {
349 #[error("Wrong TypeTag variant: expected {expected}, got {got}")]
350 Variant { expected: String, got: TypeTag },
351 #[error("StructTag params: {0}")]
352 StructTag(#[from] StructTagError),
353}
354
355#[derive(thiserror::Error, Debug)]
356pub enum StructTagError {
357 #[error("Wrong address: expected {expected}, got {got}")]
358 Address { expected: Address, got: Address },
359 #[error("Wrong module: expected {expected}, got {got}")]
360 Module {
361 expected: Identifier,
362 got: Identifier,
363 },
364 #[error("Wrong name: expected {expected}, got {got}")]
365 Name {
366 expected: Identifier,
367 got: Identifier,
368 },
369 #[error("Wrong type parameters: {0}")]
370 TypeParams(#[from] TypeParamsError),
371}
372
373#[derive(thiserror::Error, Debug)]
374pub enum TypeParamsError {
375 #[error("Wrong number of generics: expected {expected}, got {got}")]
376 Number { expected: usize, got: usize },
377 #[error("Wrong type for generic: {0}")]
378 TypeTag(Box<TypeTagError>),
379}
380
381impl From<TypeTagError> for TypeParamsError {
382 fn from(value: TypeTagError) -> Self {
383 Self::TypeTag(Box::new(value))
384 }
385}
386
387#[derive(thiserror::Error, Debug)]
388pub enum ParseTypeTagError {
389 #[error("Parsing TypeTag: {0}")]
390 FromStr(#[from] sui_sdk_types::TypeParseError),
391 #[error("Converting from TypeTag: {0}")]
392 TypeTag(#[from] TypeTagError),
393}
394
395#[derive(thiserror::Error, Debug)]
396pub enum ParseStructTagError {
397 #[error("Parsing StructTag: {0}")]
398 FromStr(#[from] sui_sdk_types::TypeParseError),
399 #[error("Converting from StructTag: {0}")]
400 StructTag(#[from] StructTagError),
401}
402
403#[derive(thiserror::Error, Debug)]
404pub enum FromRawTypeError {
405 #[error("Converting from TypeTag: {0}")]
406 TypeTag(#[from] TypeTagError),
407 #[error("Deserializing BCS: {0}")]
408 Bcs(#[from] bcs::Error),
409}
410
411#[derive(thiserror::Error, Debug)]
412pub enum FromRawStructError {
413 #[error("Converting from StructTag: {0}")]
414 StructTag(#[from] StructTagError),
415 #[error("Deserializing BCS: {0}")]
416 Bcs(#[from] bcs::Error),
417}