use super::super::InkAttribute;
use crate::{
ir::{
self,
attrs::SelectorOrWildcard,
utils,
utils::extract_cfg_attributes,
},
InputsIter,
Receiver,
};
use proc_macro2::{
Span,
TokenStream,
};
use syn::{
spanned::Spanned as _,
Result,
};
#[derive(Debug, Clone)]
pub enum InkTraitItem<'a> {
Message(InkTraitMessage<'a>),
}
impl<'a> InkTraitItem<'a> {
pub fn ident(&self) -> &syn::Ident {
match self {
Self::Message(message) => message.ident(),
}
}
pub fn ink_attrs(&self) -> InkAttribute {
match self {
Self::Message(message) => message.ink_attrs(),
}
}
pub fn filter_map_message(self) -> Option<InkTraitMessage<'a>> {
match self {
Self::Message(ink_trait_message) => Some(ink_trait_message),
}
}
}
#[derive(Debug, Clone)]
pub struct InkTraitMessage<'a> {
item: &'a syn::TraitItemFn,
}
impl<'a> InkTraitMessage<'a> {
const INVALID_ATTRIBUTES_ERRSTR: &'static str =
"encountered invalid attributes for ink! trait message";
pub(super) fn new(item: &'a syn::TraitItemFn) -> Self {
Self { item }
}
pub(super) fn extract_attributes(
span: Span,
attrs: &[syn::Attribute],
) -> Result<(InkAttribute, Vec<syn::Attribute>)> {
let (ink_attrs, non_ink_attrs) = ir::sanitize_attributes(
span,
attrs.iter().cloned(),
&ir::AttributeArgKind::Message,
|arg| {
match arg.kind() {
ir::AttributeArg::Selector(SelectorOrWildcard::Wildcard) =>
Err(Some(format_err!(arg.span(), "wildcard selectors are only supported for inherent ink! messages or constructors, not for traits."))),
ir::AttributeArg::Message
| ir::AttributeArg::Payable
| ir::AttributeArg::Default
| ir::AttributeArg::Selector(_) => Ok(()),
_ => Err(None),
}
},
)?;
Ok((ink_attrs, non_ink_attrs))
}
pub fn attrs(&self) -> Vec<syn::Attribute> {
let (_, rust_attrs) = Self::extract_attributes(self.span(), &self.item.attrs)
.expect(Self::INVALID_ATTRIBUTES_ERRSTR);
rust_attrs
}
pub fn get_cfg_attrs(&self, span: Span) -> Vec<TokenStream> {
extract_cfg_attributes(&self.attrs(), span)
}
pub fn ink_attrs(&self) -> InkAttribute {
let (ink_attrs, _) = Self::extract_attributes(self.span(), &self.item.attrs)
.expect(Self::INVALID_ATTRIBUTES_ERRSTR);
ink_attrs
}
pub fn sig(&self) -> &syn::Signature {
&self.item.sig
}
pub fn receiver(&self) -> Receiver {
match self.item.sig.inputs.iter().next() {
Some(syn::FnArg::Receiver(receiver)) => {
debug_assert!(receiver.reference.is_some());
if receiver.mutability.is_some() {
Receiver::RefMut
} else {
Receiver::Ref
}
}
_ => unreachable!("encountered invalid receiver argument for ink! message"),
}
}
pub fn inputs(&self) -> InputsIter {
InputsIter::from(self)
}
pub fn output(&self) -> Option<&syn::Type> {
match &self.item.sig.output {
syn::ReturnType::Default => None,
syn::ReturnType::Type(_, return_type) => Some(return_type),
}
}
pub fn ident(&self) -> &syn::Ident {
&self.item.sig.ident
}
pub fn local_id(&self) -> u32 {
utils::local_message_id(self.ident())
}
pub fn span(&self) -> Span {
self.item.span()
}
pub fn mutates(&self) -> bool {
self.sig()
.receiver()
.map(|receiver| receiver.mutability.is_some())
.expect("encountered missing receiver for ink! message")
}
}
impl<'a> From<&'a InkTraitMessage<'a>> for InputsIter<'a> {
fn from(message: &'a InkTraitMessage) -> Self {
Self::new(&message.item.sig.inputs)
}
}