use ink_metadata::MessageSpec;
use scale_info::{form::PortableForm, Field, Type, TypeDef, TypeDefComposite, Variant};
pub trait TypeExtensions {
fn is_primitive(&self) -> bool;
fn is_ink(&self) -> bool;
fn is_ink_types(&self) -> bool;
fn is_builtin(&self) -> bool;
fn is_custom(&self) -> bool;
fn is_lang_error(&self) -> bool;
fn qualified_name(&self) -> proc_macro2::TokenStream;
}
impl TypeExtensions for Type<PortableForm> {
fn is_primitive(&self) -> bool {
matches!(
self.type_def,
TypeDef::Primitive(_) | TypeDef::Sequence(_) | TypeDef::Tuple(_) | TypeDef::Array(_)
)
}
fn is_ink(&self) -> bool {
!self.path.segments.is_empty() && self.path.segments[0] == "ink_primitives"
}
fn is_ink_types(&self) -> bool {
self.path.segments.len() > 2
&& self.path.segments[0] == "ink_primitives"
&& self.path.segments[1] == "types"
}
fn is_builtin(&self) -> bool {
self.path.segments.len() == 1
}
fn is_lang_error(&self) -> bool {
self.is_ink() && self.path.segments.last().unwrap() == "LangError"
}
fn is_custom(&self) -> bool {
!self.is_primitive() && !self.is_ink() && !self.is_builtin()
}
fn qualified_name(&self) -> proc_macro2::TokenStream {
if self.is_lang_error() {
quote::quote! { ink_wrapper_types::InkLangError }
} else if self.is_ink_types() {
let last_segment = quote::format_ident!("{}", self.path.segments.last().unwrap());
quote::quote! { ink_primitives::#last_segment }
} else {
let last_segment = quote::format_ident!("{}", self.path.segments.last().unwrap());
quote::quote! { #last_segment }
}
}
}
pub trait MessageSpecExtensions {
fn trait_name(&self) -> Option<String>;
fn method_name(&self) -> String;
}
impl MessageSpecExtensions for MessageSpec<PortableForm> {
fn trait_name(&self) -> Option<String> {
let parts = self.label().split("::").collect::<Vec<&str>>();
match parts.len() {
1 => None,
2 => Some(parts[0].to_string()),
_ => panic!(
"Nested modules in method names are unsupported yet: {}",
self.label()
),
}
}
fn method_name(&self) -> String {
self.label().split("::").last().unwrap().to_string()
}
}
pub enum Fields {
Named(Vec<(String, u32)>),
Unnamed(Vec<u32>),
}
impl From<Vec<&Field<PortableForm>>> for Fields {
fn from(fields: Vec<&Field<PortableForm>>) -> Self {
if fields.iter().all(|f| f.name.is_none()) {
Fields::Unnamed(fields.iter().map(|f| f.ty.id).collect())
} else {
Fields::Named(
fields
.iter()
.map(|f| {
(
f.name
.as_ref()
.unwrap_or_else(|| {
panic!("{:?} has a mix of named and unnamed fields", fields)
})
.to_string(),
f.ty.id,
)
})
.collect(),
)
}
}
}
pub trait AggregateFields {
fn aggregate_fields(&self) -> Fields;
}
impl AggregateFields for Variant<PortableForm> {
fn aggregate_fields(&self) -> Fields {
self.fields
.iter()
.collect::<Vec<&Field<PortableForm>>>()
.into()
}
}
impl AggregateFields for TypeDefComposite<PortableForm> {
fn aggregate_fields(&self) -> Fields {
self.fields
.iter()
.collect::<Vec<&Field<PortableForm>>>()
.into()
}
}