cynic_codegen/inline_fragments_derive/
inline_fragments_impl.rs1use {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}