panda_macros/
panda_args.rs1#[derive(FromField)]
2#[darling(attributes(arg))]
3struct DeriveArgs {
4 #[darling(default)]
5 about: Option<String>,
6 #[darling(default)]
7 default: Option<syn::Lit>,
8 #[darling(default)]
9 required: bool,
10 ident: Option<syn::Ident>,
11 ty: syn::Type,
12}
13
14fn derive_args_to_mappings(
15 DeriveArgs {
16 about,
17 default,
18 ident,
19 ty,
20 required,
21 }: DeriveArgs,
22) -> (syn::Stmt, syn::Ident) {
23 let name = &ident;
24 let default = if let Some(default) = default {
25 match default {
26 syn::Lit::Str(string) => quote!(::std::string::String::from(#string)),
27 default => quote!(#default),
28 }
29 } else {
30 quote!(Default::default())
31 };
32 let about = about.unwrap_or_default();
33 (
34 syn::parse_quote!(
35 let #name = <#ty as ::panda::panda_arg::GetPandaArg>::get_panda_arg(
36 __args_ptr,
37 stringify!(#name),
38 #default,
39 #about,
40 #required
41 );
42 ),
43 ident.unwrap(),
44 )
45}
46
47fn get_field_statements(
48 fields: &syn::Fields,
49) -> Result<(Vec<syn::Stmt>, Vec<syn::Ident>), darling::Error> {
50 Ok(fields
51 .iter()
52 .map(DeriveArgs::from_field)
53 .collect::<Result<Vec<_>, _>>()?
54 .into_iter()
55 .map(derive_args_to_mappings)
56 .unzip())
57}
58
59fn get_name(attrs: &[syn::Attribute]) -> Option<String> {
60 attrs
61 .iter()
62 .find(|attr| attr.path.get_ident().map(|x| *x == "name").unwrap_or(false))
63 .map(|attr| attr.parse_meta().ok())
64 .flatten()
65 .map(|meta| {
66 if let syn::Meta::NameValue(syn::MetaNameValue {
67 lit: syn::Lit::Str(s),
68 ..
69 }) = meta
70 {
71 Some(s.value())
72 } else {
73 None
74 }
75 })
76 .flatten()
77}
78
79#[proc_macro_derive(PandaArgs, attributes(name, arg))]
80pub fn derive_panda_args(input: TokenStream) -> TokenStream {
81 let input = syn::parse_macro_input!(input as syn::ItemStruct);
82
83 let name = match get_name(&input.attrs) {
84 Some(name) => name,
85 None => {
86 return quote!(compile_error!(
87 "Missing plugin name, add `#[name = ...]` above struct"
88 ))
89 .into()
90 }
91 };
92
93 let ident = &input.ident;
94
95 match get_field_statements(&input.fields) {
96 Ok((statements, fields)) => {
97 let format_args = iter::repeat("{}={}")
98 .take(statements.len())
99 .collect::<Vec<_>>()
100 .join(",");
101 quote!(
102 impl ::panda::PandaArgs for #ident {
103 const PLUGIN_NAME: &'static str = #name;
104
105 fn from_panda_args() -> Self {
106 let name = ::std::ffi::CString::new(#name).unwrap();
107
108 unsafe {
109 let __args_ptr = ::panda::sys::panda_get_args(name.as_ptr());
110
111 #(
112 #statements
113 )*
114
115 ::panda::sys::panda_free_args(__args_ptr);
116
117 Self {
118 #(#fields),*
119 }
120 }
121 }
122
123 fn to_panda_args_str(&self) -> ::std::string::String {
124 format!(
125 concat!(#name, ":", #format_args),
126 #(
127 stringify!(#fields), self.#fields
128 ),*
129 )
130 }
131
132 fn to_panda_args(&self) -> ::std::vec::Vec<(&'static str, ::std::string::String)> {
133 ::std::vec![
134 #(
135 (stringify!(#fields), self.#fields.to_string()),
136 )*
137 ]
138 }
139 }
140 ).into()
141 }
142 Err(err) => err.write_errors().into(),
143 }
144}