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
16use crate::parse_iota_type_tag;
17
18#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
19pub struct TypeName {
20 pub name: String,
29}
30
31impl From<&TypeInput> for TypeName {
32 fn from(value: &TypeInput) -> Self {
33 TypeName {
34 name: value.to_canonical_string(false ),
35 }
36 }
37}
38
39impl From<&TypeTag> for TypeName {
40 fn from(value: &TypeTag) -> Self {
41 TypeName {
42 name: value.to_canonical_string(false ),
43 }
44 }
45}
46
47impl TryFrom<TypeName> for TypeInput {
48 type Error = anyhow::Error;
49
50 fn try_from(value: TypeName) -> Result<Self, Self::Error> {
51 parse_iota_type_tag(&value.name).map(|tag| tag.into())
52 }
53}
54
55#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
56pub struct StructInput {
57 pub address: AccountAddress,
58 pub module: String,
59 pub name: String,
60 #[serde(rename = "type_args", alias = "type_params")]
62 pub type_params: Vec<TypeInput>,
63}
64
65#[derive(
66 Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord, EnumVariantOrder,
67)]
68pub enum TypeInput {
69 #[serde(rename = "bool", alias = "Bool")]
71 Bool,
72 #[serde(rename = "u8", alias = "U8")]
73 U8,
74 #[serde(rename = "u64", alias = "U64")]
75 U64,
76 #[serde(rename = "u128", alias = "U128")]
77 U128,
78 #[serde(rename = "address", alias = "Address")]
79 Address,
80 #[serde(rename = "signer", alias = "Signer")]
81 Signer,
82 #[serde(rename = "vector", alias = "Vector")]
83 Vector(Box<TypeInput>),
84 #[serde(rename = "struct", alias = "Struct")]
85 Struct(Box<StructInput>),
86
87 #[serde(rename = "u16", alias = "U16")]
89 U16,
90 #[serde(rename = "u32", alias = "U32")]
91 U32,
92 #[serde(rename = "u256", alias = "U256")]
93 U256,
94}
95
96impl TypeInput {
97 pub fn to_canonical_string(&self, with_prefix: bool) -> String {
116 self.to_canonical_display(with_prefix).to_string()
117 }
118
119 pub fn to_canonical_display(&self, with_prefix: bool) -> impl std::fmt::Display + '_ {
122 struct CanonicalDisplay<'a> {
123 data: &'a TypeInput,
124 with_prefix: bool,
125 }
126
127 impl std::fmt::Display for CanonicalDisplay<'_> {
128 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
129 match self.data {
130 TypeInput::Bool => write!(f, "bool"),
131 TypeInput::U8 => write!(f, "u8"),
132 TypeInput::U16 => write!(f, "u16"),
133 TypeInput::U32 => write!(f, "u32"),
134 TypeInput::U64 => write!(f, "u64"),
135 TypeInput::U128 => write!(f, "u128"),
136 TypeInput::U256 => write!(f, "u256"),
137 TypeInput::Address => write!(f, "address"),
138 TypeInput::Signer => write!(f, "signer"),
139 TypeInput::Vector(t) => {
140 write!(f, "vector<{}>", t.to_canonical_display(self.with_prefix))
141 }
142 TypeInput::Struct(s) => {
143 write!(f, "{}", s.to_canonical_display(self.with_prefix))
144 }
145 }
146 }
147 }
148
149 CanonicalDisplay {
150 data: self,
151 with_prefix,
152 }
153 }
154
155 pub unsafe fn into_type_tag_unchecked(self) -> TypeTag {
164 match self {
165 TypeInput::Bool => TypeTag::Bool,
166 TypeInput::U8 => TypeTag::U8,
167 TypeInput::U16 => TypeTag::U16,
168 TypeInput::U32 => TypeTag::U32,
169 TypeInput::U64 => TypeTag::U64,
170 TypeInput::U128 => TypeTag::U128,
171 TypeInput::U256 => TypeTag::U256,
172 TypeInput::Address => TypeTag::Address,
173 TypeInput::Signer => TypeTag::Signer,
174 TypeInput::Vector(inner) => TypeTag::Vector(Box::new(inner.into_type_tag_unchecked())),
175 TypeInput::Struct(inner) => {
176 let StructInput {
177 address,
178 module,
179 name,
180 type_params,
181 } = *inner;
182 TypeTag::Struct(Box::new(StructTag {
183 address,
184 module: Identifier::new_unchecked(module),
185 name: Identifier::new_unchecked(name),
186 type_params: type_params
187 .into_iter()
188 .map(|ty| ty.into_type_tag_unchecked())
189 .collect(),
190 }))
191 }
192 }
193 }
194
195 pub fn into_type_tag(self) -> Result<TypeTag> {
198 self.as_type_tag()
199 }
200
201 pub fn as_type_tag(&self) -> Result<TypeTag> {
204 use TypeInput as I;
207 use TypeTag as T;
208 Ok(match self {
209 I::Bool => T::Bool,
210 I::U8 => T::U8,
211 I::U16 => T::U16,
212 I::U32 => T::U32,
213 I::U64 => T::U64,
214 I::U128 => T::U128,
215 I::U256 => T::U256,
216 I::Address => T::Address,
217 I::Signer => T::Signer,
218 I::Vector(t) => T::Vector(Box::new(t.as_type_tag()?)),
219 I::Struct(s) => {
220 let StructInput {
221 address,
222 module,
223 name,
224 type_params,
225 } = s.as_ref();
226 let type_params = type_params
227 .iter()
228 .map(|t| t.as_type_tag())
229 .collect::<Result<_>>()?;
230 T::Struct(Box::new(StructTag {
231 address: *address,
232 module: Identifier::new(module.to_owned())?,
233 name: Identifier::new(name.to_owned())?,
234 type_params,
235 }))
236 }
237 })
238 }
239}
240
241impl StructInput {
242 pub fn to_canonical_string(&self, with_prefix: bool) -> String {
257 self.to_canonical_display(with_prefix).to_string()
258 }
259
260 pub fn to_canonical_display(&self, with_prefix: bool) -> impl std::fmt::Display + '_ {
263 struct CanonicalDisplay<'a> {
264 data: &'a StructInput,
265 with_prefix: bool,
266 }
267
268 impl std::fmt::Display for CanonicalDisplay<'_> {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 write!(
271 f,
272 "{}::{}::{}",
273 self.data.address.to_canonical_display(self.with_prefix),
274 self.data.module,
275 self.data.name
276 )?;
277
278 if let Some(first_ty) = self.data.type_params.first() {
279 write!(f, "<")?;
280 write!(f, "{}", first_ty.to_canonical_display(self.with_prefix))?;
281 for ty in self.data.type_params.iter().skip(1) {
282 write!(f, ",{}", ty.to_canonical_display(self.with_prefix))?;
286 }
287 write!(f, ">")?;
288 }
289 Ok(())
290 }
291 }
292
293 CanonicalDisplay {
294 data: self,
295 with_prefix,
296 }
297 }
298}
299
300impl From<TypeTag> for TypeInput {
301 fn from(tag: TypeTag) -> Self {
302 match tag {
303 TypeTag::Bool => TypeInput::Bool,
304 TypeTag::U8 => TypeInput::U8,
305 TypeTag::U64 => TypeInput::U64,
306 TypeTag::U128 => TypeInput::U128,
307 TypeTag::Address => TypeInput::Address,
308 TypeTag::Signer => TypeInput::Signer,
309 TypeTag::Vector(inner) => TypeInput::Vector(Box::new(TypeInput::from(*inner))),
310 TypeTag::Struct(inner) => TypeInput::Struct(Box::new(StructInput::from(*inner))),
311 TypeTag::U16 => TypeInput::U16,
312 TypeTag::U32 => TypeInput::U32,
313 TypeTag::U256 => TypeInput::U256,
314 }
315 }
316}
317
318impl From<StructTag> for StructInput {
319 fn from(tag: StructTag) -> Self {
320 StructInput {
321 address: tag.address,
322 module: tag.module.to_string(),
323 name: tag.name.to_string(),
324 type_params: tag.type_params.into_iter().map(TypeInput::from).collect(),
325 }
326 }
327}
328
329impl From<StructInput> for TypeInput {
330 fn from(t: StructInput) -> TypeInput {
331 TypeInput::Struct(Box::new(t))
332 }
333}
334
335impl Display for StructInput {
336 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
337 write!(
338 f,
339 "0x{}::{}::{}",
340 self.address.short_str_lossless(),
341 self.module,
342 self.name
343 )?;
344
345 let mut prefix = "<";
346 for ty in &self.type_params {
347 write!(f, "{prefix}{ty}")?;
348 prefix = ", ";
349 }
350 if !self.type_params.is_empty() {
351 write!(f, ">")?;
352 }
353
354 Ok(())
355 }
356}
357
358impl Display for TypeInput {
359 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
360 match self {
361 TypeInput::Struct(s) => write!(f, "{s}"),
362 TypeInput::Vector(ty) => write!(f, "vector<{ty}>"),
363 TypeInput::U8 => write!(f, "u8"),
364 TypeInput::U16 => write!(f, "u16"),
365 TypeInput::U32 => write!(f, "u32"),
366 TypeInput::U64 => write!(f, "u64"),
367 TypeInput::U128 => write!(f, "u128"),
368 TypeInput::U256 => write!(f, "u256"),
369 TypeInput::Address => write!(f, "address"),
370 TypeInput::Signer => write!(f, "signer"),
371 TypeInput::Bool => write!(f, "bool"),
372 }
373 }
374}
375
376#[cfg(test)]
377mod test {
378 use iota_enum_compat_util::check_enum_compat_order;
379
380 use super::TypeInput;
381
382 #[test]
383 fn enforce_order_test() {
384 let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
385 path.extend(["tests", "staged", "type_input.yaml"]);
386 check_enum_compat_order::<TypeInput>(path);
387 }
388}