use proc_macro_error::abort; #[allow(unused_imports)] use std::iter::FromIterator; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use syn::{ parse_macro_input, spanned::Spanned, visit_mut::VisitMut, }; #[allow(unused_imports)] use quote::{quote, ToTokens}; use crate::{ MACRO_MAYBE_NAME, params::{ConvertMode, MacroParameters}, utils::{unwrap_or_error}, visit_ext::Visitor, visitor_async::{ AsyncAwaitVisitor, remove_asyncness_on_trait, remove_asyncness_on_impl, remove_asyncness_on_fn}, visitor_content::ContentVisitor, debug::* }; //////////////////////////////////////////////////////////////////////////////////////////////////// pub fn maybe(args: TokenStream, input: TokenStream) -> TokenStream { dump_maybe!(&args, &input); let params = unwrap_or_error!(MacroParameters::from_tokens(args)); dump_params!("maybe params", ¶ms); if params.disable_get() { return input; } if let Some(convert_mode) = params.mode_get() { return convert(params, input, convert_mode) } let mut tokens = TokenStream::new(); for version in ¶ms.versions { let mut ts = TokenStream2::new(); match version.kind { ConvertMode::IntoAsync | ConvertMode::IntoSync => { let _ = unwrap_or_error!(version .params .extend_tokenstream2_with_cfg_outer_attrs(&mut ts)); let name = params.make_self_path(MACRO_MAYBE_NAME); let args = version.params.to_tokens(Some(version.kind)); ts.extend(quote!(#[#name(#args)])); let _ = unwrap_or_error!(version.params.extend_tokenstream2_with_inner_attrs(&mut ts)); } } let ts: TokenStream = ts.into(); tokens.extend(ts); tokens.extend(input.clone()); } dump_tokens!("maybe after", &tokens); tokens } //////////////////////////////////////////////////////////////////////////////////////////////////// pub fn convert(mut params: MacroParameters, input: TokenStream, convert_mode: ConvertMode) -> TokenStream { dump_tokens!("convert before", &input); let mut file = parse_macro_input!(input as syn::File); for item in &mut file.items { match item { syn::Item::Impl(item) => convert_impl(&mut params, item, convert_mode), syn::Item::Struct(item) => convert_struct(&mut params, item, convert_mode), syn::Item::Enum(item) => convert_enum(&mut params, item, convert_mode), syn::Item::Trait(item) => convert_trait(&mut params, item, convert_mode), syn::Item::Fn(item) => convert_fn(&mut params, item, convert_mode), syn::Item::Use(item) => convert_use(&mut params, item, convert_mode), syn::Item::Mod(item) => convert_mod(&mut params, item, convert_mode), _ => { abort!(item.span(), "Allowed impl, struct, enum, trait, fn or use items only"); } } } let ts = quote!(#file); dump_tokens2!("convert after", &ts); ts.into() } fn convert_impl(params: &mut MacroParameters, item: &mut syn::ItemImpl, convert_mode: ConvertMode) { match &mut *item.self_ty { syn::Type::Path(syn::TypePath { path, .. }) => { if let Some(last) = path.segments.last_mut() { params.original_self_name_set(last.ident.to_string(), false); } } _ => {} }; if !params.recursive_asyncness_removal_get() { remove_asyncness_on_impl( item, convert_mode, params.send_get() ); } let mut visitor = Visitor::new(AsyncAwaitVisitor::new(params, convert_mode)); visitor.visit_item_impl_mut(item) } fn convert_struct(params: &mut MacroParameters, item: &mut syn::ItemStruct, convert_mode: ConvertMode) { params.original_self_name_set(item.ident.to_string(), false); let mut visitor = Visitor::new(AsyncAwaitVisitor::new(params, convert_mode)); visitor.visit_item_struct_mut(item) } fn convert_enum(params: &mut MacroParameters, item: &mut syn::ItemEnum, convert_mode: ConvertMode) { params.original_self_name_set(item.ident.to_string(), false); let mut visitor = Visitor::new(AsyncAwaitVisitor::new(params, convert_mode)); visitor.visit_item_enum_mut(item) } fn convert_trait(params: &mut MacroParameters, item: &mut syn::ItemTrait, convert_mode: ConvertMode) { params.original_self_name_set(item.ident.to_string(), false); if !params.recursive_asyncness_removal_get() { remove_asyncness_on_trait(item, convert_mode); } let mut visitor = Visitor::new(AsyncAwaitVisitor::new(params, convert_mode)); visitor.visit_item_trait_mut(item) } fn convert_fn(params: &mut MacroParameters, item: &mut syn::ItemFn, convert_mode: ConvertMode) { params.original_self_name_set(item.sig.ident.to_string(), true); if !params.recursive_asyncness_removal_get() { remove_asyncness_on_fn(item, convert_mode); } let mut visitor = Visitor::new(AsyncAwaitVisitor::new(params, convert_mode)); visitor.visit_item_fn_mut(item) } fn convert_use(params: &mut MacroParameters, item: &mut syn::ItemUse, convert_mode: ConvertMode) { let mut visitor = Visitor::new(AsyncAwaitVisitor::new(params, convert_mode)); visitor.visit_item_use_mut(item) } fn convert_mod(params: &mut MacroParameters, item: &mut syn::ItemMod, convert_mode: ConvertMode) { params.original_self_name_set(item.ident.to_string(), true); let mut visitor = Visitor::new(AsyncAwaitVisitor::new(params, convert_mode)); visitor.visit_item_mod_mut(item) } //////////////////////////////////////////////////////////////////////////////////////////////////// pub fn content(body: TokenStream) -> TokenStream { dump_tokens!("content before", &body); let mut visitor = Visitor::new(ContentVisitor::new()); let ts: TokenStream = visitor.process(body.into()).into(); dump_tokens!("content after", &ts); ts }