1use fusen_common::fusen_attr;
2use proc_macro::TokenStream;
3use quote::{quote, ToTokens};
4use syn::{parse::Parser, parse_macro_input, Attribute, DeriveInput, Meta};
5
6mod data;
7mod handler_macro;
8mod server_macro;
9mod trait_macro;
10
11#[proc_macro_attribute]
12pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
13 let attr = HandlerAttr::from_attr(attr);
14 match attr {
15 Ok(attr) => handler_macro::fusen_handler(attr, item),
16 Err(err) => err.into_compile_error().into(),
17 }
18}
19
20#[proc_macro_attribute]
21pub fn fusen_trait(attr: TokenStream, item: TokenStream) -> TokenStream {
22 let attr = FusenAttr::from_attr(attr);
23 match attr {
24 Ok(attr) => trait_macro::fusen_trait(attr, item),
25 Err(err) => err.into_compile_error().into(),
26 }
27}
28
29#[proc_macro_derive(Data)]
30pub fn data(item: TokenStream) -> TokenStream {
31 data::data(item)
32}
33
34#[proc_macro_attribute]
35pub fn fusen_server(attr: TokenStream, item: TokenStream) -> TokenStream {
36 let attr = FusenAttr::from_attr(attr);
37 match attr {
38 Ok(attr) => server_macro::fusen_server(attr, item),
39 Err(err) => err.into_compile_error().into(),
40 }
41}
42
43#[proc_macro_attribute]
44pub fn asset(_attr: TokenStream, item: TokenStream) -> TokenStream {
45 item
46}
47
48#[proc_macro_attribute]
49pub fn url_config(attr: TokenStream, item: TokenStream) -> TokenStream {
50 let attr = UrlConfigAttr::from_attr(attr);
51 if let Err(err) = attr {
52 return err.into_compile_error().into();
53 }
54 let attr = attr.unwrap();
55 let attr = attr.attr;
56 let org_item = parse_macro_input!(item as DeriveInput);
57 let Some(attr) = attr else {
58 return syn::Error::new_spanned(
59 org_item.to_token_stream(),
60 "url_config must label to attr",
61 )
62 .into_compile_error()
63 .into();
64 };
65 let id = &org_item.ident;
66 let token = quote! {
67
68 #[derive(serde::Serialize, serde::Deserialize, Default, fusen_macro::Data)]
69 #org_item
70
71 impl #id {
72 pub fn from_url(url : &str) -> Result<Self,fusen_common::Error> {
73 let info : Vec<&str> = url.split("://").collect();
74 if info[0] != #attr {
75 return Err(format!("err1 url {}",url).into());
76 }
77 let info : Vec<&str> = info[1].split("?").collect();
78 if info[0] != stringify!(#id) {
79 return Err(format!("err2 url {}",url).into());
80 }
81 fusen_common::url::from_url(info[1])
82 }
83 pub fn to_url(&self) -> Result<String, fusen_common::Error> {
84 let mut res = String::new();
85 res.push_str(&(#attr.to_owned() + "://" + stringify!(#id) + "?" ));
86 res.push_str(&(fusen_common::url::to_url(self)?));
87 Ok(res)
88 }
89 }
90 };
91 token.into()
92}
93
94fn get_asset_by_attrs(attrs: &Vec<Attribute>) -> Result<ResourceAttr, syn::Error> {
95 for attr in attrs {
96 if let Meta::List(list) = &attr.meta {
97 if let Some(segment) = list.path.segments.first() {
98 if segment.ident == "asset" {
99 return ResourceAttr::from_attr(list.tokens.clone().into());
100 }
101 }
102 }
103 }
104 Ok(ResourceAttr::default())
105}
106
107fusen_attr! {
108 ResourceAttr,
109 path,
110 method
111}
112
113fusen_attr! {
114 UrlConfigAttr,
115 attr
116}
117
118fusen_attr! {
119 FusenAttr,
120 id,
121 version,
122 group
123}
124
125fusen_attr! {
126 HandlerAttr,
127 id
128}