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