Skip to main content

autophagy_macro/
quote.rs

1use crate::{attribute_list::AttributeList, utility::parse_crate_path};
2use proc_macro::TokenStream;
3use proc_macro2::Ident;
4use quote::quote;
5use std::error::Error;
6use syn::{Expr, ExprLit, Item, ItemFn, ItemStruct, Lit, LitStr};
7
8const RAW_STRING_PREFIX: &str = "r#";
9
10pub fn generate(attributes: &AttributeList, item: &Item) -> Result<TokenStream, Box<dyn Error>> {
11    match item {
12        Item::Fn(function) => generate_function(attributes, function),
13        Item::Struct(r#struct) => generate_struct(attributes, r#struct),
14        _ => Err("only functions and structs can be quoted".into()),
15    }
16}
17
18fn generate_function(
19    attributes: &AttributeList,
20    function: &ItemFn,
21) -> Result<TokenStream, Box<dyn Error>> {
22    let crate_path = parse_crate_path(attributes)?;
23    let ident = &function.sig.ident;
24    let visibility = &function.vis;
25    let quote_name = Ident::new(&get_quote_name(ident, "_fn"), ident.span());
26    let name_string = get_name_string(ident);
27
28    Ok(quote! {
29        #visibility fn #quote_name() -> #crate_path::Fn {
30            #crate_path::Fn::new(#name_string, syn::parse2(quote::quote!(#function)).unwrap())
31        }
32
33        #function
34    }
35    .into())
36}
37
38fn generate_struct(
39    attributes: &AttributeList,
40    r#struct: &ItemStruct,
41) -> Result<TokenStream, Box<dyn Error>> {
42    let crate_path = parse_crate_path(attributes)?;
43    let ident = &r#struct.ident;
44    let visibility = &r#struct.vis;
45    let quote_name = Ident::new(&get_quote_name(ident, "_struct"), ident.span());
46    let name_string = get_name_string(ident);
47
48    Ok(quote! {
49        #visibility fn #quote_name() -> #crate_path::Struct {
50            #crate_path::Struct::new(#name_string, syn::parse2(quote::quote!(#r#struct)).unwrap())
51        }
52
53        #r#struct
54    }
55    .into())
56}
57
58fn get_quote_name(ident: &Ident, suffix: &str) -> String {
59    ident
60        .to_string()
61        .strip_prefix(RAW_STRING_PREFIX)
62        .map(ToOwned::to_owned)
63        .unwrap_or_else(|| ident.to_string())
64        .to_lowercase()
65        + suffix
66}
67
68fn get_name_string(ident: &Ident) -> Expr {
69    Expr::Lit(ExprLit {
70        attrs: Vec::new(),
71        lit: Lit::Str(LitStr::new(&ident.to_string(), ident.span())),
72    })
73}