mod storage;
#[cfg(test)]
mod tests;
pub use self::storage::Storage;
use crate::{
error::ExtError as _,
ir,
ir::attrs::Attrs as _,
};
use syn::spanned::Spanned as _;
#[derive(Debug, PartialEq, Eq)]
pub enum Item {
Ink(InkItem),
Rust(syn::Item),
}
impl quote::ToTokens for Item {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
Self::Ink(ink_item) => ink_item.to_tokens(tokens),
Self::Rust(rust_item) => rust_item.to_tokens(tokens),
}
}
}
impl TryFrom<syn::Item> for Item {
type Error = syn::Error;
fn try_from(item: syn::Item) -> Result<Self, Self::Error> {
match item {
syn::Item::Struct(item_struct) => {
if !ir::contains_ink_attributes(&item_struct.attrs) {
return Ok(Self::Rust(item_struct.into()))
}
let attr = ir::first_ink_attribute(&item_struct.attrs)?
.expect("missing expected ink! attribute for struct");
match attr.first().kind() {
ir::AttributeArg::Storage => {
<ir::Storage as TryFrom<_>>::try_from(item_struct)
.map(Into::into)
.map(Self::Ink)
}
ir::AttributeArg::Event => {
<ir::Event as TryFrom<_>>::try_from(item_struct)
.map(Into::into)
.map(Self::Ink)
}
_invalid => {
Err(format_err!(
attr.span(),
"encountered unsupported ink! attribute argument on struct",
))
}
}
}
syn::Item::Impl(item_impl) => {
if !ir::ItemImpl::is_ink_impl_block(&item_impl)? {
return Ok(Self::Rust(item_impl.into()))
}
<ir::ItemImpl as TryFrom<_>>::try_from(item_impl)
.map(Into::into)
.map(Self::Ink)
}
item => {
if ir::contains_ink_attributes(item.attrs()) {
let (ink_attrs, _) =
ir::partition_attributes(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::Rust(item))
}
}
}
}
impl Item {
pub fn is_ink_item(&self) -> bool {
self.map_ink_item().is_some()
}
pub fn is_rust_item(&self) -> bool {
self.map_rust_item().is_some()
}
pub fn map_ink_item(&self) -> Option<&InkItem> {
match self {
Item::Ink(ink_item) => Some(ink_item),
_ => None,
}
}
pub fn map_rust_item(&self) -> Option<&syn::Item> {
match self {
Item::Rust(rust_item) => Some(rust_item),
_ => None,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum InkItem {
Storage(ir::Storage),
Event(ir::Event),
ImplBlock(ir::ItemImpl),
}
impl quote::ToTokens for InkItem {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
Self::Storage(storage) => storage.to_tokens(tokens),
Self::Event(event) => event.to_tokens(tokens),
Self::ImplBlock(impl_block) => impl_block.to_tokens(tokens),
}
}
}
impl InkItem {
pub fn is_ink_item(item: &syn::Item) -> Result<bool, syn::Error> {
match item {
syn::Item::Struct(item_struct) => {
if ir::Storage::is_ink_storage(item_struct)?
|| ir::Event::is_ink_event(item_struct)?
{
return Ok(true)
}
}
syn::Item::Impl(item_impl) => {
return ir::ItemImpl::is_ink_impl_block(item_impl)
}
_ => (),
}
Ok(false)
}
}
impl From<ir::Storage> for InkItem {
fn from(storage: ir::Storage) -> Self {
Self::Storage(storage)
}
}
impl From<ir::Event> for InkItem {
fn from(event: ir::Event) -> Self {
Self::Event(event)
}
}
impl From<ir::ItemImpl> for InkItem {
fn from(impl_block: ir::ItemImpl) -> Self {
Self::ImplBlock(impl_block)
}
}
impl InkItem {
pub fn filter_map_storage_item(&self) -> Option<&ir::Storage> {
match self {
InkItem::Storage(storage) => Some(storage),
_ => None,
}
}
pub fn is_storage_item(&self) -> bool {
self.filter_map_storage_item().is_some()
}
pub fn filter_map_event_item(&self) -> Option<&ir::Event> {
match self {
InkItem::Event(event) => Some(event),
_ => None,
}
}
pub fn is_event_item(&self) -> bool {
self.filter_map_event_item().is_some()
}
pub fn filter_map_impl_block(&self) -> Option<&ir::ItemImpl> {
match self {
InkItem::ImplBlock(impl_block) => Some(impl_block),
_ => None,
}
}
pub fn is_impl_block(&self) -> bool {
self.filter_map_impl_block().is_some()
}
}