1#![cfg_attr(all(doc, not(doctest)), feature(doc_auto_cfg))]
2
3use std::fmt::Debug;
18use std::hash::Hash;
19use std::str::FromStr;
20
21pub use af_move_type_derive::MoveStruct;
22use af_sui_types::u256::U256;
23use af_sui_types::{Address, IdentStr, Identifier, ObjectId, StructTag, TypeTag};
24use serde::{Deserialize, Serialize};
25
26#[doc(hidden)]
27pub mod external;
28pub mod otw;
29pub mod vector;
30
31#[derive(thiserror::Error, Debug)]
36pub enum TypeTagError {
37 #[error("Wrong TypeTag variant: expected {expected}, got {got}")]
38 Variant { expected: String, got: TypeTag },
39 #[error("StructTag params: {0}")]
40 StructTag(#[from] StructTagError),
41}
42
43#[derive(thiserror::Error, Debug)]
44pub enum StructTagError {
45 #[error("Wrong address: expected {expected}, got {got}")]
46 Address { expected: Address, got: Address },
47 #[error("Wrong module: expected {expected}, got {got}")]
48 Module {
49 expected: Identifier,
50 got: Identifier,
51 },
52 #[error("Wrong name: expected {expected}, got {got}")]
53 Name {
54 expected: Identifier,
55 got: Identifier,
56 },
57 #[error("Wrong type parameters: {0}")]
58 TypeParams(#[from] TypeParamsError),
59}
60
61#[derive(thiserror::Error, Debug)]
62pub enum TypeParamsError {
63 #[error("Wrong number of generics: expected {expected}, got {got}")]
64 Number { expected: usize, got: usize },
65 #[error("Wrong type for generic: {0}")]
66 TypeTag(Box<TypeTagError>),
67}
68
69impl From<TypeTagError> for TypeParamsError {
70 fn from(value: TypeTagError) -> Self {
71 Self::TypeTag(Box::new(value))
72 }
73}
74
75#[derive(thiserror::Error, Debug)]
76pub enum ParseTypeTagError {
77 #[error("Parsing TypeTag: {0}")]
78 FromStr(#[from] sui_sdk_types::TypeParseError),
79 #[error("Converting from TypeTag: {0}")]
80 TypeTag(#[from] TypeTagError),
81}
82
83#[derive(thiserror::Error, Debug)]
84pub enum ParseStructTagError {
85 #[error("Parsing StructTag: {0}")]
86 FromStr(#[from] sui_sdk_types::TypeParseError),
87 #[error("Converting from StructTag: {0}")]
88 StructTag(#[from] StructTagError),
89}
90
91#[derive(thiserror::Error, Debug)]
92pub enum FromRawTypeError {
93 #[error("Converting from TypeTag: {0}")]
94 TypeTag(#[from] TypeTagError),
95 #[error("Deserializing BCS: {0}")]
96 Bcs(#[from] bcs::Error),
97}
98
99#[derive(thiserror::Error, Debug)]
100pub enum FromRawStructError {
101 #[error("Converting from StructTag: {0}")]
102 StructTag(#[from] StructTagError),
103 #[error("Deserializing BCS: {0}")]
104 Bcs(#[from] bcs::Error),
105}
106
107pub trait MoveType:
113 Clone
114 + std::fmt::Debug
115 + std::fmt::Display
116 + for<'de> Deserialize<'de>
117 + Serialize
118 + PartialEq
119 + Eq
120 + std::hash::Hash
121{
122 type TypeTag: MoveTypeTag;
123
124 fn from_bcs(bytes: &[u8]) -> bcs::Result<Self> {
126 bcs::from_bytes(bytes)
127 }
128
129 fn into_bcs(self) -> bcs::Result<Vec<u8>> {
131 bcs::to_bytes(&self)
132 }
133
134 fn to_bcs(&self) -> bcs::Result<Vec<u8>> {
136 bcs::to_bytes(self)
137 }
138
139 fn into_json(self) -> serde_json::Value {
141 let mut value = serde_json::json!(self);
142 number_to_string_value_recursive(&mut value);
144 value
145 }
146
147 fn to_json(&self) -> serde_json::Value {
154 let mut value = serde_json::json!(self);
155 number_to_string_value_recursive(&mut value);
157 value
158 }
159}
160
161pub trait MoveTypeTag:
162 Into<TypeTag>
163 + TryFrom<TypeTag, Error = TypeTagError>
164 + FromStr
165 + Clone
166 + Debug
167 + PartialEq
168 + Eq
169 + Hash
170 + for<'de> Deserialize<'de>
171 + PartialOrd
172 + Ord
173 + Serialize
174{
175}
176
177impl<T> MoveTypeTag for T where
178 T: Into<TypeTag>
179 + TryFrom<TypeTag, Error = TypeTagError>
180 + FromStr
181 + Clone
182 + Debug
183 + PartialEq
184 + Eq
185 + Hash
186 + for<'de> Deserialize<'de>
187 + PartialOrd
188 + Ord
189 + Serialize
190{
191}
192
193pub trait MoveStruct: MoveType<TypeTag = Self::StructTag> {
199 type StructTag: MoveStructTag;
200}
201
202pub trait MoveStructTag:
203 Into<StructTag> + TryFrom<StructTag, Error = StructTagError> + MoveTypeTag
204{
205}
206
207impl<T> MoveStructTag for T where
208 T: Into<StructTag> + TryFrom<StructTag, Error = StructTagError> + MoveTypeTag
209{
210}
211
212pub trait HasKey: MoveStruct {
217 fn object_id(&self) -> ObjectId;
218}
219
220pub trait HasCopy: MoveStruct + Copy {}
221
222pub trait HasStore: MoveStruct {}
223
224pub trait HasDrop: MoveStruct {}
225
226pub trait StaticTypeTag: MoveType {
232 fn type_() -> Self::TypeTag;
233
234 fn type_tag() -> TypeTag {
235 Self::type_().into()
236 }
237}
238
239pub trait StaticAddress: MoveStruct {
241 fn address() -> Address;
242}
243
244pub trait StaticModule: MoveStruct {
246 fn module() -> Identifier;
247}
248
249pub trait StaticName: MoveStruct {
251 fn name() -> Identifier;
252}
253
254pub trait StaticTypeParams: MoveStruct {
256 fn type_params() -> Vec<TypeTag>;
257}
258
259pub trait StaticStructTag: MoveStruct {
261 fn struct_tag() -> StructTag;
262}
263
264impl<T> StaticStructTag for T
265where
266 T: StaticAddress + StaticModule + StaticName + StaticTypeParams,
267{
268 fn struct_tag() -> StructTag {
269 StructTag {
270 address: Self::address(),
271 module: Self::module(),
272 name: Self::name(),
273 type_params: Self::type_params(),
274 }
275 }
276}
277
278#[derive(Clone, Debug, PartialEq, Eq, Hash)]
287pub struct MoveInstance<T: MoveType> {
288 pub type_: T::TypeTag,
289 pub value: T,
290}
291
292impl<T: StaticTypeTag> From<T> for MoveInstance<T> {
293 fn from(value: T) -> Self {
294 Self {
295 type_: T::type_(),
296 value,
297 }
298 }
299}
300
301impl<T: MoveStruct + tabled::Tabled> std::fmt::Display for MoveInstance<T> {
302 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 use tabled::settings::panel::Header;
304 use tabled::settings::{Rotate, Settings, Style};
305 use tabled::Table;
306
307 let stag: StructTag = self.type_.clone().into();
308 let settings = Settings::default()
309 .with(Rotate::Left)
310 .with(Rotate::Top)
311 .with(Style::rounded())
312 .with(Header::new(stag.to_string()));
313 let mut table = Table::new([&self.value]);
314 table.with(settings);
315 write!(f, "{table}")
316 }
317}
318
319impl std::fmt::Display for MoveInstance<Address> {
320 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321 write!(f, "{}", self.value)
322 }
323}
324
325macro_rules! impl_primitive_move_instance_display {
326 ($($type:ty)+) => {$(
327 impl std::fmt::Display for MoveInstance<$type> {
328 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
329 write!(f, "{}", self.value)
330 }
331 }
332 )+};
333}
334
335impl_primitive_move_instance_display! {
336 bool
337 u8
338 u16
339 u32
340 u64
341 u128
342 U256
343}
344
345impl<T: MoveType> MoveInstance<T> {
346 pub fn from_raw_type(tag: TypeTag, bytes: &[u8]) -> Result<Self, FromRawTypeError> {
348 Ok(Self {
349 type_: tag.try_into()?,
350 value: T::from_bcs(bytes)?,
351 })
352 }
353}
354
355impl<T: MoveStruct> MoveInstance<T> {
356 pub fn from_raw_struct(stag: StructTag, bytes: &[u8]) -> Result<Self, FromRawStructError> {
358 Ok(Self {
359 type_: stag.try_into()?,
360 value: T::from_bcs(bytes)?,
361 })
362 }
363}
364
365fn number_to_string_value_recursive(value: &mut serde_json::Value) {
366 match value {
367 serde_json::Value::Array(a) => {
368 for v in a {
369 number_to_string_value_recursive(v)
370 }
371 }
372 serde_json::Value::Number(n) => *value = serde_json::Value::String(n.to_string()),
373 serde_json::Value::Object(o) => {
374 for v in o.values_mut() {
375 number_to_string_value_recursive(v)
376 }
377 }
378 _ => (),
379 }
380}
381
382macro_rules! impl_primitive_type_tags {
387 ($($typ:ty: ($type_:ident, $variant:ident)),*) => {
388 $(
389 #[derive(
390 Clone,
391 Debug,
392 PartialEq,
393 Eq,
394 Hash,
395 Deserialize,
396 PartialOrd,
397 Ord,
398 Serialize
399 )]
400 pub struct $type_;
401
402 impl From<$type_> for TypeTag {
403 fn from(_value: $type_) -> Self {
404 Self::$variant
405 }
406 }
407
408 impl TryFrom<TypeTag> for $type_ {
409 type Error = TypeTagError;
410
411 fn try_from(value: TypeTag) -> Result<Self, Self::Error> {
412 match value {
413 TypeTag::$variant => Ok(Self),
414 _ => Err(TypeTagError::Variant {
415 expected: stringify!($variant).to_owned(),
416 got: value }
417 )
418 }
419 }
420 }
421
422 impl FromStr for $type_ {
423 type Err = ParseTypeTagError;
424
425 fn from_str(s: &str) -> Result<Self, Self::Err> {
426 let tag: TypeTag = s.parse()?;
427 Ok(tag.try_into()?)
428 }
429 }
430
431 impl MoveType for $typ {
432 type TypeTag = $type_;
433 }
434
435 impl StaticTypeTag for $typ {
436 fn type_() -> Self::TypeTag {
437 $type_ {}
438 }
439 }
440 )*
441 };
442}
443
444impl_primitive_type_tags! {
445 Address: (AddressTypeTag, Address),
446 bool: (BoolTypeTag, Bool),
447 u8: (U8TypeTag, U8),
448 u16: (U16TypeTag, U16),
449 u32: (U32TypeTag, U32),
450 u64: (U64TypeTag, U64),
451 u128: (U128TypeTag, U128),
452 U256: (U256TypeTag, U256)
453}
454
455#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, PartialOrd, Ord, Serialize)]
456pub struct StringTypeTag;
457
458impl From<StringTypeTag> for TypeTag {
459 fn from(value: StringTypeTag) -> Self {
460 Self::Struct(Box::new(value.into()))
461 }
462}
463
464impl TryFrom<TypeTag> for StringTypeTag {
465 type Error = TypeTagError;
466
467 fn try_from(value: TypeTag) -> Result<Self, Self::Error> {
468 match value {
469 TypeTag::Struct(stag) => Ok((*stag).try_into()?),
470 other => Err(TypeTagError::Variant {
471 expected: "Struct(_)".to_owned(),
472 got: other,
473 }),
474 }
475 }
476}
477
478impl From<StringTypeTag> for StructTag {
479 fn from(_: StringTypeTag) -> Self {
480 String::struct_tag()
481 }
482}
483
484impl TryFrom<StructTag> for StringTypeTag {
485 type Error = StructTagError;
486
487 fn try_from(value: StructTag) -> Result<Self, Self::Error> {
488 use StructTagError::*;
489 let StructTag {
490 address,
491 module,
492 name,
493 type_params,
494 } = value;
495 let expected = String::struct_tag();
496 if address != expected.address {
497 return Err(Address {
498 expected: expected.address,
499 got: address,
500 });
501 }
502 if module != expected.module {
503 return Err(Module {
504 expected: expected.module,
505 got: module,
506 });
507 }
508 if name != expected.name {
509 return Err(Name {
510 expected: expected.name,
511 got: name,
512 });
513 }
514 if !type_params.is_empty() {
515 return Err(TypeParams(TypeParamsError::Number {
516 expected: 0,
517 got: type_params.len(),
518 }));
519 }
520 Ok(Self)
521 }
522}
523
524impl FromStr for StringTypeTag {
525 type Err = ParseStructTagError;
526
527 fn from_str(s: &str) -> Result<Self, Self::Err> {
528 let stag: StructTag = s.parse()?;
529 Ok(stag.try_into()?)
530 }
531}
532
533impl MoveType for String {
534 type TypeTag = StringTypeTag;
535}
536
537impl MoveStruct for String {
538 type StructTag = StringTypeTag;
539}
540
541impl StaticTypeTag for String {
542 fn type_() -> Self::TypeTag {
543 StringTypeTag {}
544 }
545}
546
547impl StaticAddress for String {
548 fn address() -> Address {
549 Address::new(af_sui_types::hex_address_bytes(b"0x1"))
550 }
551}
552
553impl StaticModule for String {
554 fn module() -> Identifier {
555 IdentStr::cast("string").to_owned()
556 }
557}
558
559impl StaticName for String {
560 fn name() -> Identifier {
561 IdentStr::cast("String").to_owned()
562 }
563}
564
565impl StaticTypeParams for String {
566 fn type_params() -> Vec<TypeTag> {
567 vec![]
568 }
569}