x_bow_macros/
lib.rs

1mod attributes;
2mod generate;
3mod helpers;
4mod utils;
5
6use attributes::{ATTRIBUTE_MODULE_PREFIX, ATTRIBUTE_PATH, ATTRIBUTE_REMOTE_TYPE};
7use proc_macro2::TokenStream;
8use syn::{parse_macro_input, parse_quote, DeriveInput, Expr, Path};
9
10#[proc_macro_derive(IntoPath, attributes(into_path))]
11pub fn derive_into_path(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
12    let input = parse_macro_input!(input as DeriveInput);
13    let mut prefix = None;
14    const INTO_PATH: &str = "into_path";
15    const PREFIX: &str = "prefix";
16    input.attrs.iter().for_each(|attr| {
17        if attr.path().is_ident(INTO_PATH) {
18            if let Ok(syn::ExprAssign { left, right, .. }) = attr.parse_args() {
19                if let (Expr::Path(left), Expr::Path(right)) = (&*left, &*right) {
20                    if left.path.is_ident(PREFIX) {
21                        prefix = Some(right.path.clone());
22                    }
23                }
24            }
25        }
26    });
27    match helpers::into_path(
28        input,
29        prefix.unwrap_or_else(|| parse_quote!(::x_bow::__private_macro_only)),
30    ) {
31        Ok(r) => r,
32        Err(e) => e.to_compile_error(),
33    }
34    .into()
35}
36
37#[proc_macro_derive(Trackable, attributes(x_bow, track))]
38pub fn derive_trackable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
39    let input = parse_macro_input!(input as DeriveInput);
40    match derive(input) {
41        Ok(r) => r,
42        Err(e) => e.to_compile_error(),
43    }
44    .into()
45}
46fn derive(ast: DeriveInput) -> syn::Result<TokenStream> {
47    let mut remote_path = None;
48    let mut prefix_path = None;
49    ast.attrs.iter().for_each(|attr| {
50        if attr.path().is_ident(ATTRIBUTE_PATH) {
51            if let Ok(syn::ExprAssign { left, right, .. }) = attr.parse_args() {
52                if let (Expr::Path(left), Expr::Path(right)) = (&*left, &*right) {
53                    if left.path.is_ident(ATTRIBUTE_MODULE_PREFIX) {
54                        prefix_path = Some(right.path.clone());
55                    }
56                    if left.path.is_ident(ATTRIBUTE_REMOTE_TYPE) {
57                        remote_path = Some(right.path.clone());
58                    }
59                }
60            }
61        }
62    });
63    let remote_path = remote_path.unwrap_or_else(|| Path::from(ast.ident.clone()));
64    let prefix_path = prefix_path.unwrap_or_else(|| parse_quote!(::x_bow::__private_macro_only));
65    generate::generate(&ast, &remote_path, &prefix_path)
66}