1#![doc = include_str!("../README.MD")]
2
3extern crate proc_macro;
4
5use convert_case::Casing;
6use proc_macro::TokenStream;
7use quote::quote;
8use syn::{Data, DeriveInput, parse_macro_input};
9
10#[proc_macro_derive(KRQLQuery, attributes(krql, serde))]
67pub fn krql_query(input: TokenStream) -> TokenStream
68{
69 let input = parse_macro_input!(input as DeriveInput);
70 let name = input.ident;
71 let name_qc = proc_macro2::Ident::new(&format!("{}QC", name), proc_macro2::Span::call_site());
72 let name_qc_ = proc_macro2::Ident::new(&format!("{}QC_", name), proc_macro2::Span::call_site());
73 let mut key_str = name.to_string().to_case(convert_case::Case::Snake);
74 let name_cc = proc_macro2::Ident::new(key_str.as_str(), proc_macro2::Span::call_site());
75 let mut tag_str = None;
76 for attribute in input.attrs
77 {
78 if attribute.path().is_ident("krql")
79 {
80 attribute
81 .parse_nested_meta(|meta| {
82 if meta.path.is_ident("key")
84 {
85 let value = meta.value()?; let s: syn::LitStr = value.parse()?; key_str = s.value();
89 Ok(())
90 }
91 else if meta.path.is_ident("tag")
92 {
93 let value = meta.value()?; let s: syn::LitStr = value.parse()?; tag_str = Some(s.value());
97 Ok(())
98 }
99 else
100 {
101 Err(meta.error("unsupported attribute"))
102 }
103 })
104 .unwrap();
105 }
106 }
107 let key = proc_macro2::Literal::string(key_str.as_str());
108 let serde_qc_ = match tag_str
109 {
110 Some(tag) =>
111 {
112 let tag = proc_macro2::Literal::string(tag.as_str());
113 quote! {
114 #[serde(tag = #tag)]
115 }
116 }
117 None => proc_macro2::TokenStream::new(),
118 };
119 let out = match input.data
120 {
121 Data::Enum(e) =>
122 {
123 let variants_iter = e.variants.iter();
124 let variants_elements_for_match: Vec<
125 syn::punctuated::Punctuated<syn::Ident, syn::Token![,]>,
126 > = e
127 .variants
128 .iter()
129 .map(|v| v.fields.iter().map(|f| f.ident.clone().unwrap()).collect())
130 .collect();
131 let variants_elements_iter_a = variants_elements_for_match.iter();
132 let variants_elements_iter_b = variants_elements_for_match.iter();
133 let variants_names_for_match: Vec<syn::Ident> =
134 e.variants.iter().map(|v| v.ident.clone()).collect();
135 let variants_names_iter_a = variants_names_for_match.iter();
136 let variants_names_iter_b = variants_names_for_match.iter();
137 quote! {
138 impl KRQLQuery for #name
139 {
140 }
141 #[derive(serde::Serialize)]
142 struct #name_qc
143 {
144 #[serde(rename = #key)]
145 pub #name_cc: #name_qc_
146 }
147
148 impl From<#name> for #name_qc
149 {
150 fn from(value: #name) -> Self
151 {
152 Self {
153 #name_cc: #name_qc_::from(value)
154 }
155 }
156 }
157
158 #[skip_serializing_none]
159 #[derive(serde::Serialize)]
160 #serde_qc_
161 enum #name_qc_
162 {
163 #(
164 #variants_iter,
165 )*
166 }
167
168 impl From<#name> for #name_qc_
169 {
170 fn from(value: #name) -> Self
171 {
172 match value {
173 #(
174 #name ::#variants_names_iter_a { #variants_elements_iter_a } => #name_qc_ ::#variants_names_iter_b { #variants_elements_iter_b},
175 )*
176 }
177 }
178 }
179 impl serde::Serialize for #name
180 {
181 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
182 where
183 S: serde::Serializer,
184 {
185 let t: #name_qc = self.clone().into();
186 t.serialize(serializer)
187 }
188 }
189 }
190 }
191 Data::Struct(s) =>
192 {
193 let fields_iter = s.fields.iter();
194 let fields_names_iter = s.fields.iter().map(|field| field.ident.as_ref().unwrap());
195 quote! {
196 impl KRQLQuery for #name
197 {
198 }
199 #[derive(serde::Serialize, serde::Deserialize)]
200 struct #name_qc
201 {
202 #[serde(rename = #key)]
203 pub #name_cc: #name_qc_
204 }
205
206 impl From<#name> for #name_qc
207 {
208 fn from(value: #name) -> Self
209 {
210 Self { #name_cc: #name_qc_::from(value) }
211 }
212 }
213
214 #[skip_serializing_none]
215 #[derive(serde::Serialize, serde::Deserialize)]
216 #serde_qc_
217 struct #name_qc_
218 {
219 #(
220 #fields_iter,
221 )*
222 }
223
224 impl From<#name> for #name_qc_
225 {
226 fn from(value: #name) -> Self
227 {
228 Self {
229 #(
230 #fields_names_iter: value.#fields_names_iter,
231 )*
232 }
233 }
234 }
235
236 impl serde::Serialize for #name
237 {
238 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
239 where
240 S: serde::Serializer,
241 {
242 let t: #name_qc = self.clone().into();
243 t.serialize(serializer)
244 }
245 }
246
247 }
248 }
249 _ => todo!(),
250 };
251 quote! {
252 #out
253
254 impl TryFrom<&#name> for crate::dbc::Query
255 {
256 type Error = crate::Error;
257 fn try_from(value: &#name) -> std::result::Result<Self, Self::Error>
258 {
259 let krql_query = serde_saphyr::to_string(value)?;
260 Ok(crate::dbc::Query::new(
261 krql_query,
262 Default::default(),
263 crate::dbc::QueryType::KRQL,
264 ))
265 }
266 }
267
268 impl TryFrom<#name> for crate::dbc::Query
269 {
270 type Error = crate::Error;
271 fn try_from(value: #name) -> std::result::Result<Self, Self::Error>
272 {
273 (&value).try_into()
274 }
275 }
276 }
277 .into()
278}