From 25404eb4a717d1e09d1e4f38a74551cda5db0011 Mon Sep 17 00:00:00 2001 From: tyranron <tyranron@gmail.com> Date: Fri, 17 Jun 2022 16:04:48 +0200 Subject: [PATCH] Rework meta creation [skip ci] --- juniper/src/behavior.rs | 26 +++++++++++--- juniper/src/executor/mod.rs | 68 ++++++++++++++++++++++++++--------- juniper/src/resolve/mod.rs | 4 +-- juniper/src/schema/meta.rs | 23 ++++++++++++ juniper/src/types/arc.rs | 2 +- juniper/src/types/box.rs | 2 +- juniper/src/types/nullable.rs | 7 ++-- juniper/src/types/option.rs | 7 ++-- juniper/src/types/rc.rs | 2 +- juniper/src/types/ref.rs | 2 +- juniper/src/types/ref_mut.rs | 2 +- juniper/src/types/str.rs | 12 +++---- 12 files changed, 114 insertions(+), 43 deletions(-) diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs index d7a53f27..c68cae6c 100644 --- a/juniper/src/behavior.rs +++ b/juniper/src/behavior.rs @@ -2,20 +2,38 @@ use std::{marker::PhantomData, sync::atomic::AtomicPtr}; +use crate::{meta::MetaType, resolve, Registry}; + /// Default standard behavior of GraphQL types implementation. #[derive(Debug)] pub enum Standard {} +/// Coercion of behavior types and type parameters. pub struct Coerce<T: ?Sized, From: ?Sized = Standard>(PhantomData<AtomicPtr<Box<From>>>, T); impl<T, From: ?Sized> Coerce<T, From> { #[must_use] - pub const fn wrap(val: T) -> Self { - Self(PhantomData, val) + pub const fn wrap(value: T) -> Self { + Self(PhantomData, value) } } #[must_use] -pub const fn coerce<T, From: ?Sized>(val: T) -> Coerce<T, From> { - Coerce::wrap(val) +pub const fn coerce<T, From: ?Sized>(value: T) -> Coerce<T, From> { + Coerce::wrap(value) +} + +impl<T, TI, SV, B1, B2> resolve::Type<TI, SV, B1> for Coerce<T, B2> +where + T: resolve::Type<TI, SV, B2> + ?Sized, + TI: ?Sized, + B1: ?Sized, + B2: ?Sized, +{ + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> + where + SV: 'r, + { + T::meta(registry, type_info) + } } diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs index 295af173..7c0bd8d2 100644 --- a/juniper/src/executor/mod.rs +++ b/juniper/src/executor/mod.rs @@ -84,12 +84,6 @@ where field_path: Arc<FieldPath<'a>>, } -impl<'r, 'a, Ctx: ?Sized, S> Executor<'r, 'a, Ctx, S> { - pub(crate) fn current_type_new(&self) -> &TypeType<'a, S> { - &self.current_type - } -} - /// Error type for errors that occur during query execution /// /// All execution errors contain the source position in the query of the field @@ -1297,17 +1291,58 @@ impl<'r, S: 'r> Registry<'r, S> { } */ - /// Builds a [`ScalarMeta`] information for the specified [`?Sized`] - /// [`graphql::Type`]. + /// Builds a [`ScalarMeta`] information for the specified non-[`Sized`] + /// [`graphql::Type`], and stores it in this [`Registry`]. + /// + /// # Idempotent + /// + /// If this [`Registry`] contains a [`MetaType`] with such [`TypeName`] + /// already, then just returns it without doing anything. /// /// [`graphql::Type`]: resolve::Type - pub fn build_scalar_type_unsized<T, TI>(&mut self, type_info: &TI) -> ScalarMeta<'r, S> + /// [`TypeName`]: resolve::TypeName + pub fn register_scalar_unsized<'ti, T, TI>(&mut self, type_info: &'ti TI) -> MetaType<'r, S> where T: resolve::TypeName<TI> + resolve::InputValueAsRef<S> + resolve::ScalarToken<S> + ?Sized, TI: ?Sized, + 'ti: 'r, + S: Clone, { - // TODO: Allow using references. - ScalarMeta::new_unsized::<T, _>(T::type_name(type_info).to_owned()) + // TODO: Use `drop` instead of `|_| {}` once Rust's inference becomes + // better for HRTB closures. + self.register_scalar_unsized_with::<T, TI, _>(type_info, |_| {}) + } + + /// Builds a [`ScalarMeta`] information for the specified non-[`Sized`] + /// [`graphql::Type`], allowing to `customize` the created [`ScalarMeta`], + /// and stores it in this [`Registry`]. + /// + /// # Idempotent + /// + /// If this [`Registry`] contains a [`MetaType`] with such [`TypeName`] + /// already, then just returns it without doing anything. + /// + /// [`graphql::Type`]: resolve::Type + /// [`TypeName`]: resolve::TypeName + pub fn register_scalar_unsized_with<'ti, T, TI, F>( + &mut self, + type_info: &'ti TI, + customize: F, + ) -> MetaType<'r, S> + where + T: resolve::TypeName<TI> + resolve::InputValueAsRef<S> + resolve::ScalarToken<S> + ?Sized, + TI: ?Sized, + 'ti: 'r, + F: FnOnce(&mut ScalarMeta<'r, S>), + S: Clone, + { + self.entry_type::<T, _>(type_info) + .or_insert_with(move || { + let mut scalar = ScalarMeta::new_unsized::<T, _>(T::type_name(type_info)); + customize(&mut scalar); + scalar.into_meta() + }) + .clone() } /// Creates a [`ListMeta`] type. @@ -1342,7 +1377,8 @@ impl<'r, S: 'r> Registry<'r, S> { T: resolve::Type<Info, S> + ?Sized, Info: ?Sized, { - ListMeta::new(T::meta(self, info).as_type(), expected_size) + todo!() + //ListMeta::new(T::meta(self, info).as_type(), expected_size) } /// Creates a [`NullableMeta`] type. @@ -1359,13 +1395,13 @@ impl<'r, S: 'r> Registry<'r, S> { /// [`graphql::Type`]. /// /// [`graphql::Type`]: resolve::Type - pub fn build_nullable_type_reworked<T, BH, TI>(&mut self, type_info: &TI) -> NullableMeta<'r> + pub fn wrap_nullable<'ti, T, TI>(&mut self, type_info: &'ti TI) -> MetaType<'r, S> where - T: resolve::Type<TI, S, BH> + ?Sized, - BH: ?Sized, + T: resolve::Type<TI, S> + ?Sized, TI: ?Sized, + 'ti: 'r, { - NullableMeta::new(T::meta(self, type_info).as_type()) + NullableMeta::new(T::meta(self, type_info).into()).into_meta() } /// Creates an [`ObjectMeta`] type with the given `fields`. diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs index 868ce500..353095fd 100644 --- a/juniper/src/resolve/mod.rs +++ b/juniper/src/resolve/mod.rs @@ -6,9 +6,9 @@ use crate::{ }; pub trait Type<TypeInfo: ?Sized, ScalarValue, Behavior: ?Sized = behavior::Standard> { - fn meta<'r>( + fn meta<'r, 'ti: 'r>( registry: &mut Registry<'r, ScalarValue>, - type_info: &TypeInfo, + type_info: &'ti TypeInfo, ) -> MetaType<'r, ScalarValue> where ScalarValue: 'r; // TODO: remove? diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs index 17ce8c74..73d0620d 100644 --- a/juniper/src/schema/meta.rs +++ b/juniper/src/schema/meta.rs @@ -460,6 +460,29 @@ impl<'a, S> MetaType<'a, S> { } } +impl<'a, S> From<MetaType<'a, S>> for Type<'a> { + fn from(meta: MetaType<'a, S>) -> Self { + match meta { + MetaType::Scalar(ScalarMeta { name, .. }) + | MetaType::Object(ObjectMeta { name, .. }) + | MetaType::Enum(EnumMeta { name, .. }) + | MetaType::Interface(InterfaceMeta { name, .. }) + | MetaType::Union(UnionMeta { name, .. }) + | MetaType::InputObject(InputObjectMeta { name, .. }) => Type::NonNullNamed(name), + MetaType::List(ListMeta { + of_type, + expected_size, + }) => Type::NonNullList(Box::new(of_type), expected_size), + MetaType::Nullable(NullableMeta { of_type }) => match of_type { + Type::NonNullNamed(inner) => Type::Named(inner), + Type::NonNullList(inner, expected_size) => Type::List(inner, expected_size), + t => t, + }, + MetaType::Placeholder(PlaceholderMeta { of_type }) => of_type, + } + } +} + impl<'a, S> ScalarMeta<'a, S> { /// Builds a new [`ScalarMeta`] type with the specified `name`. pub fn new<T>(name: Cow<'a, str>) -> Self diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs index ef733799..db4c6cba 100644 --- a/juniper/src/types/arc.rs +++ b/juniper/src/types/arc.rs @@ -15,7 +15,7 @@ where TI: ?Sized, BH: ?Sized, { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs index ec019461..845343d2 100644 --- a/juniper/src/types/box.rs +++ b/juniper/src/types/box.rs @@ -13,7 +13,7 @@ where TI: ?Sized, BH: ?Sized, { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs index 7728959c..ee4a861a 100644 --- a/juniper/src/types/nullable.rs +++ b/juniper/src/types/nullable.rs @@ -6,6 +6,7 @@ use futures::future; use crate::{ ast::{FromInputValue, InputValue, ToInputValue}, + behavior, executor::{ExecutionResult, Executor, Registry}, graphql, reflect, resolve, schema::meta::MetaType, @@ -278,13 +279,11 @@ where TI: ?Sized, BH: ?Sized, { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { - registry - .build_nullable_type_reworked::<T, BH, _>(type_info) - .into_meta() + registry.wrap_nullable::<behavior::Coerce<T, BH>, _>(type_info) } } diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs index 0a83cc62..cdc91941 100644 --- a/juniper/src/types/option.rs +++ b/juniper/src/types/option.rs @@ -3,6 +3,7 @@ use futures::future; use crate::{ + behavior, executor::{ExecutionResult, Executor, Registry}, graphql, reflect, resolve, schema::meta::MetaType, @@ -15,13 +16,11 @@ where TI: ?Sized, BH: ?Sized, { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { - registry - .build_nullable_type_reworked::<T, BH, _>(type_info) - .into_meta() + registry.wrap_nullable::<behavior::Coerce<T, BH>, _>(type_info) } } diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs index 950ec042..f886e910 100644 --- a/juniper/src/types/rc.rs +++ b/juniper/src/types/rc.rs @@ -15,7 +15,7 @@ where TI: ?Sized, BH: ?Sized, { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs index 9b9668fe..867f4f48 100644 --- a/juniper/src/types/ref.rs +++ b/juniper/src/types/ref.rs @@ -15,7 +15,7 @@ where TI: ?Sized, BH: ?Sized, { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs index f24b96a5..c0c479c6 100644 --- a/juniper/src/types/ref_mut.rs +++ b/juniper/src/types/ref_mut.rs @@ -15,7 +15,7 @@ where TI: ?Sized, BH: ?Sized, { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs index 0e3f862b..aeeac1ed 100644 --- a/juniper/src/types/str.rs +++ b/juniper/src/types/str.rs @@ -14,17 +14,11 @@ use crate::{ }; impl<TI: ?Sized, SV: ScalarValue> resolve::Type<TI, SV> for str { - fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV> + fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV> where SV: 'r, { - let meta = registry - .build_scalar_type_unsized::<Self, _>(type_info) - .into_meta(); - registry - .entry_type::<Self, _>(type_info) - .or_insert(meta) - .clone() + registry.register_scalar_unsized::<Self, _>(type_info) } } @@ -75,6 +69,8 @@ where SV: From<String>, { fn to_input_value(&self) -> graphql::InputValue<SV> { + // TODO: Remove redundant `.to_owned()` allocation by allowing + // `ScalarValue` creation from reference? graphql::InputValue::scalar(self.to_owned()) } }