abstract_impl/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#![doc = include_str!("../README.md")]
use quote::ToTokens;
use syn::punctuated::Punctuated;
use syn::token;
use syn::{parse_macro_input, ItemImpl};
mod change_self;
mod dummy;
mod mac;
mod transform;
struct IdentList(Punctuated<syn::Ident, token::Comma>);
impl syn::parse::Parse for IdentList {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(IdentList(
input.parse_terminated(syn::Ident::parse, token::Comma)?,
))
}
}
/// Define an abstract implementation for a trait, that types can use
///
/// ```
/// # use abstract_impl::abstract_impl;
/// # trait SomeTrait {
/// # fn some() -> Self;
/// # fn other(&self) -> String;
/// # }
/// #[abstract_impl]
/// impl SomeTrait for Impl where Self: Default + std::fmt::Debug {
/// fn some() -> Self {
/// Self::default()
/// }
/// fn other(&self) -> String {
/// // You have to use context here instead of self, because we don't change macro contents
/// format!("{context:?}")
/// }
/// }
/// impl_Impl!(());
/// # fn main() {
/// # assert_eq!("()", <()>::some().other());
/// # }
/// ```
#[proc_macro_attribute]
pub fn abstract_impl(
_attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let parsed = parse_macro_input!(item as ItemImpl);
let IdentList(attrs) = parse_macro_input!(_attr);
let res = transform::transform(
parsed,
attrs.iter().all(|attr| attr.to_string() != "no_dummy"),
attrs.iter().all(|attr| attr.to_string() != "no_macro"),
);
res.to_token_stream().into()
}