split_async/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4
5use proc_macro2::TokenStream as TokenStream2;
6use syn::{Error, ImplItem, TraitItem};
7
8use quote::quote;
9use util::{SplitArgs, split_idents};
10use visit::IntoAsync;
11
12use crate::{parse::Item, visit::IntoSync};
13
14mod parse;
15mod util;
16mod visit;
17
18fn into_sync(input: &mut Item) -> TokenStream2 {
19    match input {
20        Item::Impl(item) => {
21            for inner in &mut item.items {
22                if let ImplItem::Fn(method) = inner {
23                    method.sig.asyncness = None;
24                }
25            }
26            IntoSync.into_sync(quote!(#item))
27        }
28        Item::Trait(item) => {
29            for inner in &mut item.items {
30                if let TraitItem::Fn(method) = inner {
31                    method.sig.asyncness = None;
32                }
33            }
34            IntoSync.into_sync(quote!(#item))
35        }
36        Item::Fn(item) => {
37            item.sig.asyncness = None;
38            IntoSync.into_sync(quote!(#item))
39        } // Item::Static(item) => IntoSync.into_sync(quote!(#item)),
40    }
41}
42
43fn into_async(input: &Item) -> TokenStream2 {
44    match input {
45        Item::Impl(item) => IntoAsync.into_async(quote!(#item)),
46        Item::Trait(item) => IntoAsync.into_async(quote!(#item)),
47        Item::Fn(item) => IntoAsync.into_async(quote!(#item)),
48        // Item::Static(item) => IntoAsync.into_async(quote!(#item)),
49    }
50}
51
52fn split_(args: TokenStream, input: TokenStream) -> syn::Result<TokenStream> {
53    let idents: Option<SplitArgs> = (!args.is_empty()).then(|| syn::parse(args)).transpose()?;
54
55    let item: Item = syn::parse(input)?;
56
57    let (mut sync_item, async_item) = match item {
58        Item::Fn(item_fn) => {
59            if item_fn.sig.asyncness.is_none() {
60                return Err(Error::new_spanned(&item_fn.sig, "function must be async"));
61            }
62            let idents = idents.unwrap_or_else(|| split_idents(&item_fn.sig.ident).into());
63            let mut sync_item = item_fn.clone();
64            sync_item.sig.ident = idents.0.sync_ident;
65            let mut async_item = item_fn;
66            async_item.sig.ident = idents.0.async_ident;
67            (Item::Fn(sync_item), Item::Fn(async_item))
68        }
69        _ => unimplemented!(),
70    };
71
72    let mut sync_ts = into_sync(&mut sync_item);
73    let async_ts = into_async(&async_item);
74    sync_ts.extend(async_ts);
75    Ok(sync_ts.into())
76}
77
78#[proc_macro_attribute]
79pub fn split(args: TokenStream, input: TokenStream) -> TokenStream {
80    split_(args, input).unwrap_or_else(|err| err.to_compile_error().into())
81}