Skip to main content

cynic_codegen/inline_fragments_derive/
inline_fragments_impl.rs

1use {proc_macro2::TokenStream, quote::quote_spanned, syn::spanned::Spanned};
2
3use crate::generics_for_serde;
4
5#[derive(Clone)]
6pub enum Fallback {
7    UnionUnitVariant(syn::Ident),
8    UnionVariantWithTypename(syn::Ident, syn::Type),
9    InterfaceVariant(syn::Ident, syn::Type),
10}
11
12pub struct InlineFragmentsImpl<'a> {
13    pub(super) target_enum: syn::Ident,
14    pub(super) fragments: &'a [super::Fragment],
15    pub(super) fallback: Option<Fallback>,
16    pub(super) generics: &'a syn::Generics,
17}
18
19impl quote::ToTokens for InlineFragmentsImpl<'_> {
20    fn to_tokens(&self, tokens: &mut TokenStream) {
21        use quote::{TokenStreamExt, quote};
22
23        let target_enum = &self.target_enum;
24        let inner_types = self.fragments.iter().map(|fragment| &fragment.inner_type);
25        let variant_names = self
26            .fragments
27            .iter()
28            .map(|fragment| &fragment.rust_variant_name)
29            .collect::<Vec<_>>();
30
31        let (_, ty_generics, _) = self.generics.split_for_impl();
32        let generics_with_de = generics_for_serde::with_de_and_deserialize_bounds(self.generics);
33        let (impl_generics_with_de, _, where_clause_with_de) = generics_with_de.split_for_impl();
34
35        let fallback = match &self.fallback {
36            Some(Fallback::UnionUnitVariant(variant)) => quote! {
37                <cynic::serde::de::IgnoredAny as cynic::serde::Deserialize<'de>>
38                    ::deserialize(deserializer).map(|_|
39                        #target_enum::#variant
40                    )
41            },
42            Some(Fallback::UnionVariantWithTypename(variant, ty)) => {
43                let ty_span = ty.span();
44                quote_spanned! { ty_span => {
45                        cynic::assert_type_eq_all!(#ty, String);
46                        <cynic::serde::de::IgnoredAny as cynic::serde::Deserialize<'de>>
47                            ::deserialize(deserializer).map(|_|
48                                #target_enum::#variant(typename.to_string())
49                            )
50                    }
51                }
52            }
53            Some(Fallback::InterfaceVariant(variant, ty)) => quote! {
54                <#ty as cynic::serde::Deserialize<'de>>::deserialize(deserializer).map(
55                    #target_enum::#variant
56                )
57            },
58            None => {
59                quote! {
60                    use cynic::serde::de::Error;
61                    Err(D::Error::custom(format!("Unknown type: {}", typename)))
62                }
63            }
64        };
65
66        tokens.append_all(quote! {
67            #[automatically_derived]
68            impl #impl_generics_with_de cynic::serde::Deserialize<'de> for #target_enum #ty_generics #where_clause_with_de {
69                fn deserialize<__D>(deserializer: __D) -> Result<Self, __D::Error>
70                where
71                    __D: cynic::serde::Deserializer<'de>,
72                {
73                    deserializer.deserialize_map(cynic::__private::InlineFragmentVisitor::<Self>::new())
74                }
75            }
76
77            #[automatically_derived]
78            impl #impl_generics_with_de cynic::InlineFragments<'de> for #target_enum #ty_generics #where_clause_with_de {
79                fn deserialize_variant<__D>(typename: &str, deserializer: __D) -> Result<Self, __D::Error>
80                where
81                    __D: cynic::serde::Deserializer<'de>
82                {
83                    #(
84                        if Some(typename) == <#inner_types as cynic::QueryFragment>::TYPE {
85                            return <#inner_types as cynic::serde::Deserialize<'de>>::deserialize(deserializer).map(
86                                #target_enum::#variant_names
87                            )
88                        }
89                    )*
90
91                    #fallback
92                }
93            }
94        });
95    }
96}