From 48631e9b25d089a422f1bb7d2595ac14aa837464 Mon Sep 17 00:00:00 2001 From: tyranron Date: Mon, 27 Jun 2022 15:14:05 +0200 Subject: [PATCH] Impl `reflect` traits for enums --- juniper_codegen/src/common/behavior.rs | 8 ++ juniper_codegen/src/common/field/arg.rs | 2 +- juniper_codegen/src/graphql_enum/derive.rs | 1 + juniper_codegen/src/graphql_enum/mod.rs | 85 +++++++++++++++++++ juniper_codegen/src/graphql_interface/attr.rs | 8 +- .../src/graphql_interface/derive.rs | 4 +- juniper_codegen/src/graphql_object/attr.rs | 4 +- juniper_codegen/src/graphql_object/derive.rs | 4 +- juniper_codegen/src/graphql_object/mod.rs | 2 +- juniper_codegen/src/graphql_scalar/attr.rs | 4 +- juniper_codegen/src/graphql_scalar/derive.rs | 2 +- juniper_codegen/src/graphql_scalar/mod.rs | 4 +- 12 files changed, 111 insertions(+), 17 deletions(-) diff --git a/juniper_codegen/src/common/behavior.rs b/juniper_codegen/src/common/behavior.rs index d20d7c16..5976c9d0 100644 --- a/juniper_codegen/src/common/behavior.rs +++ b/juniper_codegen/src/common/behavior.rs @@ -10,6 +10,8 @@ use syn::{ parse_quote, }; +use crate::util::span_container::SpanContainer; + /// [`Behaviour`] parametrization of the code generation. /// /// [`Behaviour`]: juniper::behavior @@ -55,3 +57,9 @@ impl Type { } } } + +impl From>> for Type { + fn from(attr: Option>) -> Self { + attr.map(SpanContainer::into_inner).unwrap_or_default() + } +} diff --git a/juniper_codegen/src/common/field/arg.rs b/juniper_codegen/src/common/field/arg.rs index a65b5e70..3bd1f9f3 100644 --- a/juniper_codegen/src/common/field/arg.rs +++ b/juniper_codegen/src/common/field/arg.rs @@ -494,7 +494,7 @@ impl OnMethod { ty: argument.ty.as_ref().clone(), description: attr.description.as_ref().map(|d| d.as_ref().value()), default: attr.default.as_ref().map(|v| v.as_ref().clone()), - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), }))) } } diff --git a/juniper_codegen/src/graphql_enum/derive.rs b/juniper_codegen/src/graphql_enum/derive.rs index 7600226e..c386827b 100644 --- a/juniper_codegen/src/graphql_enum/derive.rs +++ b/juniper_codegen/src/graphql_enum/derive.rs @@ -92,6 +92,7 @@ pub(crate) fn expand(input: TokenStream) -> syn::Result { description, context, scalar, + behavior: attr.behavior.into(), values, has_ignored_variants, }; diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs index 8556d8b6..bebe05c2 100644 --- a/juniper_codegen/src/graphql_enum/mod.rs +++ b/juniper_codegen/src/graphql_enum/mod.rs @@ -18,6 +18,7 @@ use syn::{ use crate::{ common::{ + behavior, parse::{ attr::{err, OptionExt as _}, ParseBufferExt as _, @@ -71,6 +72,17 @@ struct ContainerAttr { /// [0]: https://spec.graphql.org/October2021#sec-Enums scalar: Option>, + /// Explicitly specified type of the custom [`Behavior`] to parametrize this + /// [GraphQL enum][0] implementation with. + /// + /// If [`None`], then [`behavior::Standard`] will be used for the generated + /// code. + /// + /// [`Behavior`]: juniper::behavior + /// [`behavior::Standard`]: juniper::behavior::Standard + /// [0]: https://spec.graphql.org/October2021#sec-Enums + behavior: Option>, + /// Explicitly specified [`RenameRule`] for all [values][1] of this /// [GraphQL enum][0]. /// @@ -128,6 +140,13 @@ impl Parse for ContainerAttr { .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl)) .none_or_else(|_| err::dup_arg(&ident))? } + "behave" | "behavior" => { + input.parse::()?; + let bh = input.parse::()?; + out.behavior + .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh)) + .none_or_else(|_| err::dup_arg(&ident))? + } "rename_all" => { input.parse::()?; let val = input.parse::()?; @@ -161,6 +180,7 @@ impl ContainerAttr { description: try_merge_opt!(description: self, another), context: try_merge_opt!(context: self, another), scalar: try_merge_opt!(scalar: self, another), + behavior: try_merge_opt!(behavior: self, another), rename_values: try_merge_opt!(rename_values: self, another), is_internal: self.is_internal || another.is_internal, }) @@ -389,6 +409,13 @@ struct Definition { /// [0]: https://spec.graphql.org/October2021#sec-Enums scalar: scalar::Type, + /// [`Behavior`] parametrization to generate code with for this + /// [GraphQL enum][0]. + /// + /// [`Behavior`]: juniper::behavior + /// [0]: https://spec.graphql.org/October2021#sec-Enums + behavior: behavior::Type, + /// [Values][1] of this [GraphQL enum][0]. /// /// [0]: https://spec.graphql.org/October2021#sec-Enums @@ -411,6 +438,8 @@ impl ToTokens for Definition { self.impl_from_input_value_tokens().to_tokens(into); self.impl_to_input_value_tokens().to_tokens(into); self.impl_reflection_traits_tokens().to_tokens(into); + //////////////////////////////////////////////////////////////////////// + self.impl_reflect().to_tokens(into); } } @@ -729,6 +758,47 @@ impl Definition { } } + /// Returns generated code implementing [`reflect::BaseType`], + /// [`reflect::BaseSubTypes`] and [`reflect::WrappedType`] traits for this + /// [GraphQL enum][0]. + /// + /// [`reflect::BaseSubTypes`]: juniper::reflect::BaseSubTypes + /// [`reflect::BaseType`]: juniper::reflect::BaseType + /// [`reflect::WrappedType`]: juniper::reflect::WrappedType + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_reflect(&self) -> TokenStream { + let bh = &self.behavior; + let (ty, generics) = self.ty_and_generics(); + let (impl_gens, _, where_clause) = generics.split_for_impl(); + + let name = &self.name; + + quote! { + #[automatically_derived] + impl#impl_gens ::juniper::reflect::BaseType<#bh> for #ty + #where_clause + { + const NAME: ::juniper::reflect::Type = #name; + } + + #[automatically_derived] + impl#impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty + #where_clause + { + const NAMES: ::juniper::reflect::Types = + &[>::NAME]; + } + + #[automatically_derived] + impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty + #where_clause + { + const VALUE: ::juniper::reflect::WrappedValue = + ::juniper::reflect::wrap::SINGULAR; + } + } + } + /// Returns prepared [`syn::Generics`] for [`GraphQLType`] trait (and /// similar) implementation of this enum. /// @@ -787,4 +857,19 @@ impl Definition { generics } + + /// Returns prepared self [`syn::Type`] and [`syn::Generics`] for a trait + /// implementation. + #[must_use] + fn ty_and_generics(&self) -> (syn::Type, syn::Generics) { + let generics = self.generics.clone(); + + let ty = { + let ident = &self.ident; + let (_, ty_gen, _) = generics.split_for_impl(); + parse_quote! { #ident#ty_gen } + }; + + (ty, generics) + } } diff --git a/juniper_codegen/src/graphql_interface/attr.rs b/juniper_codegen/src/graphql_interface/attr.rs index dc4a52ff..6d546411 100644 --- a/juniper_codegen/src/graphql_interface/attr.rs +++ b/juniper_codegen/src/graphql_interface/attr.rs @@ -124,7 +124,7 @@ fn expand_on_trait( description: attr.description.map(|d| d.into_inner().into_boxed_str()), context, scalar, - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), fields, implemented_for: attr .implemented_for @@ -218,7 +218,7 @@ fn parse_trait_method( description, deprecated, ident: method_ident.clone(), - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), arguments: Some(arguments), has_receiver: method.sig.receiver().is_some(), is_async: method.sig.asyncness.is_some(), @@ -313,7 +313,7 @@ fn expand_on_derive_input( description: attr.description.map(|d| d.into_inner().into_boxed_str()), context, scalar, - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), fields, implemented_for: attr .implemented_for @@ -388,7 +388,7 @@ fn parse_struct_field(field: &mut syn::Field, renaming: &RenameRule) -> Option syn::Result { description: attr.description.map(|d| d.into_inner().into_boxed_str()), context, scalar, - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), fields, implemented_for: attr .implemented_for @@ -160,7 +160,7 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option syn::Result> { .map(SpanContainer::into_inner) .unwrap_or_else(|| parse_quote! { () }), scalar, - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), fields, interfaces: attr .interfaces @@ -154,7 +154,7 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option>, /// Explicitly specified type of the custom [`Behavior`] to parametrize this - /// [GraphQL object][0] type implementation with. + /// [GraphQL object][0] implementation with. /// /// If [`None`], then [`behavior::Standard`] will be used for the generated /// code. diff --git a/juniper_codegen/src/graphql_scalar/attr.rs b/juniper_codegen/src/graphql_scalar/attr.rs index 01b34dd4..3139da74 100644 --- a/juniper_codegen/src/graphql_scalar/attr.rs +++ b/juniper_codegen/src/graphql_scalar/attr.rs @@ -64,7 +64,7 @@ fn expand_on_type_alias( specified_by_url: attr.specified_by_url.as_deref().cloned(), scalar, scalar_value: attr.scalar.as_deref().into(), - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), }; Ok(quote! { @@ -99,7 +99,7 @@ fn expand_on_derive_input( specified_by_url: attr.specified_by_url.as_deref().cloned(), scalar, scalar_value: attr.scalar.as_deref().into(), - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), }; Ok(quote! { diff --git a/juniper_codegen/src/graphql_scalar/derive.rs b/juniper_codegen/src/graphql_scalar/derive.rs index 33c0db85..552c28ba 100644 --- a/juniper_codegen/src/graphql_scalar/derive.rs +++ b/juniper_codegen/src/graphql_scalar/derive.rs @@ -38,7 +38,7 @@ pub fn expand(input: TokenStream) -> syn::Result { specified_by_url: attr.specified_by_url.as_deref().cloned(), scalar, scalar_value: attr.scalar.as_deref().into(), - behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), + behavior: attr.behavior.into(), } .to_token_stream()) } diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs index 64370796..e4ebe806 100644 --- a/juniper_codegen/src/graphql_scalar/mod.rs +++ b/juniper_codegen/src/graphql_scalar/mod.rs @@ -67,7 +67,7 @@ struct Attr { scalar: Option>, /// Explicitly specified type of the custom [`Behavior`] to parametrize this - /// [GraphQL scalar][0] type implementation with. + /// [GraphQL scalar][0] implementation with. /// /// If [`None`], then [`behavior::Standard`] will be used for the generated /// code. @@ -1721,7 +1721,7 @@ impl ParseToken { #[derive(Debug, Default)] struct FieldAttr { /// Explicitly specified type of the custom [`Behavior`] used for - /// [GraphQL scalar][0] implementation by the [`Field`]. + /// [GraphQL scalar][0] implementation by this [`Field`]. /// /// If [`None`], then [`behavior::Standard`] will be used for the generated /// code.