serde_query_core/
lib.rs

1mod node;
2mod parse_input;
3mod parse_query;
4mod query;
5
6#[cfg(test)]
7mod tests;
8
9use node::Node;
10use parse_input::parse_input;
11use proc_macro2::{Span, TokenStream};
12use proc_macro_error::Diagnostic;
13use syn::DeriveInput;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum DeriveTarget {
17    Deserialize,
18    DeserializeQuery,
19}
20
21pub fn generate_derive(
22    mut input: DeriveInput,
23    target: DeriveTarget,
24) -> Result<TokenStream, Vec<Diagnostic>> {
25    let parse_input_result = parse_input(&mut input);
26    if !parse_input_result.diagnostics.is_empty() {
27        return Err(parse_input_result.diagnostics);
28    }
29
30    let name = &input.ident;
31    let node = Node::from_queries(parse_input_result.queries.into_iter())?;
32    let mut stream = node.generate().map_err(|diagnostic| vec![diagnostic])?;
33
34    // generate the root code
35    match target {
36        // generate DeserializeQuery and conversion traits
37        DeriveTarget::DeserializeQuery => {
38            let wrapper_ty = syn::Ident::new("__QueryWrapper", Span::call_site());
39
40            // Inherit visibility of the wrapped struct to avoid error E0446
41            // See: https://github.com/pandaman64/serde-query/issues/7
42            let vis = input.vis;
43
44            let deserialize_impl = node.generate_deserialize(
45                name,
46                &wrapper_ty,
47                |value| quote::quote!(#wrapper_ty(#value)),
48            );
49
50            stream.extend(quote::quote! {
51                #[repr(transparent)]
52                #vis struct #wrapper_ty (#name);
53
54                #deserialize_impl
55
56                impl core::convert::From<#wrapper_ty> for #name {
57                    fn from(val: #wrapper_ty) -> Self {
58                        val.0
59                    }
60                }
61
62                impl core::ops::Deref for #wrapper_ty {
63                    type Target = #name;
64
65                    fn deref(&self) -> &Self::Target {
66                        &self.0
67                    }
68                }
69
70                impl core::ops::DerefMut for #wrapper_ty {
71                    fn deref_mut(&mut self) -> &mut Self::Target {
72                        &mut self.0
73                    }
74                }
75            });
76
77            stream.extend(quote::quote! {
78                impl<'de> serde_query::DeserializeQuery<'de> for #name {
79                    type Query = #wrapper_ty;
80                }
81            });
82        }
83        DeriveTarget::Deserialize => {
84            let deserialize_impl = node.generate_deserialize(name, name, |value| value);
85            stream.extend(deserialize_impl);
86        }
87    }
88
89    // Cargo-culting serde. Possibly for scoping?
90    Ok(quote::quote! {
91        const _: () = {
92            #stream
93        };
94    })
95}