use super::{
Constructor,
Message,
};
use crate::{
error::ExtError as _,
ir,
ir::attrs::Attrs as _,
};
use syn::spanned::Spanned as _;
#[derive(Debug, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum ImplItem {
Constructor(Constructor),
Message(Message),
Other(syn::ImplItem),
}
impl quote::ToTokens for ImplItem {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
Self::Constructor(constructor) => constructor.to_tokens(tokens),
Self::Message(message) => message.to_tokens(tokens),
Self::Other(other) => other.to_tokens(tokens),
}
}
}
impl TryFrom<syn::ImplItem> for ImplItem {
type Error = syn::Error;
fn try_from(impl_item: syn::ImplItem) -> Result<Self, Self::Error> {
match impl_item {
syn::ImplItem::Method(method_item) => {
if !ir::contains_ink_attributes(&method_item.attrs) {
return Ok(Self::Other(method_item.into()))
}
let attr = ir::first_ink_attribute(&method_item.attrs)?
.expect("missing expected ink! attribute for struct");
match attr.first().kind() {
ir::AttributeArg::Message => {
<Message as TryFrom<_>>::try_from(method_item)
.map(Into::into)
.map(Self::Message)
}
ir::AttributeArg::Constructor => {
<Constructor as TryFrom<_>>::try_from(method_item)
.map(Into::into)
.map(Self::Constructor)
}
_ => Err(format_err_spanned!(
method_item,
"encountered invalid ink! attribute at this point, expected either \
#[ink(message)] or #[ink(constructor) attributes"
)),
}
}
other_item => {
if ir::contains_ink_attributes(other_item.attrs()) {
let (ink_attrs, _) =
ir::partition_attributes(other_item.attrs().iter().cloned())?;
assert!(!ink_attrs.is_empty());
fn into_err(attr: &ir::InkAttribute) -> syn::Error {
format_err!(attr.span(), "encountered unexpected ink! attribute",)
}
return Err(ink_attrs[1..]
.iter()
.map(into_err)
.fold(into_err(&ink_attrs[0]), |fst, snd| fst.into_combine(snd)))
}
Ok(Self::Other(other_item))
}
}
}
}
impl ImplItem {
pub fn is_message(&self) -> bool {
self.filter_map_message().is_some()
}
pub fn filter_map_message(&self) -> Option<&Message> {
match self {
ImplItem::Message(message) => Some(message),
_ => None,
}
}
pub fn is_constructor(&self) -> bool {
self.filter_map_constructor().is_some()
}
pub fn filter_map_constructor(&self) -> Option<&Constructor> {
match self {
ImplItem::Constructor(constructor) => Some(constructor),
_ => None,
}
}
pub fn is_other_item(&self) -> bool {
self.filter_map_other_item().is_some()
}
pub fn filter_map_other_item(&self) -> Option<&syn::ImplItem> {
match self {
ImplItem::Other(rust_item) => Some(rust_item),
_ => None,
}
}
}