1pub mod attr;
6pub mod derive;
7
8use std::collections::HashSet;
9
10use proc_macro2::TokenStream;
11use quote::{format_ident, quote, quote_spanned, ToTokens};
12use syn::{
13 ext::IdentExt as _,
14 parse::{Parse, ParseStream},
15 parse_quote,
16 punctuated::Punctuated,
17 spanned::Spanned,
18 token,
19 visit::Visit,
20};
21
22use crate::common::{
23 field, filter_attrs, gen,
24 parse::{
25 attr::{err, OptionExt as _},
26 GenericsExt as _, ParseBufferExt as _,
27 },
28 rename, scalar, AttrNames, Description, SpanContainer,
29};
30
31fn enum_idents(
37 trait_ident: &syn::Ident,
38 alias_ident: Option<&syn::Ident>,
39) -> (syn::Ident, syn::Ident) {
40 let enum_alias_ident = alias_ident
41 .cloned()
42 .unwrap_or_else(|| format_ident!("{trait_ident}Value"));
43 let enum_ident = alias_ident.map_or_else(
44 || format_ident!("{trait_ident}ValueEnum"),
45 |c| format_ident!("{c}Enum"),
46 );
47 (enum_ident, enum_alias_ident)
48}
49
50#[derive(Debug, Default)]
56struct Attr {
57 name: Option<SpanContainer<String>>,
63
64 description: Option<SpanContainer<Description>>,
72
73 r#enum: Option<SpanContainer<syn::Ident>>,
81
82 implemented_for: HashSet<SpanContainer<syn::TypePath>>,
88
89 implements: HashSet<SpanContainer<syn::TypePath>>,
95
96 context: Option<SpanContainer<syn::Type>>,
104
105 scalar: Option<SpanContainer<scalar::AttrValue>>,
118
119 asyncness: Option<SpanContainer<syn::Ident>>,
125
126 rename_fields: Option<SpanContainer<rename::Policy>>,
134
135 is_internal: bool,
138}
139
140impl Parse for Attr {
141 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
142 let mut out = Self::default();
143 while !input.is_empty() {
144 let ident = input.parse_any_ident()?;
145 match ident.to_string().as_str() {
146 "name" => {
147 input.parse::<token::Eq>()?;
148 let name = input.parse::<syn::LitStr>()?;
149 out.name
150 .replace(SpanContainer::new(
151 ident.span(),
152 Some(name.span()),
153 name.value(),
154 ))
155 .none_or_else(|_| err::dup_arg(&ident))?
156 }
157 "desc" | "description" => {
158 input.parse::<token::Eq>()?;
159 let desc = input.parse::<Description>()?;
160 out.description
161 .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
162 .none_or_else(|_| err::dup_arg(&ident))?
163 }
164 "ctx" | "context" | "Context" => {
165 input.parse::<token::Eq>()?;
166 let ctx = input.parse::<syn::Type>()?;
167 out.context
168 .replace(SpanContainer::new(ident.span(), Some(ctx.span()), ctx))
169 .none_or_else(|_| err::dup_arg(&ident))?
170 }
171 "scalar" | "Scalar" | "ScalarValue" => {
172 input.parse::<token::Eq>()?;
173 let scl = input.parse::<scalar::AttrValue>()?;
174 out.scalar
175 .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl))
176 .none_or_else(|_| err::dup_arg(&ident))?
177 }
178 "for" | "implementers" => {
179 input.parse::<token::Eq>()?;
180 for impler in input.parse_maybe_wrapped_and_punctuated::<
181 syn::TypePath, token::Bracket, token::Comma,
182 >()? {
183 let impler_span = impler.span();
184 out
185 .implemented_for
186 .replace(SpanContainer::new(ident.span(), Some(impler_span), impler))
187 .none_or_else(|_| err::dup_arg(impler_span))?;
188 }
189 }
190 "impl" | "implements" => {
191 input.parse::<token::Eq>()?;
192 for iface in input.parse_maybe_wrapped_and_punctuated::<
193 syn::TypePath, token::Bracket, token::Comma,
194 >()? {
195 let iface_span = iface.span();
196 out
197 .implements
198 .replace(SpanContainer::new(ident.span(), Some(iface_span), iface))
199 .none_or_else(|_| err::dup_arg(iface_span))?;
200 }
201 }
202 "enum" => {
203 input.parse::<token::Eq>()?;
204 let alias = input.parse::<syn::Ident>()?;
205 out.r#enum
206 .replace(SpanContainer::new(ident.span(), Some(alias.span()), alias))
207 .none_or_else(|_| err::dup_arg(&ident))?
208 }
209 "async" => {
210 let span = ident.span();
211 out.asyncness
212 .replace(SpanContainer::new(span, Some(span), ident))
213 .none_or_else(|_| err::dup_arg(span))?;
214 }
215 "rename_all" => {
216 input.parse::<token::Eq>()?;
217 let val = input.parse::<syn::LitStr>()?;
218 out.rename_fields
219 .replace(SpanContainer::new(
220 ident.span(),
221 Some(val.span()),
222 val.try_into()?,
223 ))
224 .none_or_else(|_| err::dup_arg(&ident))?;
225 }
226 "internal" => {
227 out.is_internal = true;
228 }
229 name => {
230 return Err(err::unknown_arg(&ident, name));
231 }
232 }
233 input.try_parse::<token::Comma>()?;
234 }
235 Ok(out)
236 }
237}
238
239impl Attr {
240 fn try_merge(self, mut another: Self) -> syn::Result<Self> {
243 Ok(Self {
244 name: try_merge_opt!(name: self, another),
245 description: try_merge_opt!(description: self, another),
246 context: try_merge_opt!(context: self, another),
247 scalar: try_merge_opt!(scalar: self, another),
248 implemented_for: try_merge_hashset!(implemented_for: self, another => span_joined),
249 implements: try_merge_hashset!(implements: self, another => span_joined),
250 r#enum: try_merge_opt!(r#enum: self, another),
251 asyncness: try_merge_opt!(asyncness: self, another),
252 rename_fields: try_merge_opt!(rename_fields: self, another),
253 is_internal: self.is_internal || another.is_internal,
254 })
255 }
256
257 fn from_attrs(names: impl AttrNames, attrs: &[syn::Attribute]) -> syn::Result<Self> {
260 let mut attr = filter_attrs(names, attrs)
261 .map(|attr| attr.parse_args())
262 .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
263
264 if attr.description.is_none() {
265 attr.description = Description::parse_from_doc_attrs(attrs)?;
266 }
267
268 Ok(attr)
269 }
270}
271
272struct Definition {
276 generics: syn::Generics,
281
282 vis: syn::Visibility,
287
288 enum_ident: syn::Ident,
294
295 enum_alias_ident: syn::Ident,
300
301 name: Box<str>,
305
306 description: Option<Description>,
310
311 context: syn::Type,
318
319 scalar: scalar::Type,
326
327 fields: Vec<field::Definition>,
332
333 implemented_for: Vec<syn::TypePath>,
337
338 implements: Vec<syn::TypePath>,
343
344 suppress_dead_code: Option<(syn::Ident, syn::Fields)>,
351
352 src_intra_doc_link: Box<str>,
357}
358
359impl ToTokens for Definition {
360 fn to_tokens(&self, into: &mut TokenStream) {
361 self.generate_enum_tokens().to_tokens(into);
362 self.impl_graphql_interface_tokens().to_tokens(into);
363 self.impl_output_type_tokens().to_tokens(into);
364 self.impl_graphql_type_tokens().to_tokens(into);
365 self.impl_graphql_value_tokens().to_tokens(into);
366 self.impl_graphql_value_async_tokens().to_tokens(into);
367 self.impl_reflection_traits_tokens().to_tokens(into);
368 self.impl_field_meta_tokens().to_tokens(into);
369 self.impl_field_tokens().to_tokens(into);
370 self.impl_async_field_tokens().to_tokens(into);
371 }
372}
373
374impl Definition {
375 #[must_use]
379 fn generate_enum_tokens(&self) -> TokenStream {
380 let vis = &self.vis;
381 let enum_ident = &self.enum_ident;
382 let alias_ident = &self.enum_alias_ident;
383
384 let variant_gens_pars = (0..self.implemented_for.len()).map::<syn::GenericParam, _>(|id| {
385 let par = format_ident!("__I{id}");
386 parse_quote! { #par }
387 });
388 let variants_idents = self
389 .implemented_for
390 .iter()
391 .filter_map(|ty| ty.path.segments.last().map(|seg| &seg.ident));
392
393 let interface_gens = &self.generics;
394 let (interface_impl_gens, interface_ty_gens, interface_where_clause) =
395 self.generics.split_for_impl();
396 let (interface_gens_lifetimes, interface_gens_tys) = interface_gens
397 .params
398 .clone()
399 .into_iter()
400 .partition::<Punctuated<_, _>, _>(|par| matches!(par, syn::GenericParam::Lifetime(_)));
401
402 let enum_gens = {
403 let mut enum_gens = interface_gens.clone();
404 enum_gens.params = interface_gens_lifetimes.clone();
405 enum_gens.params.extend(variant_gens_pars.clone());
406 enum_gens.params.extend(interface_gens_tys.clone());
407 enum_gens
408 };
409 let enum_alias_gens = {
410 let mut enum_alias_gens = interface_gens.clone();
411 enum_alias_gens.move_bounds_to_where_clause();
412 enum_alias_gens
413 };
414 let enum_to_alias_gens = {
415 interface_gens_lifetimes
416 .into_iter()
417 .map(|par| match par {
418 syn::GenericParam::Lifetime(def) => {
419 let lifetime = &def.lifetime;
420 quote! { #lifetime }
421 }
422 rest => quote! { #rest },
423 })
424 .chain(self.implemented_for.iter().map(ToTokens::to_token_stream))
425 .chain(interface_gens_tys.into_iter().map(|par| match par {
426 syn::GenericParam::Type(ty) => {
427 let par_ident = &ty.ident;
428 quote! { #par_ident }
429 }
430 rest => quote! { #rest },
431 }))
432 };
433 let enum_doc = format!(
434 "Enum building an opaque value represented by [`{}`]({}) \
435 [GraphQL interface][0].\
436 \n\n\
437 [0]: https://spec.graphql.org/October2021#sec-Interfaces",
438 self.name, self.src_intra_doc_link,
439 );
440 let enum_alias_doc = format!(
441 "Opaque value represented by [`{}`]({}) [GraphQL interface][0].\
442 \n\n\
443 [0]: https://spec.graphql.org/October2021#sec-Interfaces",
444 self.name, self.src_intra_doc_link,
445 );
446
447 let phantom_variant = self
448 .has_phantom_variant()
449 .then(|| {
450 let phantom_params = interface_gens.params.iter().filter_map(|p| {
451 let ty = match p {
452 syn::GenericParam::Type(ty) => {
453 let ident = &ty.ident;
454 quote! { #ident }
455 }
456 syn::GenericParam::Lifetime(lt) => {
457 let lifetime = <.lifetime;
458 quote! { &#lifetime () }
459 }
460 syn::GenericParam::Const(_) => return None,
461 };
462 Some(quote! {
463 ::core::marker::PhantomData<
464 ::core::sync::atomic::AtomicPtr<std::boxed::Box<#ty>>
465 >
466 })
467 });
468 quote! { __Phantom(#(#phantom_params),*) }
469 })
470 .into_iter();
471
472 let from_impls = self
473 .implemented_for
474 .iter()
475 .zip(variants_idents.clone())
476 .map(|(ty, ident)| {
477 quote! {
478 #[automatically_derived]
479 impl #interface_impl_gens ::core::convert::From<#ty>
480 for #alias_ident #interface_ty_gens
481 #interface_where_clause
482 {
483 fn from(v: #ty) -> Self {
484 Self::#ident(v)
485 }
486 }
487 }
488 });
489
490 quote! {
491 #[automatically_derived]
492 #[derive(::core::clone::Clone, ::core::marker::Copy, ::core::fmt::Debug)]
493 #[doc = #enum_doc]
494 #vis enum #enum_ident #enum_gens {
495 #( #[doc(hidden)] #variants_idents(#variant_gens_pars), )*
496 #( #[doc(hidden)] #phantom_variant, )*
497 }
498
499 #[automatically_derived]
500 #[doc = #enum_alias_doc]
501 #vis type #alias_ident #enum_alias_gens =
502 #enum_ident<#( #enum_to_alias_gens ),*>;
503
504 #( #from_impls )*
505 }
506 }
507
508 #[must_use]
514 fn impl_graphql_interface_tokens(&self) -> TokenStream {
515 let ty = &self.enum_alias_ident;
516 let scalar = &self.scalar;
517
518 let gens = self.impl_generics(false);
519 let (impl_generics, _, where_clause) = gens.split_for_impl();
520 let (_, ty_generics, _) = self.generics.split_for_impl();
521
522 let suppress_dead_code = self.suppress_dead_code.as_ref().map(|(ident, fields)| {
523 let const_gens = self.const_trait_generics();
524 let fields = fields.iter().map(|f| &f.ident);
525
526 quote! {{
527 const SUPPRESS_DEAD_CODE: () = {
528 let none = ::core::option::Option::<#ident #const_gens>::None;
529 match none {
530 ::core::option::Option::Some(unreachable) => {
531 #( let _ = unreachable.#fields; )*
532 }
533 ::core::option::Option::None => {}
534 }
535 };
536 let _ = SUPPRESS_DEAD_CODE;
537 }}
538 });
539
540 let implemented_for = &self.implemented_for;
541 let all_impled_for_unique = (implemented_for.len() > 1).then(|| {
542 quote! { ::juniper::sa::assert_type_ne_all!(#( #implemented_for ),*); }
543 });
544
545 let mark_object_or_interface = self.implemented_for.iter().map(|impl_for| {
546 quote_spanned! { impl_for.span() =>
547 trait GraphQLObjectOrInterface<S: ::juniper::ScalarValue, T> {
548 fn mark();
549 }
550
551 {
552 struct Object;
553
554 impl<S, T> GraphQLObjectOrInterface<S, Object> for T
555 where
556 S: ::juniper::ScalarValue,
557 T: ::juniper::marker::GraphQLObject<S>,
558 {
559 fn mark() {
560 <T as ::juniper::marker::GraphQLObject<S>>::mark()
561 }
562 }
563 }
564
565 {
566 struct Interface;
567
568 impl<S, T> GraphQLObjectOrInterface<S, Interface> for T
569 where
570 S: ::juniper::ScalarValue,
571 T: ::juniper::marker::GraphQLInterface<S>,
572 {
573 fn mark() {
574 <T as ::juniper::marker::GraphQLInterface<S>>::mark()
575 }
576 }
577 }
578
579 <#impl_for as GraphQLObjectOrInterface<#scalar, _>>::mark();
580 }
581 });
582
583 quote! {
584 #[automatically_derived]
585 impl #impl_generics ::juniper::marker::GraphQLInterface<#scalar>
586 for #ty #ty_generics
587 #where_clause
588 {
589 fn mark() {
590 #suppress_dead_code
591 #all_impled_for_unique
592 #( { #mark_object_or_interface } )*
593 }
594 }
595 }
596 }
597
598 #[must_use]
604 fn impl_output_type_tokens(&self) -> TokenStream {
605 let ty = &self.enum_alias_ident;
606 let scalar = &self.scalar;
607 let const_scalar = &self.scalar.default_ty();
608
609 let generics = self.impl_generics(false);
610 let (impl_generics, _, where_clause) = generics.split_for_impl();
611 let (_, ty_generics, _) = self.generics.split_for_impl();
612 let ty_const_generics = self.const_trait_generics();
613
614 let fields_marks = self
615 .fields
616 .iter()
617 .map(|f| f.method_mark_tokens(false, scalar));
618
619 let is_output = self.implemented_for.iter().map(|impler| {
620 quote_spanned! { impler.span() =>
621 <#impler as ::juniper::marker::IsOutputType<#scalar>>::mark();
622 }
623 });
624
625 let const_impl_for = self.implemented_for.iter().cloned().map(|mut ty| {
626 generics.replace_type_path_with_defaults(&mut ty);
627 ty
628 });
629 let const_implements = self
630 .implements
631 .iter()
632 .cloned()
633 .map(|mut ty| {
634 generics.replace_type_path_with_defaults(&mut ty);
635 ty
636 })
637 .collect::<Vec<_>>();
638 let transitive_checks = const_impl_for.clone().map(|const_impl_for| {
639 quote_spanned! { const_impl_for.span() =>
640 ::juniper::assert_transitive_impls!(
641 #const_scalar,
642 #ty #ty_const_generics,
643 #const_impl_for,
644 #( #const_implements ),*
645 );
646 }
647 });
648
649 quote! {
650 #[automatically_derived]
651 impl #impl_generics ::juniper::marker::IsOutputType<#scalar>
652 for #ty #ty_generics
653 #where_clause
654 {
655 fn mark() {
656 #( #fields_marks )*
657 #( #is_output )*
658 ::juniper::assert_interfaces_impls!(
659 #const_scalar,
660 #ty #ty_const_generics,
661 #( #const_impl_for ),*
662 );
663 ::juniper::assert_implemented_for!(
664 #const_scalar,
665 #ty #ty_const_generics,
666 #( #const_implements ),*
667 );
668 #( #transitive_checks )*
669 }
670 }
671 }
672 }
673
674 #[must_use]
680 fn impl_graphql_type_tokens(&self) -> TokenStream {
681 let ty = &self.enum_alias_ident;
682 let scalar = &self.scalar;
683
684 let generics = self.impl_generics(false);
685 let (impl_generics, _, where_clause) = generics.split_for_impl();
686 let (_, ty_generics, _) = self.generics.split_for_impl();
687
688 let name = &self.name;
689 let description = &self.description;
690
691 let mut implemented_for = self.implemented_for.clone();
693 implemented_for.sort_unstable_by(|a, b| {
694 let (a, b) = (quote!(#a).to_string(), quote!(#b).to_string());
695 a.cmp(&b)
696 });
697
698 let mut implements = self.implements.clone();
700 implements.sort_unstable_by(|a, b| {
701 let (a, b) = (quote!(#a).to_string(), quote!(#b).to_string());
702 a.cmp(&b)
703 });
704 let impl_interfaces = (!implements.is_empty()).then(|| {
705 quote! {
706 .interfaces(&[
707 #( registry.get_type::<#implements>(info), )*
708 ])
709 }
710 });
711
712 let fields_meta = self.fields.iter().map(|f| f.method_meta_tokens(None));
713
714 quote! {
715 #[automatically_derived]
716 impl #impl_generics ::juniper::GraphQLType<#scalar>
717 for #ty #ty_generics
718 #where_clause
719 {
720 fn name(
721 _ : &Self::TypeInfo,
722 ) -> ::core::option::Option<&'static ::core::primitive::str> {
723 ::core::option::Option::Some(#name)
724 }
725
726 fn meta<'r>(
727 info: &Self::TypeInfo,
728 registry: &mut ::juniper::Registry<'r, #scalar>
729 ) -> ::juniper::meta::MetaType<'r, #scalar>
730 where #scalar: 'r,
731 {
732 #( let _ = registry.get_type::<#implemented_for>(info); )*
734
735 let fields = [
736 #( #fields_meta, )*
737 ];
738 registry.build_interface_type::<#ty #ty_generics>(info, &fields)
739 #description
740 #impl_interfaces
741 .into_meta()
742 }
743 }
744 }
745 }
746
747 #[must_use]
753 fn impl_graphql_value_tokens(&self) -> TokenStream {
754 let ty = &self.enum_alias_ident;
755 let trait_name = &self.name;
756 let scalar = &self.scalar;
757 let context = &self.context;
758
759 let generics = self.impl_generics(false);
760 let (impl_generics, _, where_clause) = generics.split_for_impl();
761 let (_, ty_generics, _) = self.generics.split_for_impl();
762
763 let fields_resolvers = self.fields.iter().map(|f| {
764 let name = &f.name;
765 Some(quote! {
766 #name => {
767 ::juniper::macros::reflect::Field::<
768 #scalar,
769 { ::juniper::macros::reflect::fnv1a128(#name) }
770 >::call(self, info, args, executor)
771 }
772 })
773 });
774
775 let no_field_err =
776 field::Definition::method_resolve_field_err_no_field_tokens(scalar, trait_name);
777
778 let downcast_check = self.method_concrete_type_name_tokens();
779
780 let downcast = self.method_resolve_into_type_tokens();
781
782 quote! {
783 #[allow(deprecated)]
784 #[automatically_derived]
785 impl #impl_generics ::juniper::GraphQLValue<#scalar> for #ty #ty_generics
786 #where_clause
787 {
788 type Context = #context;
789 type TypeInfo = ();
790
791 fn type_name<'__i>(
792 &self,
793 info: &'__i Self::TypeInfo,
794 ) -> ::core::option::Option<&'__i ::core::primitive::str> {
795 <Self as ::juniper::GraphQLType<#scalar>>::name(info)
796 }
797
798 fn resolve_field(
799 &self,
800 info: &Self::TypeInfo,
801 field: &::core::primitive::str,
802 args: &::juniper::Arguments<'_, #scalar>,
803 executor: &::juniper::Executor<'_, '_, Self::Context, #scalar>,
804 ) -> ::juniper::ExecutionResult<#scalar> {
805 match field {
806 #( #fields_resolvers )*
807 _ => #no_field_err,
808 }
809 }
810
811 fn concrete_type_name(
812 &self,
813 context: &Self::Context,
814 info: &Self::TypeInfo,
815 ) -> ::std::string::String {
816 #downcast_check
817 }
818
819 fn resolve_into_type(
820 &self,
821 info: &Self::TypeInfo,
822 type_name: &::core::primitive::str,
823 _: ::core::option::Option<&[::juniper::Selection<'_, #scalar>]>,
824 executor: &::juniper::Executor<'_, '_, Self::Context, #scalar>,
825 ) -> ::juniper::ExecutionResult<#scalar> {
826 #downcast
827 }
828 }
829 }
830 }
831
832 #[must_use]
838 fn impl_graphql_value_async_tokens(&self) -> TokenStream {
839 let ty = &self.enum_alias_ident;
840 let trait_name = &self.name;
841 let scalar = &self.scalar;
842
843 let generics = self.impl_generics(true);
844 let (impl_generics, _, where_clause) = generics.split_for_impl();
845 let (_, ty_generics, _) = self.generics.split_for_impl();
846
847 let fields_resolvers = self.fields.iter().map(|f| {
848 let name = &f.name;
849 quote! {
850 #name => {
851 ::juniper::macros::reflect::AsyncField::<
852 #scalar,
853 { ::juniper::macros::reflect::fnv1a128(#name) }
854 >::call(self, info, args, executor)
855 }
856 }
857 });
858 let no_field_err =
859 field::Definition::method_resolve_field_err_no_field_tokens(scalar, trait_name);
860
861 let downcast = self.method_resolve_into_type_async_tokens();
862
863 quote! {
864 #[allow(deprecated, non_snake_case)]
865 #[automatically_derived]
866 impl #impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #ty_generics
867 #where_clause
868 {
869 fn resolve_field_async<'b>(
870 &'b self,
871 info: &'b Self::TypeInfo,
872 field: &'b ::core::primitive::str,
873 args: &'b ::juniper::Arguments<'_, #scalar>,
874 executor: &'b ::juniper::Executor<'_, '_, Self::Context, #scalar>,
875 ) -> ::juniper::BoxFuture<'b, ::juniper::ExecutionResult<#scalar>> {
876 match field {
877 #( #fields_resolvers )*
878 _ => ::std::boxed::Box::pin(async move { #no_field_err }),
879 }
880 }
881
882 fn resolve_into_type_async<'b>(
883 &'b self,
884 info: &'b Self::TypeInfo,
885 type_name: &::core::primitive::str,
886 _: ::core::option::Option<&'b [::juniper::Selection<'b, #scalar>]>,
887 executor: &'b ::juniper::Executor<'b, 'b, Self::Context, #scalar>
888 ) -> ::juniper::BoxFuture<'b, ::juniper::ExecutionResult<#scalar>> {
889 #downcast
890 }
891 }
892 }
893 }
894
895 #[must_use]
904 fn impl_reflection_traits_tokens(&self) -> TokenStream {
905 let ty = &self.enum_alias_ident;
906 let implemented_for = &self.implemented_for;
907 let implements = &self.implements;
908 let scalar = &self.scalar;
909 let name = &self.name;
910 let fields = self.fields.iter().map(|f| &f.name);
911
912 let generics = self.impl_generics(false);
913 let (impl_generics, _, where_clause) = generics.split_for_impl();
914 let (_, ty_generics, _) = self.generics.split_for_impl();
915
916 quote! {
917 #[automatically_derived]
918 impl #impl_generics ::juniper::macros::reflect::BaseType<#scalar>
919 for #ty #ty_generics
920 #where_clause
921 {
922 const NAME: ::juniper::macros::reflect::Type = #name;
923 }
924
925 #[automatically_derived]
926 impl #impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
927 for #ty #ty_generics
928 #where_clause
929 {
930 const NAMES: ::juniper::macros::reflect::Types = &[
931 <Self as ::juniper::macros::reflect::BaseType<#scalar>>::NAME,
932 #( <#implemented_for as ::juniper::macros::reflect::BaseType<#scalar>>::NAME ),*
933 ];
934 }
935
936 #[automatically_derived]
937 impl #impl_generics ::juniper::macros::reflect::Implements<#scalar>
938 for #ty #ty_generics
939 #where_clause
940 {
941 const NAMES: ::juniper::macros::reflect::Types =
942 &[#( <#implements as ::juniper::macros::reflect::BaseType<#scalar>>::NAME ),*];
943 }
944
945 #[automatically_derived]
946 impl #impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
947 for #ty #ty_generics
948 #where_clause
949 {
950 const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
951 }
952
953 #[automatically_derived]
954 impl #impl_generics ::juniper::macros::reflect::Fields<#scalar>
955 for #ty #ty_generics
956 #where_clause
957 {
958 const NAMES: ::juniper::macros::reflect::Names = &[#(#fields),*];
959 }
960 }
961 }
962
963 fn impl_field_meta_tokens(&self) -> TokenStream {
969 let ty = &self.enum_alias_ident;
970 let context = &self.context;
971 let scalar = &self.scalar;
972
973 let generics = self.impl_generics(false);
974 let (impl_generics, _, where_clause) = generics.split_for_impl();
975 let (_, ty_generics, _) = self.generics.split_for_impl();
976
977 self.fields
978 .iter()
979 .map(|field| {
980 let field_name = &field.name;
981 let mut return_ty = field.ty.clone();
982 generics.replace_type_with_defaults(&mut return_ty);
983
984 let (args_tys, args_names): (Vec<_>, Vec<_>) = field
985 .arguments
986 .iter()
987 .flat_map(|vec| vec.iter())
988 .filter_map(|arg| match arg {
989 field::MethodArgument::Regular(arg) => Some((&arg.ty, &arg.name)),
990 _ => None,
991 })
992 .unzip();
993
994 quote! {
995 #[allow(non_snake_case)]
996 #[automatically_derived]
997 impl #impl_generics ::juniper::macros::reflect::FieldMeta<
998 #scalar,
999 { ::juniper::macros::reflect::fnv1a128(#field_name) }
1000 > for #ty #ty_generics #where_clause {
1001 type Context = #context;
1002 type TypeInfo = ();
1003 const TYPE: ::juniper::macros::reflect::Type =
1004 <#return_ty as ::juniper::macros::reflect::BaseType<#scalar>>::NAME;
1005 const SUB_TYPES: ::juniper::macros::reflect::Types =
1006 <#return_ty as ::juniper::macros::reflect::BaseSubTypes<#scalar>>::NAMES;
1007 const WRAPPED_VALUE: ::juniper::macros::reflect::WrappedValue =
1008 <#return_ty as ::juniper::macros::reflect::WrappedType<#scalar>>::VALUE;
1009 const ARGUMENTS: &'static [(
1010 ::juniper::macros::reflect::Name,
1011 ::juniper::macros::reflect::Type,
1012 ::juniper::macros::reflect::WrappedValue,
1013 )] = &[#( (
1014 #args_names,
1015 <#args_tys as ::juniper::macros::reflect::BaseType<#scalar>>::NAME,
1016 <#args_tys as ::juniper::macros::reflect::WrappedType<#scalar>>::VALUE,
1017 ) ),*];
1018 }
1019 }
1020 })
1021 .collect()
1022 }
1023
1024 fn impl_field_tokens(&self) -> TokenStream {
1030 let ty = &self.enum_alias_ident;
1031 let scalar = &self.scalar;
1032 let const_scalar = self.scalar.default_ty();
1033
1034 let generics = self.impl_generics(false);
1035 let (impl_generics, _, where_clause) = generics.split_for_impl();
1036 let (_, ty_generics, _) = self.generics.split_for_impl();
1037
1038 let const_implemented_for = self
1039 .implemented_for
1040 .iter()
1041 .cloned()
1042 .map(|mut impl_for| {
1043 generics.replace_type_path_with_defaults(&mut impl_for);
1044 impl_for
1045 })
1046 .collect::<Vec<_>>();
1047 let implemented_for_idents = self
1048 .implemented_for
1049 .iter()
1050 .filter_map(|ty| ty.path.segments.last().map(|seg| &seg.ident))
1051 .collect::<Vec<_>>();
1052
1053 self.fields
1054 .iter()
1055 .map(|field| {
1056 let field_name = &field.name;
1057 let mut return_ty = field.ty.clone();
1058 generics.replace_type_with_defaults(&mut return_ty);
1059
1060 let const_ty_generics = self.const_trait_generics();
1061
1062 let unreachable_arm = (self.implemented_for.is_empty()
1063 || !self.generics.params.is_empty())
1064 .then(|| {
1065 quote! { _ => unreachable!() }
1066 });
1067
1068 quote_spanned! { field.ident.span() =>
1069 #[allow(non_snake_case)]
1070 #[automatically_derived]
1071 impl #impl_generics ::juniper::macros::reflect::Field<
1072 #scalar,
1073 { ::juniper::macros::reflect::fnv1a128(#field_name) }
1074 > for #ty #ty_generics #where_clause {
1075 fn call(
1076 &self,
1077 info: &Self::TypeInfo,
1078 args: &::juniper::Arguments<'_, #scalar>,
1079 executor: &::juniper::Executor<'_, '_, Self::Context, #scalar>,
1080 ) -> ::juniper::ExecutionResult<#scalar> {
1081 match self {
1082 #( #ty::#implemented_for_idents(v) => {
1083 ::juniper::assert_field!(
1084 #ty #const_ty_generics,
1085 #const_implemented_for,
1086 #const_scalar,
1087 #field_name,
1088 );
1089
1090 <_ as ::juniper::macros::reflect::Field::<
1091 #scalar,
1092 { ::juniper::macros::reflect::fnv1a128(#field_name) },
1093 >>::call(v, info, args, executor)
1094 } )*
1095 #unreachable_arm
1096 }
1097 }
1098 }
1099 }
1100 })
1101 .collect()
1102 }
1103
1104 fn impl_async_field_tokens(&self) -> TokenStream {
1110 let ty = &self.enum_alias_ident;
1111 let scalar = &self.scalar;
1112 let const_scalar = self.scalar.default_ty();
1113
1114 let generics = self.impl_generics(true);
1115 let (impl_generics, _, where_clause) = generics.split_for_impl();
1116 let (_, ty_generics, _) = self.generics.split_for_impl();
1117
1118 let const_implemented_for = self
1119 .implemented_for
1120 .iter()
1121 .cloned()
1122 .map(|mut impl_for| {
1123 generics.replace_type_path_with_defaults(&mut impl_for);
1124 impl_for
1125 })
1126 .collect::<Vec<_>>();
1127 let implemented_for_idents = self
1128 .implemented_for
1129 .iter()
1130 .filter_map(|ty| ty.path.segments.last().map(|seg| &seg.ident))
1131 .collect::<Vec<_>>();
1132
1133 self.fields
1134 .iter()
1135 .map(|field| {
1136 let field_name = &field.name;
1137 let mut return_ty = field.ty.clone();
1138 generics.replace_type_with_defaults(&mut return_ty);
1139
1140 let const_ty_generics = self.const_trait_generics();
1141
1142 let unreachable_arm = (self.implemented_for.is_empty()
1143 || !self.generics.params.is_empty())
1144 .then(|| {
1145 quote! { _ => unreachable!() }
1146 });
1147
1148 quote_spanned! { field.ident.span() =>
1149 #[allow(non_snake_case)]
1150 #[automatically_derived]
1151 impl #impl_generics ::juniper::macros::reflect::AsyncField<
1152 #scalar,
1153 { ::juniper::macros::reflect::fnv1a128(#field_name) }
1154 > for #ty #ty_generics #where_clause {
1155 fn call<'b>(
1156 &'b self,
1157 info: &'b Self::TypeInfo,
1158 args: &'b ::juniper::Arguments<'_, #scalar>,
1159 executor: &'b ::juniper::Executor<'_, '_, Self::Context, #scalar>,
1160 ) -> ::juniper::BoxFuture<'b, ::juniper::ExecutionResult<#scalar>> {
1161 match self {
1162 #( #ty::#implemented_for_idents(v) => {
1163 ::juniper::assert_field!(
1164 #ty #const_ty_generics,
1165 #const_implemented_for,
1166 #const_scalar,
1167 #field_name,
1168 );
1169
1170 <_ as ::juniper::macros::reflect::AsyncField<
1171 #scalar,
1172 { ::juniper::macros::reflect::fnv1a128(#field_name) },
1173 >>::call(v, info, args, executor)
1174 } )*
1175 #unreachable_arm
1176 }
1177 }
1178 }
1179 }
1180 })
1181 .collect()
1182 }
1183
1184 #[must_use]
1191 fn method_concrete_type_name_tokens(&self) -> TokenStream {
1192 let scalar = &self.scalar;
1193
1194 let match_arms = self
1195 .implemented_for
1196 .iter()
1197 .filter_map(|ty| ty.path.segments.last().map(|seg| (&seg.ident, ty)))
1198 .map(|(ident, ty)| {
1199 quote! {
1200 Self::#ident(v) => <
1201 #ty as ::juniper::GraphQLValue<#scalar>
1202 >::concrete_type_name(v, context, info),
1203 }
1204 });
1205
1206 let non_exhaustive_match_arm =
1207 (!self.generics.params.is_empty() || self.implemented_for.is_empty()).then(|| {
1208 quote! { _ => unreachable!(), }
1209 });
1210
1211 quote! {
1212 match self {
1213 #( #match_arms )*
1214 #non_exhaustive_match_arm
1215 }
1216 }
1217 }
1218
1219 #[must_use]
1227 fn method_resolve_into_type_async_tokens(&self) -> TokenStream {
1228 let resolving_code = gen::async_resolving_code(None);
1229
1230 let match_arms = self.implemented_for.iter().filter_map(|ty| {
1231 ty.path.segments.last().map(|ident| {
1232 quote! {
1233 Self::#ident(v) => {
1234 let fut = ::juniper::futures::future::ready(v);
1235 #resolving_code
1236 }
1237 }
1238 })
1239 });
1240 let non_exhaustive_match_arm =
1241 (!self.generics.params.is_empty() || self.implemented_for.is_empty()).then(|| {
1242 quote! { _ => unreachable!(), }
1243 });
1244
1245 quote! {
1246 match self {
1247 #( #match_arms )*
1248 #non_exhaustive_match_arm
1249 }
1250 }
1251 }
1252
1253 #[must_use]
1260 fn method_resolve_into_type_tokens(&self) -> TokenStream {
1261 let resolving_code = gen::sync_resolving_code();
1262
1263 let match_arms = self.implemented_for.iter().filter_map(|ty| {
1264 ty.path.segments.last().map(|ident| {
1265 quote! {
1266 Self::#ident(res) => #resolving_code,
1267 }
1268 })
1269 });
1270
1271 let non_exhaustive_match_arm =
1272 (!self.generics.params.is_empty() || self.implemented_for.is_empty()).then(|| {
1273 quote! { _ => unreachable!(), }
1274 });
1275
1276 quote! {
1277 match self {
1278 #( #match_arms )*
1279 #non_exhaustive_match_arm
1280 }
1281 }
1282 }
1283
1284 #[must_use]
1287 fn const_trait_generics(&self) -> syn::PathArguments {
1288 struct GenericsForConst(syn::AngleBracketedGenericArguments);
1289
1290 impl Visit<'_> for GenericsForConst {
1291 fn visit_generic_param(&mut self, param: &syn::GenericParam) {
1292 let arg = match param {
1293 syn::GenericParam::Lifetime(_) => parse_quote! { 'static },
1294 syn::GenericParam::Type(ty) => {
1295 if ty.default.is_none() {
1296 parse_quote! { ::juniper::DefaultScalarValue }
1297 } else {
1298 return;
1299 }
1300 }
1301 syn::GenericParam::Const(c) => {
1302 if c.default.is_none() {
1303 parse_quote!({ 0_u8 as _ })
1309 } else {
1310 return;
1311 }
1312 }
1313 };
1314 self.0.args.push(arg)
1315 }
1316 }
1317
1318 let mut visitor = GenericsForConst(parse_quote!( <> ));
1319 visitor.visit_generics(&self.generics);
1320 syn::PathArguments::AngleBracketed(visitor.0)
1321 }
1322
1323 #[must_use]
1332 fn impl_generics(&self, for_async: bool) -> syn::Generics {
1333 let mut generics = self.generics.clone();
1334
1335 let scalar = &self.scalar;
1336 if scalar.is_implicit_generic() {
1337 generics.params.push(parse_quote! { #scalar });
1338 }
1339 if scalar.is_generic() {
1340 generics
1341 .make_where_clause()
1342 .predicates
1343 .push(parse_quote! { #scalar: ::juniper::ScalarValue });
1344 }
1345 if let Some(bound) = scalar.bounds() {
1346 generics.make_where_clause().predicates.push(bound);
1347 }
1348
1349 if for_async {
1350 let self_ty = if self.generics.lifetimes().next().is_some() {
1351 let mut generics = self.generics.clone();
1354 for lt in generics.lifetimes_mut() {
1355 let ident = lt.lifetime.ident.unraw();
1356 lt.lifetime.ident = format_ident!("__fa__{ident}");
1357 }
1358
1359 let lifetimes = generics.lifetimes().map(|lt| <.lifetime);
1360 let ty = &self.enum_alias_ident;
1361 let (_, ty_generics, _) = generics.split_for_impl();
1362
1363 quote! { for<#( #lifetimes ),*> #ty #ty_generics }
1364 } else {
1365 quote! { Self }
1366 };
1367 generics
1368 .make_where_clause()
1369 .predicates
1370 .push(parse_quote! { #self_ty: ::core::marker::Sync });
1371
1372 if scalar.is_generic() {
1373 generics
1374 .make_where_clause()
1375 .predicates
1376 .push(parse_quote! { #scalar: ::core::marker::Send + ::core::marker::Sync });
1377 }
1378 }
1379
1380 generics
1381 }
1382
1383 #[must_use]
1386 fn has_phantom_variant(&self) -> bool {
1387 !self.generics.params.is_empty()
1388 }
1389}