1#![doc = include_str!("../README.md")]
2
3use serde::de::DeserializeOwned;
4use serde::{Deserialize, Serialize};
5use std::fmt;
6use std::str::FromStr;
7
8#[cfg(feature = "derive")]
9pub use talus_sui_move_derive::{move_module, move_struct};
10
11pub mod prelude {
12 #[cfg(feature = "derive")]
16 pub use crate::{move_module, move_struct};
17 pub use crate::{
18 Copyable, Droppable, HasCopy, HasDrop, HasKey, HasStore, MoveInstance, MoveStruct,
19 MoveType, Storable, U256,
20 };
21 pub use sui_sdk_types::{Address, Identifier, StructTag, TypeTag};
22}
23
24#[doc(hidden)]
25pub mod __private {
26 pub use serde;
27 pub use sui_sdk_types;
28}
29
30mod builtins;
31pub mod decode;
32pub use decode::{decode_copyable, decode_keyed, decode_storable};
33
34#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
39#[repr(transparent)]
40pub struct U256(pub ethnum::U256);
41
42impl U256 {
43 pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
45 Self(ethnum::U256::from_le_bytes(bytes))
46 }
47
48 pub fn to_le_bytes(self) -> [u8; 32] {
50 self.0.to_le_bytes()
51 }
52}
53
54impl From<ethnum::U256> for U256 {
55 fn from(value: ethnum::U256) -> Self {
56 Self(value)
57 }
58}
59
60impl From<U256> for ethnum::U256 {
61 fn from(value: U256) -> Self {
62 value.0
63 }
64}
65
66impl Serialize for U256 {
67 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68 where
69 S: serde::Serializer,
70 {
71 self.to_le_bytes().serialize(serializer)
72 }
73}
74
75impl<'de> Deserialize<'de> for U256 {
76 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77 where
78 D: serde::Deserializer<'de>,
79 {
80 <[u8; 32]>::deserialize(deserializer).map(Self::from_le_bytes)
81 }
82}
83
84pub trait MoveType: Serialize + for<'de> Deserialize<'de> + fmt::Debug + PartialEq + Eq {
97 fn type_tag_static() -> sui_sdk_types::TypeTag;
99
100 fn type_tag(&self) -> sui_sdk_types::TypeTag {
102 Self::type_tag_static()
103 }
104
105 fn to_bcs(&self) -> Result<Vec<u8>, bcs::Error> {
107 bcs::to_bytes(self)
108 }
109
110 fn from_bcs(bytes: &[u8]) -> Result<Self, bcs::Error>
112 where
113 Self: Sized,
114 {
115 bcs::from_bytes(bytes)
116 }
117}
118
119pub trait MoveStruct: MoveType {
125 fn struct_tag_static() -> sui_sdk_types::StructTag;
127
128 fn struct_tag(&self) -> sui_sdk_types::StructTag {
129 Self::struct_tag_static()
130 }
131}
132
133pub trait HasKey {}
135
136pub trait HasStore {}
138
139pub trait HasCopy: Clone {}
141
142pub trait HasDrop {}
144
145pub trait Storable: MoveType + HasStore {}
147impl<T: MoveType + HasStore> Storable for T {}
148
149pub trait Copyable: MoveType + HasCopy + HasDrop + Clone {}
151impl<T: MoveType + HasCopy + HasDrop + Clone> Copyable for T {}
152
153pub trait Droppable: MoveType + HasDrop {}
155impl<T: MoveType + HasDrop> Droppable for T {}
156
157#[derive(thiserror::Error, Debug)]
159pub enum DecodeError {
160 #[error("type tag mismatch. expected {expected:?}, got {got:?}")]
161 TypeTagMismatch {
162 expected: sui_sdk_types::TypeTag,
163 got: sui_sdk_types::TypeTag,
164 },
165 #[error(transparent)]
166 Bcs(#[from] bcs::Error),
167 #[error("failed to parse identifier: {0}")]
168 Identifier(String),
169 #[error("failed to parse address: {0}")]
170 Address(String),
171}
172
173#[derive(Clone, Debug, PartialEq, Eq)]
190pub struct MoveInstance<T: MoveType> {
191 pub type_tag: sui_sdk_types::TypeTag,
192 pub value: T,
193}
194
195impl<T: MoveType + DeserializeOwned> MoveInstance<T> {
196 pub fn from_raw_type(
198 type_tag: sui_sdk_types::TypeTag,
199 bytes: &[u8],
200 ) -> Result<Self, DecodeError> {
201 let expected = T::type_tag_static();
202 if type_tag != expected {
203 return Err(DecodeError::TypeTagMismatch {
204 expected,
205 got: type_tag,
206 });
207 }
208 let value = T::from_bcs(bytes)?;
209 Ok(Self { type_tag, value })
210 }
211}
212
213pub fn parse_identifier(value: &str) -> Result<sui_sdk_types::Identifier, DecodeError> {
224 sui_sdk_types::Identifier::from_str(value)
225 .map_err(|_| DecodeError::Identifier(value.to_string()))
226}
227
228pub fn parse_address(value: &str) -> Result<sui_sdk_types::Address, DecodeError> {
242 sui_sdk_types::Address::from_str(value).map_err(|_| DecodeError::Address(value.to_string()))
243}
244
245pub fn type_tag_of<T: MoveType>() -> sui_sdk_types::TypeTag {
254 T::type_tag_static()
255}