Add *Internal custom derive variants for juniper crate

Currently, custom derives inside the main juniper crate are supported by
an ugly hack using the __juniper_use_everything macro.

This commit adds new custom derive variants that are for
main juniper crate internal use only (GraphQL{Enum,InputObject}Internal.

All custom derives inside the juniper crate are refactored to use the
new '*Internal' derives.

This allows us to
* remove the use_everything macro,
* simplify the generated code for custom derives
* support the Rust 2018 edition
This commit is contained in:
Christoph Herzog 2018-12-19 01:56:37 +01:00 committed by theduke
parent 3f1ae66b2c
commit 8dd2eafef8
18 changed files with 129 additions and 166 deletions

View file

@ -7,7 +7,7 @@ use validation::RuleError;
use value::{DefaultScalarValue, Object, Value};
use GraphQLError::ValidationError;
#[derive(GraphQLEnum, Debug)]
#[derive(GraphQLEnumInternal, Debug)]
enum Color {
Red,
Green,

View file

@ -15,33 +15,33 @@ Syntax to validate:
*/
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
enum DefaultName {
Foo,
Bar,
}
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
#[graphql(name = "ANamedEnum")]
enum Named {
Foo,
Bar,
}
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
enum NoTrailingComma {
Foo,
Bar,
}
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
#[graphql(description = "A description of the enum itself")]
enum EnumDescription {
Foo,
Bar,
}
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
enum EnumValueDescription {
#[graphql(description = "The FOO value")]
Foo,
@ -49,7 +49,7 @@ enum EnumValueDescription {
Bar,
}
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
enum EnumDeprecation {
#[graphql(deprecated = "Please don't use FOO any more")]
Foo,

View file

@ -6,47 +6,47 @@ use value::{DefaultScalarValue, Object, Value};
struct Root;
#[derive(GraphQLInputObject)]
#[derive(GraphQLInputObjectInternal)]
struct DefaultName {
field_one: String,
field_two: String,
}
#[derive(GraphQLInputObject)]
#[derive(GraphQLInputObjectInternal)]
struct NoTrailingComma {
field_one: String,
field_two: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
struct Derive {
field_one: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
#[graphql(name = "ANamedInputObject")]
struct Named {
field_one: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
#[graphql(description = "Description for the input object")]
struct Description {
field_one: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
pub struct Public {
field_one: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
#[graphql(description = "Description for the input object")]
pub struct PublicWithDescription {
field_one: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
#[graphql(
name = "APublicNamedInputObjectWithDescription",
description = "Description for the input object",
@ -55,13 +55,13 @@ pub struct NamedPublicWithDescription {
field_one: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
#[graphql(name = "APublicNamedInputObject")]
pub struct NamedPublic {
field_one: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
struct FieldDescription {
#[graphql(description = "The first field")]
field_one: String,
@ -69,7 +69,7 @@ struct FieldDescription {
field_two: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
struct FieldWithDefaults {
#[graphql(default = "123")]
field_one: i32,

View file

@ -10,7 +10,7 @@ use schema::model::RootNode;
use types::scalars::EmptyMutation;
use value::{ParseScalarResult, ParseScalarValue, Value};
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
#[graphql(name = "SampleEnum")]
enum Sample {
One,

View file

@ -32,7 +32,7 @@ graphql_scalar!(TestComplexScalar {
}
});
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
#[graphql(scalar = "DefaultScalarValue")]
struct TestInputObject {
a: Option<String>,
@ -41,20 +41,20 @@ struct TestInputObject {
d: Option<TestComplexScalar>,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
#[graphql(scalar = "DefaultScalarValue")]
struct TestNestedInputObject {
na: TestInputObject,
nb: String,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
struct ExampleInputObject {
a: Option<String>,
b: i32,
}
#[derive(GraphQLInputObject, Debug)]
#[derive(GraphQLInputObjectInternal, Debug)]
struct InputWithDefaults {
#[graphql(default = "123")]
a: i32,

View file

@ -121,20 +121,6 @@ extern crate juniper_codegen;
#[doc(hidden)]
pub use juniper_codegen::*;
// This macro is used as abstraction to make custom derives work
// in juniper itself and outside of juniper
// This macro needs to be here because it is used a derive in value::scalar
// The tests in macros are using a macro from the value module, and because
// rust macros needs to be defined before they are used it would cause problems
// to move this macro somewhere else.
#[macro_export]
#[doc(hidden)]
macro_rules! __juniper_use_everything {
() => {
pub use $crate::*;
};
}
#[macro_use]
mod value;
#[macro_use]

View file

@ -19,7 +19,7 @@ Syntax to validate:
*/
#[derive(GraphQLInputObject)]
#[derive(GraphQLInputObjectInternal)]
struct Point {
x: i32,
}

View file

@ -9,17 +9,17 @@ use schema::meta::{MetaType, ScalarMeta, EnumMeta, EnumValue, InputObjectMeta, A
use schema::model::SchemaType;
use types::scalars::EmptyMutation;
#[derive(GraphQLEnum)]
#[derive(GraphQLEnumInternal)]
enum Enum {
EnumValue
}
#[derive(GraphQLInputObject)]
#[derive(GraphQLInputObjectInternal)]
struct Bar {
foo: String,
}
#[derive(GraphQLInputObject)]
#[derive(GraphQLInputObjectInternal)]
struct Foo {
key: i32,
other: Bar,

View file

@ -57,7 +57,7 @@ pub struct DirectiveType<'a, S> {
pub arguments: Vec<Argument<'a, S>>,
}
#[derive(Clone, PartialEq, Eq, Debug, GraphQLEnum)]
#[derive(Clone, PartialEq, Eq, Debug, GraphQLEnumInternal)]
#[graphql(name = "__DirectiveLocation")]
pub enum DirectiveLocation {
Query,

View file

@ -2,7 +2,7 @@
use std::collections::HashMap;
#[derive(GraphQLEnum, Copy, Clone, Eq, PartialEq, Debug)]
#[derive(GraphQLEnumInternal, Copy, Clone, Eq, PartialEq, Debug)]
pub enum Episode {
#[graphql(name = "NEW_HOPE")]
NewHope,

View file

@ -12,7 +12,7 @@ use schema::meta::{Argument, MetaType};
///
/// The GraphQL specification defines a number of type kinds - the meta type
/// of a type.
#[derive(Clone, Eq, PartialEq, Debug, GraphQLEnum)]
#[derive(Clone, Eq, PartialEq, Debug, GraphQLEnumInternal)]
#[graphql(name = "__TypeKind")]
pub enum TypeKind {
/// ## Scalar types

View file

@ -27,7 +27,7 @@ struct ComplicatedArgs;
pub(crate) struct QueryRoot;
#[derive(Debug, GraphQLInputObject)]
#[derive(Debug, GraphQLInputObjectInternal)]
struct TestInput {
id: i32,
name: String,

View file

@ -251,7 +251,7 @@ where
/// The default scalar value representation in juniper
///
/// This types closely follows the graphql specification.
#[derive(Debug, PartialEq, Clone, ScalarValue)]
#[derive(Debug, PartialEq, Clone, GraphQLScalarValueInternal)]
#[allow(missing_docs)]
pub enum DefaultScalarValue {
Int(i32),

View file

@ -1,7 +1,7 @@
use proc_macro2::{Span, TokenStream};
use proc_macro2::{TokenStream};
use syn;
use syn::{Data, DeriveInput, Fields, Ident, Variant};
use syn::{Data, DeriveInput, Fields, Variant};
use util::*;
@ -119,7 +119,13 @@ impl EnumVariantAttrs {
}
}
pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
pub fn impl_enum(ast: &syn::DeriveInput, is_internal: bool) -> TokenStream {
let juniper_path = if is_internal {
quote!(crate)
} else {
quote!(juniper)
};
let variants = match ast.data {
Data::Enum(ref enum_data) => enum_data.variants.iter().collect::<Vec<_>>(),
_ => {
@ -166,17 +172,17 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
};
let depr = match var_attrs.deprecation {
Some(DeprecationAttr { reason: Some(s) }) => quote!{
_juniper::meta::DeprecationStatus::Deprecated(Some(#s.to_string()))
#juniper_path::meta::DeprecationStatus::Deprecated(Some(#s.to_string()))
},
Some(DeprecationAttr { reason: None }) => quote!{
_juniper::meta::DeprecationStatus::Deprecated(None)
#juniper_path::meta::DeprecationStatus::Deprecated(None)
},
None => quote!{
_juniper::meta::DeprecationStatus::Current
#juniper_path::meta::DeprecationStatus::Current
},
};
values.extend(quote!{
_juniper::meta::EnumValue{
#juniper_path::meta::EnumValue{
name: #name.to_string(),
description: #descr,
deprecation_status: #depr,
@ -185,7 +191,7 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
// Build resolve match clause.
resolves.extend(quote!{
&#ident::#var_ident => _juniper::Value::scalar(String::from(#name)),
&#ident::#var_ident => #juniper_path::Value::scalar(String::from(#name)),
});
// Build from_input clause.
@ -196,14 +202,14 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
// Build to_input clause.
to_inputs.extend(quote!{
&#ident::#var_ident =>
_juniper::InputValue::scalar(#name.to_string()),
#juniper_path::InputValue::scalar(#name.to_string()),
});
}
let body = quote! {
impl<__S> _juniper::GraphQLType<__S> for #ident
where __S: _juniper::ScalarValue,
for<'__b> &'__b __S: _juniper::ScalarRefValue<'__b>
impl<__S> #juniper_path::GraphQLType<__S> for #ident
where __S: #juniper_path::ScalarValue,
for<'__b> &'__b __S: #juniper_path::ScalarRefValue<'__b>
{
type Context = ();
type TypeInfo = ();
@ -212,8 +218,8 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
Some(#name)
}
fn meta<'r>(_: &(), registry: &mut _juniper::Registry<'r, __S>)
-> _juniper::meta::MetaType<'r, __S>
fn meta<'r>(_: &(), registry: &mut #juniper_path::Registry<'r, __S>)
-> #juniper_path::meta::MetaType<'r, __S>
where __S: 'r,
{
let meta = registry.build_enum_type::<#ident>(&(), &[
@ -226,18 +232,18 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
fn resolve(
&self,
_: &(),
_: Option<&[_juniper::Selection<__S>]>,
_: &_juniper::Executor<Self::Context, __S>
) -> _juniper::Value<__S> {
_: Option<&[#juniper_path::Selection<__S>]>,
_: &#juniper_path::Executor<Self::Context, __S>
) -> #juniper_path::Value<__S> {
match self {
#(#resolves)*
}
}
}
impl<__S: _juniper::ScalarValue> _juniper::FromInputValue<__S> for #ident {
fn from_input_value(v: &_juniper::InputValue<__S>) -> Option<#ident>
where for<'__b> &'__b __S: _juniper::ScalarRefValue<'__b>
impl<__S: #juniper_path::ScalarValue> #juniper_path::FromInputValue<__S> for #ident {
fn from_input_value(v: &#juniper_path::InputValue<__S>) -> Option<#ident>
where for<'__b> &'__b __S: #juniper_path::ScalarRefValue<'__b>
{
match v.as_enum_value().or_else(|| {
v.as_scalar_value::<String>().map(|s| s as &str)
@ -248,30 +254,13 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> TokenStream {
}
}
impl<__S: _juniper::ScalarValue> _juniper::ToInputValue<__S> for #ident {
fn to_input_value(&self) -> _juniper::InputValue<__S> {
impl<__S: #juniper_path::ScalarValue> #juniper_path::ToInputValue<__S> for #ident {
fn to_input_value(&self) -> #juniper_path::InputValue<__S> {
match self {
#(#to_inputs)*
}
}
}
};
let dummy_const = Ident::new(
&format!("_IMPL_GRAPHQLENUM_FOR_{}", ident),
Span::call_site(),
);
let generated = quote! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
#[doc(hidden)]
const #dummy_const : () = {
mod _juniper {
__juniper_use_everything!();
}
#body
};
};
generated
body
}

View file

@ -121,7 +121,13 @@ impl ObjFieldAttrs {
}
}
pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
pub fn impl_input_object(ast: &syn::DeriveInput, is_internal: bool) -> TokenStream {
let juniper_path = if is_internal {
quote!(crate)
} else {
quote!(juniper)
};
let fields = match ast.data {
Data::Struct(ref data) => match data.fields {
Fields::Named(ref named) => named.named.iter().collect::<Vec<_>>(),
@ -222,7 +228,7 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
let from_input_default = match default {
Some(ref def) => {
quote!{
Some(&&_juniper::InputValue::Null) | None if true => #def,
Some(&&#juniper_path::InputValue::Null) | None if true => #def,
}
}
None => quote!{},
@ -233,9 +239,9 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
// TODO: investigate the unwraps here, they seem dangerous!
match obj.get(#name) {
#from_input_default
Some(ref v) => _juniper::FromInputValue::from_input_value(v).unwrap(),
Some(ref v) => #juniper_path::FromInputValue::from_input_value(v).unwrap(),
None => {
_juniper::FromInputValue::from_input_value(&_juniper::InputValue::null())
#juniper_path::FromInputValue::from_input_value(&#juniper_path::InputValue::null())
.unwrap()
},
}
@ -260,10 +266,10 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
let where_clause = generics.where_clause.get_or_insert(parse_quote!(where));
where_clause
.predicates
.push(parse_quote!(__S: _juniper::ScalarValue));
.push(parse_quote!(__S: #juniper_path::ScalarValue));
where_clause
.predicates
.push(parse_quote!(for<'__b> &'__b __S: _juniper::ScalarRefValue<'__b>));
.push(parse_quote!(for<'__b> &'__b __S: #juniper_path::ScalarRefValue<'__b>));
}
Ident::new("__S", Span::call_site())
};
@ -271,7 +277,7 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
let (impl_generics, _, where_clause) = generics.split_for_impl();
let body = quote! {
impl#impl_generics _juniper::GraphQLType<#scalar> for #ident #ty_generics
impl#impl_generics #juniper_path::GraphQLType<#scalar> for #ident #ty_generics
#where_clause
{
type Context = ();
@ -283,8 +289,8 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
fn meta<'r>(
_: &(),
registry: &mut _juniper::Registry<'r, #scalar>
) -> _juniper::meta::MetaType<'r, #scalar>
registry: &mut #juniper_path::Registry<'r, #scalar>
) -> #juniper_path::meta::MetaType<'r, #scalar>
where #scalar: 'r
{
let fields = &[
@ -296,12 +302,12 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
}
}
impl#impl_generics _juniper::FromInputValue<#scalar> for #ident #ty_generics
impl#impl_generics #juniper_path::FromInputValue<#scalar> for #ident #ty_generics
#where_clause
{
fn from_input_value(value: &_juniper::InputValue<#scalar>) -> Option<Self>
fn from_input_value(value: &#juniper_path::InputValue<#scalar>) -> Option<Self>
where
for<'__b> &'__b #scalar: _juniper::ScalarRefValue<'__b>
for<'__b> &'__b #scalar: #juniper_path::ScalarRefValue<'__b>
{
if let Some(obj) = value.to_object_value() {
let item = #ident {
@ -315,32 +321,16 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> TokenStream {
}
}
impl#impl_generics _juniper::ToInputValue<#scalar> for #ident #ty_generics
impl#impl_generics #juniper_path::ToInputValue<#scalar> for #ident #ty_generics
#where_clause
{
fn to_input_value(&self) -> _juniper::InputValue<#scalar> {
_juniper::InputValue::object(vec![
fn to_input_value(&self) -> #juniper_path::InputValue<#scalar> {
#juniper_path::InputValue::object(vec![
#(#to_inputs)*
].into_iter().collect())
}
}
};
let dummy_const = Ident::new(
&format!("_IMPL_GRAPHQLINPUTOBJECT_FOR_{}", ident),
Span::call_site(),
);
let generated = quote! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
#[doc(hidden)]
const #dummy_const : () = {
mod _juniper {
__juniper_use_everything!();
}
#body
};
};
generated
body
}

View file

@ -225,7 +225,7 @@ pub fn impl_object(ast: &syn::DeriveInput) -> TokenStream {
let (impl_generics, _, where_clause) = generics.split_for_impl();
let toks = quote! {
let body = quote! {
impl#impl_generics juniper::GraphQLType<#scalar> for #ident #ty_generics
#where_clause
{
@ -271,23 +271,5 @@ pub fn impl_object(ast: &syn::DeriveInput) -> TokenStream {
}
}
};
let dummy_const = Ident::new(
format!("_IMPL_JUNIPER_SCALAR_VALUE_FOR_{}", ident).as_str(),
Span::call_site(),
);
quote!{
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
#[doc(hidden)]
const #dummy_const: () = {
mod juniper {
__juniper_use_everything!();
}
extern crate std;
#toks
};
}
body
}

View file

@ -1,8 +1,8 @@
use proc_macro2::{Span, TokenStream};
use proc_macro2::{TokenStream};
use syn::{self, Data, Fields, Ident, Variant};
pub fn impl_scalar_value(ast: &syn::DeriveInput) -> TokenStream {
pub fn impl_scalar_value(ast: &syn::DeriveInput, is_internal: bool) -> TokenStream {
let ident = &ast.ident;
let variants = match ast.data {
@ -18,29 +18,15 @@ pub fn impl_scalar_value(ast: &syn::DeriveInput) -> TokenStream {
.collect::<Result<Vec<_>, String>>()
.unwrap_or_else(|s| panic!("{}", s));
let serialize = derive_serialize(variants.iter(), ident);
let serialize = derive_serialize(variants.iter(), ident, is_internal);
let display = derive_display(variants.iter(), ident);
let dummy_const = Ident::new(
format!("_IMPL_JUNIPER_SCALAR_VALUE_FOR_{}", ident).as_str(),
Span::call_site(),
);
quote!{
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
#[doc(hidden)]
const #dummy_const: () = {
mod juniper {
__juniper_use_everything!();
}
#(#froms)*
extern crate std;
#(#froms)*
#serialize
#display
};
#serialize
#display
}
}
@ -64,7 +50,7 @@ where
}
}
fn derive_serialize<'a, I>(variants: I, ident: &Ident) -> TokenStream
fn derive_serialize<'a, I>(variants: I, ident: &Ident, is_internal: bool) -> TokenStream
where
I: Iterator<Item = &'a Variant>,
{
@ -73,10 +59,16 @@ where
quote!(#ident::#variant(ref v) => v.serialize(serializer),)
});
let serde_path = if is_internal {
quote!(crate::serde)
} else {
quote!(juniper::serde)
};
quote!{
impl juniper::serde::Serialize for #ident {
impl #serde_path::Serialize for #ident {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where S: juniper::serde::Serializer
where S: #serde_path::Serializer
{
match *self {
#(#arms)*

View file

@ -19,7 +19,7 @@ extern crate regex;
mod derive_enum;
mod derive_input_object;
mod derive_object;
mod derive_juniper_scalar_value;
mod derive_scalar_value;
mod util;
use proc_macro::TokenStream;
@ -27,14 +27,30 @@ use proc_macro::TokenStream;
#[proc_macro_derive(GraphQLEnum, attributes(graphql))]
pub fn derive_enum(input: TokenStream) -> TokenStream {
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_enum::impl_enum(&ast);
let gen = derive_enum::impl_enum(&ast, false);
gen.into()
}
#[proc_macro_derive(GraphQLEnumInternal, attributes(graphql))]
#[doc(hidden)]
pub fn derive_enum_internal(input: TokenStream) -> TokenStream {
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_enum::impl_enum(&ast, true);
gen.into()
}
#[proc_macro_derive(GraphQLInputObject, attributes(graphql))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_input_object::impl_input_object(&ast);
let gen = derive_input_object::impl_input_object(&ast, false);
gen.into()
}
#[proc_macro_derive(GraphQLInputObjectInternal, attributes(graphql))]
#[doc(hidden)]
pub fn derive_input_object_internal(input: TokenStream) -> TokenStream {
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_input_object::impl_input_object(&ast, true);
gen.into()
}
@ -46,8 +62,16 @@ pub fn derive_object(input: TokenStream) -> TokenStream {
}
#[proc_macro_derive(ScalarValue)]
pub fn derive_juniper_scalar_value(input: TokenStream) -> TokenStream {
pub fn derive_scalar_value(input: TokenStream) -> TokenStream {
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_juniper_scalar_value::impl_scalar_value(&ast);
let gen = derive_scalar_value::impl_scalar_value(&ast, false);
gen.into()
}
#[proc_macro_derive(GraphQLScalarValueInternal)]
#[doc(hidden)]
pub fn derive_scalar_value_internal(input: TokenStream) -> TokenStream {
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_scalar_value::impl_scalar_value(&ast, true);
gen.into()
}