1use std::fmt::{Display, Formatter};
5
6use anyhow::Result;
7use move_core_types::{
8 account_address::AccountAddress,
9 identifier::Identifier,
10 language_storage::{StructTag, TypeTag},
11};
12use serde::{Deserialize, Serialize};
13use sui_macros::EnumVariantOrder;
14
15use crate::base_types::MoveObjectType;
16
17#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
18pub struct StructInput {
19 pub address: AccountAddress,
20 pub module: String,
21 pub name: String,
22 #[serde(rename = "type_args", alias = "type_params")]
24 pub type_params: Vec<TypeInput>,
25}
26
27#[derive(
28 Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord, EnumVariantOrder,
29)]
30pub enum TypeInput {
31 #[serde(rename = "bool", alias = "Bool")]
33 Bool,
34 #[serde(rename = "u8", alias = "U8")]
35 U8,
36 #[serde(rename = "u64", alias = "U64")]
37 U64,
38 #[serde(rename = "u128", alias = "U128")]
39 U128,
40 #[serde(rename = "address", alias = "Address")]
41 Address,
42 #[serde(rename = "signer", alias = "Signer")]
43 Signer,
44 #[serde(rename = "vector", alias = "Vector")]
45 Vector(Box<TypeInput>),
46 #[serde(rename = "struct", alias = "Struct")]
47 Struct(Box<StructInput>),
48
49 #[serde(rename = "u16", alias = "U16")]
51 U16,
52 #[serde(rename = "u32", alias = "U32")]
53 U32,
54 #[serde(rename = "u256", alias = "U256")]
55 U256,
56}
57
58impl TypeInput {
59 pub fn to_canonical_string(&self, with_prefix: bool) -> String {
76 self.to_canonical_display(with_prefix).to_string()
77 }
78
79 pub fn to_canonical_display(&self, with_prefix: bool) -> impl std::fmt::Display + '_ {
81 struct CanonicalDisplay<'a> {
82 data: &'a TypeInput,
83 with_prefix: bool,
84 }
85
86 impl std::fmt::Display for CanonicalDisplay<'_> {
87 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
88 match self.data {
89 TypeInput::Bool => write!(f, "bool"),
90 TypeInput::U8 => write!(f, "u8"),
91 TypeInput::U16 => write!(f, "u16"),
92 TypeInput::U32 => write!(f, "u32"),
93 TypeInput::U64 => write!(f, "u64"),
94 TypeInput::U128 => write!(f, "u128"),
95 TypeInput::U256 => write!(f, "u256"),
96 TypeInput::Address => write!(f, "address"),
97 TypeInput::Signer => write!(f, "signer"),
98 TypeInput::Vector(t) => {
99 write!(f, "vector<{}>", t.to_canonical_display(self.with_prefix))
100 }
101 TypeInput::Struct(s) => {
102 write!(f, "{}", s.to_canonical_display(self.with_prefix))
103 }
104 }
105 }
106 }
107
108 CanonicalDisplay {
109 data: self,
110 with_prefix,
111 }
112 }
113
114 pub unsafe fn into_type_tag_unchecked(self) -> TypeTag {
122 match self {
123 TypeInput::Bool => TypeTag::Bool,
124 TypeInput::U8 => TypeTag::U8,
125 TypeInput::U16 => TypeTag::U16,
126 TypeInput::U32 => TypeTag::U32,
127 TypeInput::U64 => TypeTag::U64,
128 TypeInput::U128 => TypeTag::U128,
129 TypeInput::U256 => TypeTag::U256,
130 TypeInput::Address => TypeTag::Address,
131 TypeInput::Signer => TypeTag::Signer,
132 TypeInput::Vector(inner) => unsafe {
133 TypeTag::Vector(Box::new(inner.into_type_tag_unchecked()))
134 },
135 TypeInput::Struct(inner) => {
136 let StructInput {
137 address,
138 module,
139 name,
140 type_params,
141 } = *inner;
142 unsafe {
143 TypeTag::Struct(Box::new(StructTag {
144 address,
145 module: Identifier::new_unchecked(module),
146 name: Identifier::new_unchecked(name),
147 type_params: type_params
148 .into_iter()
149 .map(|ty| ty.into_type_tag_unchecked())
150 .collect(),
151 }))
152 }
153 }
154 }
155 }
156
157 pub fn to_type_tag(&self) -> Result<TypeTag> {
161 use TypeInput as I;
162 use TypeTag as T;
163 Ok(match self {
164 I::Bool => T::Bool,
165 I::U8 => T::U8,
166 I::U16 => T::U16,
167 I::U32 => T::U32,
168 I::U64 => T::U64,
169 I::U128 => T::U128,
170 I::U256 => T::U256,
171 I::Address => T::Address,
172 I::Signer => T::Signer,
173 I::Vector(t) => T::Vector(Box::new(t.to_type_tag()?)),
174 I::Struct(s) => {
175 let StructInput {
176 address,
177 module,
178 name,
179 type_params,
180 } = s.as_ref();
181 let type_params = type_params
182 .iter()
183 .map(|t| t.to_type_tag())
184 .collect::<Result<_>>()?;
185 T::Struct(Box::new(StructTag {
186 address: *address,
187 module: Identifier::new(module.to_owned())?,
188 name: Identifier::new(name.to_owned())?,
189 type_params,
190 }))
191 }
192 })
193 }
194}
195
196impl StructInput {
197 pub fn to_canonical_string(&self, with_prefix: bool) -> String {
210 self.to_canonical_display(with_prefix).to_string()
211 }
212
213 pub fn to_canonical_display(&self, with_prefix: bool) -> impl std::fmt::Display + '_ {
215 struct CanonicalDisplay<'a> {
216 data: &'a StructInput,
217 with_prefix: bool,
218 }
219
220 impl std::fmt::Display for CanonicalDisplay<'_> {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 write!(
223 f,
224 "{}::{}::{}",
225 self.data.address.to_canonical_display(self.with_prefix),
226 self.data.module,
227 self.data.name
228 )?;
229
230 if let Some(first_ty) = self.data.type_params.first() {
231 write!(f, "<")?;
232 write!(f, "{}", first_ty.to_canonical_display(self.with_prefix))?;
233 for ty in self.data.type_params.iter().skip(1) {
234 write!(f, ",{}", ty.to_canonical_display(self.with_prefix))?;
237 }
238 write!(f, ">")?;
239 }
240 Ok(())
241 }
242 }
243
244 CanonicalDisplay {
245 data: self,
246 with_prefix,
247 }
248 }
249}
250
251impl From<MoveObjectType> for TypeInput {
252 fn from(obj: MoveObjectType) -> Self {
253 Self::from(TypeTag::from(obj))
254 }
255}
256
257impl From<TypeTag> for TypeInput {
258 fn from(tag: TypeTag) -> Self {
259 match tag {
260 TypeTag::Bool => TypeInput::Bool,
261 TypeTag::U8 => TypeInput::U8,
262 TypeTag::U64 => TypeInput::U64,
263 TypeTag::U128 => TypeInput::U128,
264 TypeTag::Address => TypeInput::Address,
265 TypeTag::Signer => TypeInput::Signer,
266 TypeTag::Vector(inner) => TypeInput::Vector(Box::new(TypeInput::from(*inner))),
267 TypeTag::Struct(inner) => TypeInput::Struct(Box::new(StructInput::from(*inner))),
268 TypeTag::U16 => TypeInput::U16,
269 TypeTag::U32 => TypeInput::U32,
270 TypeTag::U256 => TypeInput::U256,
271 }
272 }
273}
274
275impl From<StructTag> for StructInput {
276 fn from(tag: StructTag) -> Self {
277 StructInput {
278 address: tag.address,
279 module: tag.module.to_string(),
280 name: tag.name.to_string(),
281 type_params: tag.type_params.into_iter().map(TypeInput::from).collect(),
282 }
283 }
284}
285
286impl From<StructInput> for TypeInput {
287 fn from(t: StructInput) -> TypeInput {
288 TypeInput::Struct(Box::new(t))
289 }
290}
291
292impl Display for StructInput {
293 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
294 write!(
295 f,
296 "0x{}::{}::{}",
297 self.address.short_str_lossless(),
298 self.module,
299 self.name
300 )?;
301
302 let mut prefix = "<";
303 for ty in &self.type_params {
304 write!(f, "{}{}", prefix, ty)?;
305 prefix = ", ";
306 }
307 if !self.type_params.is_empty() {
308 write!(f, ">")?;
309 }
310
311 Ok(())
312 }
313}
314
315impl Display for TypeInput {
316 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
317 match self {
318 TypeInput::Struct(s) => write!(f, "{}", s),
319 TypeInput::Vector(ty) => write!(f, "vector<{}>", ty),
320 TypeInput::U8 => write!(f, "u8"),
321 TypeInput::U16 => write!(f, "u16"),
322 TypeInput::U32 => write!(f, "u32"),
323 TypeInput::U64 => write!(f, "u64"),
324 TypeInput::U128 => write!(f, "u128"),
325 TypeInput::U256 => write!(f, "u256"),
326 TypeInput::Address => write!(f, "address"),
327 TypeInput::Signer => write!(f, "signer"),
328 TypeInput::Bool => write!(f, "bool"),
329 }
330 }
331}
332
333#[cfg(test)]
334mod test {
335 use super::TypeInput;
336 use sui_enum_compat_util::*;
337
338 #[test]
339 fn enforce_order_test() {
340 let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
341 path.extend(["tests", "staged", "type_input.yaml"]);
342 check_enum_compat_order::<TypeInput>(path);
343 }
344}