use proc_macro2::TokenStream;
use quote::{ quote, ToTokens };
use syn::
{
parse::{ Parse, ParseStream },
Result, Token,
Item,
spanned::Spanned, };
use core::fmt;
trait AsMuchAsPossibleNoDelimiter {}
pub struct Many< T : ToTokens >( pub Vec< T > );
impl< T > fmt::Debug for Many< T >
where T: ToTokens + fmt::Debug
{
fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> fmt::Result
{
f.debug_tuple( "Many" ).field( &self.0 ).finish()
}
}
impl< T > Many< T >
where
T : ToTokens,
{
pub fn iter( &self ) -> core::slice::Iter< '_, T >
{
self.0.iter()
}
}
impl< T > IntoIterator for Many< T >
where
T : ToTokens,
{
type Item = T;
type IntoIter = std::vec::IntoIter< Self::Item >;
fn into_iter( self ) -> Self::IntoIter
{
self.0.into_iter()
}
}
impl< 'a, T > IntoIterator for &'a Many< T >
where
T : ToTokens,
{
type Item = &'a T;
type IntoIter = core::slice::Iter< 'a, T >;
fn into_iter( self ) -> Self::IntoIter
{
self.0.iter()
}
}
impl< T > quote::ToTokens for Many< T >
where
T : ToTokens,
{
fn to_tokens( &self, tokens : &mut TokenStream )
{
for item in &self.0
{
item.to_tokens( tokens );
}
}
}
pub struct Item2
{
pub optional : Option< Token![ ? ] >,
pub func : syn::Item,
}
impl fmt::Debug for Item2
{
fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> fmt::Result
{
f.debug_struct( "Item2" )
.field( "optional", &self.optional.is_some() ) .field( "func", &self.func.to_token_stream().to_string() ) .finish()
}
}
impl AsMuchAsPossibleNoDelimiter for Item2 {}
impl Parse for Item2
{
fn parse( input : ParseStream< '_ > ) -> Result< Self >
{
let optional : Option< Token![ ? ] > = input.parse()?;
let func : Item = input.parse()?;
if !matches!( func, Item::Fn( _ ) )
{
return Err( syn::Error::new( func.span(), "Expected a function item" ) );
}
Ok( Self { optional, func } )
}
}
impl ToTokens for Item2
{
fn to_tokens( &self, tokens : &mut TokenStream )
{
self.optional.to_tokens( tokens );
self.func.to_tokens( tokens );
}
}
pub struct Items2
(
pub Many< Item2 >,
);
impl fmt::Debug for Items2
{
fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> fmt::Result
{
f.debug_tuple( "Items2" ).field( &self.0 ).finish()
}
}
impl< T > Parse for Many< T >
where
T : Parse + ToTokens + AsMuchAsPossibleNoDelimiter,
{
fn parse( input : ParseStream< '_ > ) -> Result< Self >
{
let mut items = Vec::new();
while !input.is_empty()
{
let item : T = input.parse()?;
items.push( item );
}
Ok( Self( items ) )
}
}
impl Parse for Items2
{
fn parse( input : ParseStream< '_ > ) -> Result< Self >
{
let many : Many< Item2 > = input.parse()?;
Ok( Self( many ) )
}
}
impl ToTokens for Items2
{
fn to_tokens( &self, tokens : &mut TokenStream )
{
self.0.iter().for_each( | e |
{
let func = match &e.func
{
Item::Fn( func_item ) => func_item,
_ => panic!( "Internal error: Item2 should always contain a function item at {:?}", e.func.span() ),
};
let name_ident = &func.sig.ident;
let declare_aliased = quote!
{
( as $Name2 : ident ) =>
{
impls_index::fn_rename!
{
@Name { $Name2 }
@Fn
{
#func }
}
};
};
let mut mandatory = quote!
{
#[ allow( unused_macros ) ]
};
if e.optional.is_none()
{
mandatory = quote!
{
#[ deny( unused_macros ) ]
}
}
let result = quote!
{
#mandatory
macro_rules! #name_ident {
#declare_aliased
() =>
{
#func };
}
};
result.to_tokens( tokens )
});
}
}
pub fn impls( input : proc_macro::TokenStream ) -> Result< TokenStream >
{
let items2 : Items2 = syn::parse( input )?;
let result = quote!
{
#items2
};
Ok( result )
}