From 56a68a9e24f2be488225d62c28f28ce6f883d3d1 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 19 Apr 2022 18:47:42 +0300
Subject: [PATCH 01/58] Bootstrap, vol.1

---
 juniper/src/graphql/mod.rs     |  1 +
 juniper/src/graphql/resolve.rs | 33 +++++++++++++++++++++++++++++++++
 juniper/src/lib.rs             |  9 +++++----
 juniper/src/resolve/mod.rs     | 12 ++++++++++++
 4 files changed, 51 insertions(+), 4 deletions(-)
 create mode 100644 juniper/src/graphql/mod.rs
 create mode 100644 juniper/src/graphql/resolve.rs
 create mode 100644 juniper/src/resolve/mod.rs

diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
new file mode 100644
index 000000000..581d1dcd4
--- /dev/null
+++ b/juniper/src/graphql/mod.rs
@@ -0,0 +1 @@
+pub mod resolve;
diff --git a/juniper/src/graphql/resolve.rs b/juniper/src/graphql/resolve.rs
new file mode 100644
index 000000000..ef411da2e
--- /dev/null
+++ b/juniper/src/graphql/resolve.rs
@@ -0,0 +1,33 @@
+use crate::{executor::Registry, resolve, schema::meta::MetaType, DefaultScalarValue};
+
+pub trait TypeName {
+    fn type_name<Info: ?Sized>(info: &Info) -> &str
+    where
+        Self: resolve::TypeName<Info>;
+}
+
+impl<T: ?Sized> TypeName for T {
+    fn type_name<Info: ?Sized>(info: &Info) -> &str
+    where
+        Self: resolve::TypeName<Info>,
+    {
+        <Self as resolve::TypeName<Info>>::type_name(info)
+    }
+}
+
+pub trait Type<S = DefaultScalarValue> {
+    fn meta<'r, Info: ?Sized>(info: &Info, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
+    where
+        S: 'r,
+        Self: resolve::Type<Info, S>;
+}
+
+impl<T: ?Sized, S> Type<S> for T {
+    fn meta<'r, Info: ?Sized>(info: &Info, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
+    where
+        S: 'r,
+        Self: resolve::Type<Info, S>,
+    {
+        <Self as resolve::Type<Info, S>>::meta(info, registry)
+    }
+}
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 0373175e2..fa869cbd0 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -28,19 +28,20 @@ pub use juniper_codegen::{
 #[doc(hidden)]
 #[macro_use]
 pub mod macros;
+
 mod ast;
 pub mod executor;
+pub mod graphql;
+pub mod http;
+pub mod integrations;
 mod introspection;
 pub mod parser;
+pub mod resolve;
 pub(crate) mod schema;
 mod types;
 mod util;
 pub mod validation;
 mod value;
-// This needs to be public until docs have support for private modules:
-// https://github.com/rust-lang/cargo/issues/1520
-pub mod http;
-pub mod integrations;
 
 #[cfg(all(test, not(feature = "expose-test-schema")))]
 mod tests;
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
new file mode 100644
index 000000000..9016b9ac8
--- /dev/null
+++ b/juniper/src/resolve/mod.rs
@@ -0,0 +1,12 @@
+use crate::{executor::Registry, schema::meta::MetaType, DefaultScalarValue, ScalarValue};
+
+pub trait TypeName<Info: ?Sized> {
+    fn type_name(info: &Info) -> &str;
+}
+
+pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
+    fn meta<'r>(info: &Info, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
+    where
+        S: 'r;
+}
+

From 4ef63e0b7c26b7b39e7e184eaba49ddb36cf0b53 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 19 Apr 2022 19:04:34 +0300
Subject: [PATCH 02/58] Bootstrap, vol.2

---
 juniper/src/executor/mod.rs    |  2 +-
 juniper/src/graphql/resolve.rs | 51 +++++++++++++++++++++++++++++++++-
 juniper/src/resolve/mod.rs     | 19 ++++++++++++-
 3 files changed, 69 insertions(+), 3 deletions(-)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 47d5fead2..cf35af155 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -69,7 +69,7 @@ pub enum FieldPath<'a> {
 /// of the current field stack, context, variables, and errors.
 pub struct Executor<'r, 'a, CtxT, S = DefaultScalarValue>
 where
-    CtxT: 'a,
+    CtxT: ?Sized + 'a,
     S: 'a,
 {
     fragments: &'r HashMap<&'a str, Fragment<'a, S>>,
diff --git a/juniper/src/graphql/resolve.rs b/juniper/src/graphql/resolve.rs
index ef411da2e..068115a86 100644
--- a/juniper/src/graphql/resolve.rs
+++ b/juniper/src/graphql/resolve.rs
@@ -1,4 +1,9 @@
-use crate::{executor::Registry, resolve, schema::meta::MetaType, DefaultScalarValue};
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    resolve,
+    schema::meta::MetaType,
+    Arguments, DefaultScalarValue,
+};
 
 pub trait TypeName {
     fn type_name<Info: ?Sized>(info: &Info) -> &str
@@ -31,3 +36,47 @@ impl<T: ?Sized, S> Type<S> for T {
         <Self as resolve::Type<Info, S>>::meta(info, registry)
     }
 }
+
+pub trait Field<S = DefaultScalarValue> {
+    fn resolve_field<Info: ?Sized, Ctx: ?Sized>(
+        &self,
+        info: &Info,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>
+    where
+        Self: resolve::Field<Info, Ctx, S>;
+}
+
+impl<T: ?Sized, S> Field<S> for T {
+    fn resolve_field<Info: ?Sized, Ctx: ?Sized>(
+        &self,
+        info: &Info,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>
+    where
+        Self: resolve::Field<Info, Ctx, S>,
+    {
+        <Self as resolve::Field<Info, Ctx, S>>::resolve_field(
+            self, info, field_name, arguments, executor,
+        )
+    }
+}
+
+pub trait ConcreteTypeName {
+    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
+    where
+        Self: resolve::ConcreteTypeName<Info>;
+}
+
+impl<T: ?Sized> ConcreteTypeName for T {
+    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
+    where
+        Self: resolve::ConcreteTypeName<Info>,
+    {
+        <Self as resolve::ConcreteTypeName<Info>>::concrete_type_name(self, info)
+    }
+}
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 9016b9ac8..27b28a196 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -1,4 +1,8 @@
-use crate::{executor::Registry, schema::meta::MetaType, DefaultScalarValue, ScalarValue};
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    schema::meta::MetaType,
+    Arguments, DefaultScalarValue,
+};
 
 pub trait TypeName<Info: ?Sized> {
     fn type_name(info: &Info) -> &str;
@@ -10,3 +14,16 @@ pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
         S: 'r;
 }
 
+pub trait Field<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+    fn resolve_field(
+        &self,
+        info: &Info,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>;
+}
+
+pub trait ConcreteTypeName<Info: ?Sized> {
+    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str;
+}

From 2d1e5d38b753859401ad634fddc0ecd75ad3da21 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Fri, 22 Apr 2022 16:48:19 +0300
Subject: [PATCH 03/58] Impl some basic types

---
 juniper/src/executor/mod.rs    |  63 +++++++++++
 juniper/src/graphql/mod.rs     |  55 ++++++++++
 juniper/src/graphql/resolve.rs | 194 +++++++++++++++++++++++++++++----
 juniper/src/lib.rs             |   2 +-
 juniper/src/resolve/mod.rs     |  67 ++++++++++--
 juniper/src/types/arc.rs       | 186 +++++++++++++++++++++++++++++++
 juniper/src/types/box.rs       | 184 +++++++++++++++++++++++++++++++
 juniper/src/types/iter.rs      |  65 +++++++++++
 juniper/src/types/mod.rs       |   9 ++
 juniper/src/types/option.rs    |  78 +++++++++++++
 juniper/src/types/rc.rs        | 186 +++++++++++++++++++++++++++++++
 juniper/src/types/ref.rs       | 182 +++++++++++++++++++++++++++++++
 juniper/src/types/ref_mut.rs   | 182 +++++++++++++++++++++++++++++++
 juniper/src/types/vec.rs       |  77 +++++++++++++
 14 files changed, 1496 insertions(+), 34 deletions(-)
 create mode 100644 juniper/src/types/arc.rs
 create mode 100644 juniper/src/types/box.rs
 create mode 100644 juniper/src/types/iter.rs
 create mode 100644 juniper/src/types/option.rs
 create mode 100644 juniper/src/types/rc.rs
 create mode 100644 juniper/src/types/ref.rs
 create mode 100644 juniper/src/types/ref_mut.rs
 create mode 100644 juniper/src/types/vec.rs

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index cf35af155..23073222f 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -17,6 +17,7 @@ use crate::{
         Selection, ToInputValue, Type,
     },
     parser::{SourcePosition, Spanning},
+    resolve,
     schema::{
         meta::{
             Argument, DeprecationStatus, EnumMeta, EnumValue, Field, InputObjectMeta,
@@ -83,6 +84,12 @@ 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
@@ -1183,6 +1190,32 @@ impl<'r, S: 'r> Registry<'r, S> {
         }
     }
 
+    /// Returns a [`Type`] meta information for the specified [`graphql::Type`],
+    /// registered in this [`Registry`].
+    ///
+    /// If this [`Registry`] doesn't contain a [`Type`] meta information with
+    /// such [`TypeName`] before, it will construct the one and store it.
+    ///
+    /// [`graphql::Type`]: resolve::Type
+    /// [`TypeName`]: resolve::TypeName
+    pub fn get_type_new<T, Info>(&mut self, info: &Info) -> Type<'r>
+    where
+        T: resolve::Type<Info, S> + resolve::TypeName<Info> + ?Sized,
+        Info: ?Sized,
+    {
+        let name = T::type_name(info);
+        let validated_name = name.parse::<Name>().unwrap();
+        if !self.types.contains_key(name) {
+            self.insert_placeholder(
+                validated_name.clone(),
+                Type::NonNullNamed(Cow::Owned(name.to_string())),
+            );
+            let meta = T::meta(self, info);
+            self.types.insert(validated_name, meta);
+        }
+        self.types[name].as_type()
+    }
+
     /// Creates a [`Field`] with the provided `name`.
     pub fn field<T>(&mut self, name: &str, info: &T::TypeInfo) -> Field<'r, S>
     where
@@ -1278,6 +1311,24 @@ impl<'r, S: 'r> Registry<'r, S> {
         ListMeta::new(of_type, expected_size)
     }
 
+    /// Builds a [`ListMeta`] information for the specified [`graphql::Type`].
+    ///
+    /// Specifying `expected_size` will be used in validation to ensure that
+    /// values of this type matches it.
+    ///
+    /// [`graphql::Type`]: resolve::Type
+    pub fn build_list_type_new<T, Info>(
+        &mut self,
+        info: &Info,
+        expected_size: Option<usize>,
+    ) -> ListMeta<'r>
+    where
+        T: resolve::Type<Info, S> + ?Sized,
+        Info: ?Sized,
+    {
+        ListMeta::new(T::meta(self, info).as_type(), expected_size)
+    }
+
     /// Creates a [`NullableMeta`] type.
     pub fn build_nullable_type<T>(&mut self, info: &T::TypeInfo) -> NullableMeta<'r>
     where
@@ -1288,6 +1339,18 @@ impl<'r, S: 'r> Registry<'r, S> {
         NullableMeta::new(of_type)
     }
 
+    /// Builds a [`NullableMeta`] information for the specified
+    /// [`graphql::Type`].
+    ///
+    /// [`graphql::Type`]: resolve::Type
+    pub fn build_nullable_type_new<T, Info>(&mut self, info: &Info) -> NullableMeta<'r>
+    where
+        T: resolve::Type<Info, S> + ?Sized,
+        Info: ?Sized,
+    {
+        NullableMeta::new(T::meta(self, info).as_type())
+    }
+
     /// Creates an [`ObjectMeta`] type with the given `fields`.
     pub fn build_object_type<T>(
         &mut self,
diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 581d1dcd4..4d87480d9 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -1 +1,56 @@
 pub mod resolve;
+
+use crate::DefaultScalarValue;
+
+pub use crate::value::Value;
+
+pub use self::resolve::Type;
+
+pub trait Interface<S = DefaultScalarValue>:
+    OutputType<S>
+    + Type<S>
+    + resolve::TypeName
+    + resolve::ConcreteTypeName
+    + resolve::Value<S>
+    + resolve::ValueAsync<S>
+    + resolve::ConcreteValue<S>
+    + resolve::ConcreteValueAsync<S>
+    + resolve::Field<S>
+    + resolve::FieldAsync<S>
+{
+    fn assert_interface();
+}
+
+pub trait Object<S = DefaultScalarValue>:
+    OutputType<S>
+    + Type<S>
+    + resolve::TypeName
+    + resolve::ConcreteTypeName
+    + resolve::Value<S>
+    + resolve::ValueAsync<S>
+    + resolve::Field<S>
+    + resolve::FieldAsync<S>
+{
+    fn assert_object();
+}
+
+pub trait Union<S = DefaultScalarValue>:
+    OutputType<S>
+    + Type<S>
+    + resolve::TypeName
+    + resolve::ConcreteTypeName
+    + resolve::Value<S>
+    + resolve::ValueAsync<S>
+    + resolve::ConcreteValue<S>
+    + resolve::ConcreteValueAsync<S>
+{
+    fn assert_union();
+}
+
+pub trait InputType<S = DefaultScalarValue> {
+    fn assert_input_type();
+}
+
+pub trait OutputType<S = DefaultScalarValue> {
+    fn assert_output_type();
+}
diff --git a/juniper/src/graphql/resolve.rs b/juniper/src/graphql/resolve.rs
index 068115a86..22fe5342b 100644
--- a/juniper/src/graphql/resolve.rs
+++ b/juniper/src/graphql/resolve.rs
@@ -1,10 +1,25 @@
 use crate::{
-    executor::{ExecutionResult, Executor, Registry},
-    resolve,
-    schema::meta::MetaType,
-    Arguments, DefaultScalarValue,
+    meta::MetaType, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
+    Registry, Selection,
 };
 
+pub trait Type<S = DefaultScalarValue> {
+    fn meta<'r, Info: ?Sized>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+        Self: resolve::Type<Info, S>;
+}
+
+impl<T: ?Sized, S> Type<S> for T {
+    fn meta<'r, Info: ?Sized>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+        Self: resolve::Type<Info, S>,
+    {
+        <Self as resolve::Type<Info, S>>::meta(registry, info)
+    }
+}
+
 pub trait TypeName {
     fn type_name<Info: ?Sized>(info: &Info) -> &str
     where
@@ -20,29 +35,148 @@ impl<T: ?Sized> TypeName for T {
     }
 }
 
-pub trait Type<S = DefaultScalarValue> {
-    fn meta<'r, Info: ?Sized>(info: &Info, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
+pub trait ConcreteTypeName {
+    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
     where
-        S: 'r,
-        Self: resolve::Type<Info, S>;
+        Self: resolve::ConcreteTypeName<Info>;
 }
 
-impl<T: ?Sized, S> Type<S> for T {
-    fn meta<'r, Info: ?Sized>(info: &Info, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
+impl<T: ?Sized> ConcreteTypeName for T {
+    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
     where
-        S: 'r,
-        Self: resolve::Type<Info, S>,
+        Self: resolve::ConcreteTypeName<Info>,
+    {
+        <Self as resolve::ConcreteTypeName<Info>>::concrete_type_name(self, info)
+    }
+}
+
+pub trait Value<S = DefaultScalarValue> {
+    fn resolve_value<Info: ?Sized, Ctx: ?Sized>(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>
+    where
+        Self: resolve::Value<Info, Ctx, S>;
+}
+
+impl<T: ?Sized, S> Value<S> for T {
+    fn resolve_value<Info: ?Sized, Ctx: ?Sized>(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>
+    where
+        Self: resolve::Value<Info, Ctx, S>,
+    {
+        <Self as resolve::Value<Info, Ctx, S>>::resolve_value(self, selection_set, info, executor)
+    }
+}
+
+pub trait ValueAsync<S = DefaultScalarValue> {
+    fn resolve_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>
+    where
+        Self: resolve::ValueAsync<Info, Ctx, S>;
+}
+
+impl<T: ?Sized, S> ValueAsync<S> for T {
+    fn resolve_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>
+    where
+        Self: resolve::ValueAsync<Info, Ctx, S>,
     {
-        <Self as resolve::Type<Info, S>>::meta(info, registry)
+        <Self as resolve::ValueAsync<Info, Ctx, S>>::resolve_value_async(
+            self,
+            selection_set,
+            info,
+            executor,
+        )
+    }
+}
+
+pub trait ConcreteValue<S = DefaultScalarValue> {
+    fn resolve_concrete_value<Info: ?Sized, Ctx: ?Sized>(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>
+    where
+        Self: resolve::ConcreteValue<Info, Ctx, S>;
+}
+
+impl<T: ?Sized, S> ConcreteValue<S> for T {
+    fn resolve_concrete_value<Info: ?Sized, Ctx: ?Sized>(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>
+    where
+        Self: resolve::ConcreteValue<Info, Ctx, S>,
+    {
+        <Self as resolve::ConcreteValue<Info, Ctx, S>>::resolve_concrete_value(
+            self,
+            type_name,
+            selection_set,
+            info,
+            executor,
+        )
+    }
+}
+
+pub trait ConcreteValueAsync<S = DefaultScalarValue> {
+    fn resolve_concrete_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>
+    where
+        Self: resolve::ConcreteValueAsync<Info, Ctx, S>;
+}
+
+impl<T: ?Sized, S> ConcreteValueAsync<S> for T {
+    fn resolve_concrete_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>
+    where
+        Self: resolve::ConcreteValueAsync<Info, Ctx, S>,
+    {
+        <Self as resolve::ConcreteValueAsync<Info, Ctx, S>>::resolve_concrete_value_async(
+            self,
+            type_name,
+            selection_set,
+            info,
+            executor,
+        )
     }
 }
 
 pub trait Field<S = DefaultScalarValue> {
     fn resolve_field<Info: ?Sized, Ctx: ?Sized>(
         &self,
-        info: &Info,
         field_name: &str,
         arguments: &Arguments<S>,
+        info: &Info,
         executor: &Executor<Ctx, S>,
     ) -> ExecutionResult<S>
     where
@@ -52,31 +186,45 @@ pub trait Field<S = DefaultScalarValue> {
 impl<T: ?Sized, S> Field<S> for T {
     fn resolve_field<Info: ?Sized, Ctx: ?Sized>(
         &self,
-        info: &Info,
         field_name: &str,
         arguments: &Arguments<S>,
+        info: &Info,
         executor: &Executor<Ctx, S>,
     ) -> ExecutionResult<S>
     where
         Self: resolve::Field<Info, Ctx, S>,
     {
         <Self as resolve::Field<Info, Ctx, S>>::resolve_field(
-            self, info, field_name, arguments, executor,
+            self, field_name, arguments, info, executor,
         )
     }
 }
 
-pub trait ConcreteTypeName {
-    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
+pub trait FieldAsync<S = DefaultScalarValue> {
+    fn resolve_field_async<'r, Info: ?Sized, Ctx: ?Sized>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>
     where
-        Self: resolve::ConcreteTypeName<Info>;
+        Self: resolve::FieldAsync<Info, Ctx, S>;
 }
 
-impl<T: ?Sized> ConcreteTypeName for T {
-    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
+impl<T: ?Sized, S> FieldAsync<S> for T {
+    fn resolve_field_async<'r, Info: ?Sized, Ctx: ?Sized>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>
     where
-        Self: resolve::ConcreteTypeName<Info>,
+        Self: resolve::FieldAsync<Info, Ctx, S>,
     {
-        <Self as resolve::ConcreteTypeName<Info>>::concrete_type_name(self, info)
+        <Self as resolve::FieldAsync<Info, Ctx, S>>::resolve_field_async(
+            self, field_name, arguments, info, executor,
+        )
     }
 }
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index fa869cbd0..d9b4979cf 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -41,7 +41,7 @@ pub(crate) mod schema;
 mod types;
 mod util;
 pub mod validation;
-mod value;
+pub(crate) mod value;
 
 #[cfg(all(test, not(feature = "expose-test-schema")))]
 mod tests;
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 27b28a196..e027d0cf5 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -1,29 +1,76 @@
 use crate::{
-    executor::{ExecutionResult, Executor, Registry},
-    schema::meta::MetaType,
-    Arguments, DefaultScalarValue,
+    meta::MetaType, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, Registry,
+    Selection,
 };
 
+pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r;
+}
+
 pub trait TypeName<Info: ?Sized> {
     fn type_name(info: &Info) -> &str;
 }
 
-pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
-    fn meta<'r>(info: &Info, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
-    where
-        S: 'r;
+pub trait ConcreteTypeName<Info: ?Sized> {
+    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str;
+}
+
+pub trait Value<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>;
+}
+
+pub trait ValueAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>;
+}
+
+pub trait ConcreteValue<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+    fn resolve_concrete_value(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S>;
+}
+
+pub trait ConcreteValueAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+    fn resolve_concrete_value_async<'r>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>;
 }
 
 pub trait Field<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
     fn resolve_field(
         &self,
-        info: &Info,
         field_name: &str,
         arguments: &Arguments<S>,
+        info: &Info,
         executor: &Executor<Ctx, S>,
     ) -> ExecutionResult<S>;
 }
 
-pub trait ConcreteTypeName<Info: ?Sized> {
-    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str;
+pub trait FieldAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+    fn resolve_field_async<'r>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>>;
 }
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
new file mode 100644
index 000000000..8300eec92
--- /dev/null
+++ b/juniper/src/types/arc.rs
@@ -0,0 +1,186 @@
+use std::sync::Arc;
+
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
+    schema::meta::MetaType,
+    Arguments, BoxFuture, Selection,
+};
+
+impl<T, Info, S> resolve::Type<Info, S> for Arc<T>
+where
+    T: resolve::Type<Info, S> + ?Sized,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        T::meta(registry, info)
+    }
+}
+
+impl<T, Info> resolve::TypeName<Info> for Arc<T>
+where
+    T: resolve::TypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn type_name(info: &Info) -> &str {
+        T::type_name(info)
+    }
+}
+
+impl<T, Info> resolve::ConcreteTypeName<Info> for Arc<T>
+where
+    T: resolve::ConcreteTypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+        (**self).concrete_type_name(info)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Arc<T>
+where
+    T: resolve::Value<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_value(selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Arc<T>
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_value_async(selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for Arc<T>
+where
+    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for Arc<T>
+where
+    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value_async<'r>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for Arc<T>
+where
+    T: resolve::Field<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field(
+        &self,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_field(field_name, arguments, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for Arc<T>
+where
+    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field_async<'r>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_field_async(field_name, arguments, info, executor)
+    }
+}
+
+impl<T, S> graphql::InputType<S> for Arc<T>
+where
+    T: graphql::InputType<S> + ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S> graphql::OutputType<S> for Arc<T>
+where
+    T: graphql::OutputType<S> + ?Sized,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
+
+impl<T, S> graphql::Interface<S> for Arc<T>
+where
+    T: graphql::Interface<S> + ?Sized,
+{
+    fn assert_interface() {
+        T::assert_interface()
+    }
+}
+
+impl<T, S> graphql::Object<S> for Arc<T>
+where
+    T: graphql::Object<S> + ?Sized,
+{
+    fn assert_object() {
+        T::assert_object()
+    }
+}
+
+impl<T, S> graphql::Union<S> for Arc<T>
+where
+    T: graphql::Union<S> + ?Sized,
+{
+    fn assert_union() {
+        T::assert_union()
+    }
+}
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
new file mode 100644
index 000000000..5f0b0ce15
--- /dev/null
+++ b/juniper/src/types/box.rs
@@ -0,0 +1,184 @@
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
+    schema::meta::MetaType,
+    Arguments, BoxFuture, Selection,
+};
+
+impl<T, Info, S> resolve::Type<Info, S> for Box<T>
+where
+    T: resolve::Type<Info, S> + ?Sized,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        T::meta(registry, info)
+    }
+}
+
+impl<T, Info> resolve::TypeName<Info> for Box<T>
+where
+    T: resolve::TypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn type_name(info: &Info) -> &str {
+        T::type_name(info)
+    }
+}
+
+impl<T, Info> resolve::ConcreteTypeName<Info> for Box<T>
+where
+    T: resolve::ConcreteTypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+        (**self).concrete_type_name(info)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Box<T>
+where
+    T: resolve::Value<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_value(selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Box<T>
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_value_async(selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for Box<T>
+where
+    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for Box<T>
+where
+    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value_async<'r>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for Box<T>
+where
+    T: resolve::Field<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field(
+        &self,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_field(field_name, arguments, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for Box<T>
+where
+    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field_async<'r>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_field_async(field_name, arguments, info, executor)
+    }
+}
+
+impl<T, S> graphql::InputType<S> for Box<T>
+where
+    T: graphql::InputType<S> + ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S> graphql::OutputType<S> for Box<T>
+where
+    T: graphql::OutputType<S> + ?Sized,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
+
+impl<T, S> graphql::Interface<S> for Box<T>
+where
+    T: graphql::Interface<S> + ?Sized,
+{
+    fn assert_interface() {
+        T::assert_interface()
+    }
+}
+
+impl<T, S> graphql::Object<S> for Box<T>
+where
+    T: graphql::Object<S> + ?Sized,
+{
+    fn assert_object() {
+        T::assert_object()
+    }
+}
+
+impl<T, S> graphql::Union<S> for Box<T>
+where
+    T: graphql::Union<S> + ?Sized,
+{
+    fn assert_union() {
+        T::assert_union()
+    }
+}
diff --git a/juniper/src/types/iter.rs b/juniper/src/types/iter.rs
new file mode 100644
index 000000000..2b4e5edde
--- /dev/null
+++ b/juniper/src/types/iter.rs
@@ -0,0 +1,65 @@
+use crate::{graphql, resolve, ExecutionResult, Executor, Selection};
+
+pub fn resolve_list<'t, T, S, Info, Ctx, I>(
+    iter: I,
+    selection_set: Option<&[Selection<'_, S>]>,
+    info: &Info,
+    executor: &Executor<Ctx, S>,
+) -> ExecutionResult<S>
+where
+    I: Iterator<Item = &'t T> + ExactSizeIterator,
+    T: resolve::Value<Info, Ctx, S> + ?Sized + 't,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    let is_non_null = executor
+        .current_type_new()
+        .list_contents()
+        .ok_or("Iterating over non-list type")?
+        .is_non_null();
+
+    let mut values = Vec::with_capacity(iter.len());
+    for v in iter {
+        let val = v.resolve_value(selection_set, info, executor)?;
+        if is_non_null && val.is_null() {
+            return Err("Resolved `null` on non-null type".into());
+        }
+        values.push(val);
+    }
+    Ok(graphql::Value::list(values))
+}
+
+pub async fn resolve_list_async<'a, 't, T, S, Info, Ctx, I>(
+    iter: I,
+    selection_set: Option<&[Selection<'_, S>]>,
+    info: &'a Info,
+    executor: &'a Executor<'a, 'a, Ctx, S>,
+) -> ExecutionResult<S>
+where
+    I: Iterator<Item = &'t T> + ExactSizeIterator,
+    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized + 't,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    use futures::stream::{FuturesOrdered, StreamExt as _};
+
+    let is_non_null = executor
+        .current_type_new()
+        .list_contents()
+        .ok_or("Iterating over non-list type")?
+        .is_non_null();
+
+    let mut futs = iter
+        .map(|v| async move { v.resolve_value_async(selection_set, info, executor).await })
+        .collect::<FuturesOrdered<_>>();
+
+    let mut values = Vec::with_capacity(futs.len());
+    while let Some(res) = futs.next().await {
+        let val = res?;
+        if is_non_null && val.is_null() {
+            return Err("Resolved `null` on non-null type".into());
+        }
+        values.push(val);
+    }
+    Ok(graphql::Value::list(values))
+}
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 8ac005ba0..55451b5aa 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -1,3 +1,12 @@
+mod arc;
+mod r#box;
+pub mod iter;
+mod option;
+mod rc;
+mod r#ref;
+mod ref_mut;
+mod vec;
+
 pub mod async_await;
 pub mod base;
 pub mod containers;
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
new file mode 100644
index 000000000..98f995c48
--- /dev/null
+++ b/juniper/src/types/option.rs
@@ -0,0 +1,78 @@
+use futures::future;
+
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
+    schema::meta::MetaType,
+    BoxFuture, Selection,
+};
+
+impl<T, Info, S> resolve::Type<Info, S> for Option<T>
+where
+    T: resolve::Type<Info, S>,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        registry.build_nullable_type_new::<T, _>(info).into_meta()
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Option<T>
+where
+    T: resolve::Value<Info, Ctx, S>,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        match self {
+            Some(v) => v.resolve_value(selection_set, info, executor),
+            None => Ok(graphql::Value::Null),
+        }
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Option<T>
+where
+    T: resolve::ValueAsync<Info, Ctx, S>,
+    Info: ?Sized,
+    Ctx: ?Sized,
+    S: Send,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        match self {
+            Some(v) => v.resolve_value_async(selection_set, info, executor),
+            None => Box::pin(future::ok(graphql::Value::Null)),
+        }
+    }
+}
+
+impl<T, S> graphql::InputType<S> for Option<T>
+where
+    T: graphql::InputType<S>,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S> graphql::OutputType<S> for Option<T>
+where
+    T: graphql::OutputType<S>,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
new file mode 100644
index 000000000..0ac2d2639
--- /dev/null
+++ b/juniper/src/types/rc.rs
@@ -0,0 +1,186 @@
+use std::rc::Rc;
+
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
+    schema::meta::MetaType,
+    Arguments, BoxFuture, Selection,
+};
+
+impl<T, Info, S> resolve::Type<Info, S> for Rc<T>
+where
+    T: resolve::Type<Info, S> + ?Sized,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        T::meta(registry, info)
+    }
+}
+
+impl<T, Info> resolve::TypeName<Info> for Rc<T>
+where
+    T: resolve::TypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn type_name(info: &Info) -> &str {
+        T::type_name(info)
+    }
+}
+
+impl<T, Info> resolve::ConcreteTypeName<Info> for Rc<T>
+where
+    T: resolve::ConcreteTypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+        (**self).concrete_type_name(info)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Rc<T>
+where
+    T: resolve::Value<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_value(selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Rc<T>
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_value_async(selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for Rc<T>
+where
+    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for Rc<T>
+where
+    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value_async<'r>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for Rc<T>
+where
+    T: resolve::Field<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field(
+        &self,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_field(field_name, arguments, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for Rc<T>
+where
+    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field_async<'r>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_field_async(field_name, arguments, info, executor)
+    }
+}
+
+impl<T, S> graphql::InputType<S> for Rc<T>
+where
+    T: graphql::InputType<S> + ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S> graphql::OutputType<S> for Rc<T>
+where
+    T: graphql::OutputType<S> + ?Sized,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
+
+impl<T, S> graphql::Interface<S> for Rc<T>
+where
+    T: graphql::Interface<S> + ?Sized,
+{
+    fn assert_interface() {
+        T::assert_interface()
+    }
+}
+
+impl<T, S> graphql::Object<S> for Rc<T>
+where
+    T: graphql::Object<S> + ?Sized,
+{
+    fn assert_object() {
+        T::assert_object()
+    }
+}
+
+impl<T, S> graphql::Union<S> for Rc<T>
+where
+    T: graphql::Union<S> + ?Sized,
+{
+    fn assert_union() {
+        T::assert_union()
+    }
+}
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
new file mode 100644
index 000000000..2f0867947
--- /dev/null
+++ b/juniper/src/types/ref.rs
@@ -0,0 +1,182 @@
+use crate::{
+    graphql, meta::MetaType, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry,
+    Selection,
+};
+
+impl<'me, T, Info, S> resolve::Type<Info, S> for &'me T
+where
+    T: resolve::Type<Info, S> + ?Sized,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        T::meta(registry, info)
+    }
+}
+
+impl<'me, T, Info> resolve::TypeName<Info> for &'me T
+where
+    T: resolve::TypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn type_name(info: &Info) -> &str {
+        T::type_name(info)
+    }
+}
+
+impl<'me, T, Info> resolve::ConcreteTypeName<Info> for &'me T
+where
+    T: resolve::ConcreteTypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+        (**self).concrete_type_name(info)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for &'me T
+where
+    T: resolve::Value<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_value(selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for &'me T
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_value_async(selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for &'me T
+where
+    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for &'me T
+where
+    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value_async<'r>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for &'me T
+where
+    T: resolve::Field<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field(
+        &self,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_field(field_name, arguments, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for &'me T
+where
+    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field_async<'r>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_field_async(field_name, arguments, info, executor)
+    }
+}
+
+impl<'me, T, S> graphql::InputType<S> for &'me T
+where
+    T: graphql::InputType<S> + ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<'me, T, S> graphql::OutputType<S> for &'me T
+where
+    T: graphql::OutputType<S> + ?Sized,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
+
+impl<'me, T, S> graphql::Interface<S> for &'me T
+where
+    T: graphql::Interface<S> + ?Sized,
+{
+    fn assert_interface() {
+        T::assert_interface()
+    }
+}
+
+impl<'me, T, S> graphql::Object<S> for &'me T
+where
+    T: graphql::Object<S> + ?Sized,
+{
+    fn assert_object() {
+        T::assert_object()
+    }
+}
+
+impl<'me, T, S> graphql::Union<S> for &'me T
+where
+    T: graphql::Union<S> + ?Sized,
+{
+    fn assert_union() {
+        T::assert_union()
+    }
+}
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
new file mode 100644
index 000000000..566359b65
--- /dev/null
+++ b/juniper/src/types/ref_mut.rs
@@ -0,0 +1,182 @@
+use crate::{
+    graphql, meta::MetaType, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry,
+    Selection,
+};
+
+impl<'me, T, Info, S> resolve::Type<Info, S> for &'me mut T
+where
+    T: resolve::Type<Info, S> + ?Sized,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        T::meta(registry, info)
+    }
+}
+
+impl<'me, T, Info> resolve::TypeName<Info> for &'me mut T
+where
+    T: resolve::TypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn type_name(info: &Info) -> &str {
+        T::type_name(info)
+    }
+}
+
+impl<'me, T, Info> resolve::ConcreteTypeName<Info> for &'me mut T
+where
+    T: resolve::ConcreteTypeName<Info> + ?Sized,
+    Info: ?Sized,
+{
+    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+        (**self).concrete_type_name(info)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for &'me mut T
+where
+    T: resolve::Value<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_value(selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for &'me mut T
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_value_async(selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for &'me mut T
+where
+    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for &'me mut T
+where
+    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_concrete_value_async<'r>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for &'me mut T
+where
+    T: resolve::Field<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field(
+        &self,
+        field_name: &str,
+        arguments: &Arguments<S>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        (**self).resolve_field(field_name, arguments, info, executor)
+    }
+}
+
+impl<'me, T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for &'me mut T
+where
+    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_field_async<'r>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<S>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        (**self).resolve_field_async(field_name, arguments, info, executor)
+    }
+}
+
+impl<'me, T, S> graphql::InputType<S> for &'me mut T
+where
+    T: graphql::InputType<S> + ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<'me, T, S> graphql::OutputType<S> for &'me mut T
+where
+    T: graphql::OutputType<S> + ?Sized,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
+
+impl<'me, T, S> graphql::Interface<S> for &'me mut T
+where
+    T: graphql::Interface<S> + ?Sized,
+{
+    fn assert_interface() {
+        T::assert_interface()
+    }
+}
+
+impl<'me, T, S> graphql::Object<S> for &'me mut T
+where
+    T: graphql::Object<S> + ?Sized,
+{
+    fn assert_object() {
+        T::assert_object()
+    }
+}
+
+impl<'me, T, S> graphql::Union<S> for &'me mut T
+where
+    T: graphql::Union<S> + ?Sized,
+{
+    fn assert_union() {
+        T::assert_union()
+    }
+}
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
new file mode 100644
index 000000000..e2374e27f
--- /dev/null
+++ b/juniper/src/types/vec.rs
@@ -0,0 +1,77 @@
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
+    schema::meta::MetaType,
+    BoxFuture, Selection,
+};
+
+use super::iter;
+
+impl<T, Info, S> resolve::Type<Info, S> for Vec<T>
+where
+    T: resolve::Type<Info, S>,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        registry.build_list_type_new::<T, _>(info, None).into_meta()
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Vec<T>
+where
+    T: resolve::Value<Info, Ctx, S>,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        iter::resolve_list(self.iter(), selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Vec<T>
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + Sync,
+    Info: Sync + ?Sized,
+    Ctx: Sync + ?Sized,
+    S: Send + Sync,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        Box::pin(iter::resolve_list_async(
+            self.iter(),
+            selection_set,
+            info,
+            executor,
+        ))
+    }
+}
+
+impl<T, S> graphql::InputType<S> for Vec<T>
+where
+    T: graphql::InputType<S>,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S> graphql::OutputType<S> for Vec<T>
+where
+    T: graphql::OutputType<S>,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}

From c8759cd16e98ae79f4b16bf1bf6794bc04a37af3 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 25 Apr 2022 15:50:28 +0300
Subject: [PATCH 04/58] Impl basic types, vol.2

---
 juniper/src/lib.rs            |   2 +-
 juniper/src/types/arc.rs      |   2 +
 juniper/src/types/array.rs    |  83 +++++++++++
 juniper/src/types/box.rs      |   2 +
 juniper/src/types/iter.rs     |   2 +
 juniper/src/types/mod.rs      |   7 +-
 juniper/src/types/nullable.rs | 255 +++++++++++++++++++++++++---------
 juniper/src/types/option.rs   |   2 +
 juniper/src/types/rc.rs       |   2 +
 juniper/src/types/ref.rs      |   4 +
 juniper/src/types/ref_mut.rs  |   4 +
 juniper/src/types/slice.rs    |  81 +++++++++++
 juniper/src/types/vec.rs      |   2 +
 13 files changed, 382 insertions(+), 66 deletions(-)
 create mode 100644 juniper/src/types/array.rs
 create mode 100644 juniper/src/types/slice.rs

diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index d9b4979cf..9ee509bbc 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -82,7 +82,7 @@ pub use crate::{
         async_await::{GraphQLTypeAsync, GraphQLValueAsync},
         base::{Arguments, GraphQLType, GraphQLValue, TypeKind},
         marker::{self, GraphQLInterface, GraphQLObject, GraphQLUnion},
-        nullable::Nullable,
+        Nullable,
         scalars::{EmptyMutation, EmptySubscription, ID},
         subscriptions::{
             ExecutionOutput, GraphQLSubscriptionType, GraphQLSubscriptionValue,
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 8300eec92..467951c88 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -1,3 +1,5 @@
+//! GraphQL implementation for [`Arc`].
+
 use std::sync::Arc;
 
 use crate::{
diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
new file mode 100644
index 000000000..e018148da
--- /dev/null
+++ b/juniper/src/types/array.rs
@@ -0,0 +1,83 @@
+//! GraphQL implementation for [array].
+//!
+//! [array]: primitive@std::array
+
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
+    schema::meta::MetaType,
+    BoxFuture, Selection,
+};
+
+use super::iter;
+
+impl<T, Info, S, const N: usize> resolve::Type<Info, S> for [T; N]
+where
+    T: resolve::Type<Info, S>,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        registry
+            .build_list_type_new::<T, _>(info, Some(N))
+            .into_meta()
+    }
+}
+
+impl<T, Info, Ctx, S, const N: usize> resolve::Value<Info, Ctx, S> for [T; N]
+where
+    T: resolve::Value<Info, Ctx, S>,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        iter::resolve_list(self.iter(), selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S, const N: usize> resolve::ValueAsync<Info, Ctx, S> for [T; N]
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + Sync,
+    Info: Sync + ?Sized,
+    Ctx: Sync + ?Sized,
+    S: Send + Sync,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        Box::pin(iter::resolve_list_async(
+            self.iter(),
+            selection_set,
+            info,
+            executor,
+        ))
+    }
+}
+
+impl<T, S, const N: usize> graphql::InputType<S> for [T; N]
+where
+    T: graphql::InputType<S>,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S, const N: usize> graphql::OutputType<S> for [T; N]
+where
+    T: graphql::OutputType<S>,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 5f0b0ce15..c8140f3e2 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -1,3 +1,5 @@
+//! GraphQL implementation for [`Box`].
+
 use crate::{
     executor::{ExecutionResult, Executor, Registry},
     graphql, resolve,
diff --git a/juniper/src/types/iter.rs b/juniper/src/types/iter.rs
index 2b4e5edde..c3979b088 100644
--- a/juniper/src/types/iter.rs
+++ b/juniper/src/types/iter.rs
@@ -1,3 +1,5 @@
+//! GraphQL implementation for [`Iterator`].
+
 use crate::{graphql, resolve, ExecutionResult, Executor, Selection};
 
 pub fn resolve_list<'t, T, S, Info, Ctx, I>(
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 55451b5aa..5fceeb2ba 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -1,10 +1,13 @@
+mod array;
 mod arc;
 mod r#box;
 pub mod iter;
+mod nullable;
 mod option;
 mod rc;
 mod r#ref;
 mod ref_mut;
+mod slice;
 mod vec;
 
 pub mod async_await;
@@ -12,8 +15,10 @@ pub mod base;
 pub mod containers;
 pub mod marker;
 pub mod name;
-pub mod nullable;
 pub mod pointers;
 pub mod scalars;
 pub mod subscriptions;
 pub mod utilities;
+
+#[doc(inline)]
+pub use self::nullable::Nullable;
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index 7e8d01cc1..1d2f55839 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -1,40 +1,52 @@
+//! GraphQL implementation for [`Nullable`].
+
+use std::mem;
+
+use futures::future;
+
 use crate::{
-    ast::{FromInputValue, InputValue, Selection, ToInputValue},
+    ast::{FromInputValue, InputValue, ToInputValue},
     executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
     schema::meta::MetaType,
     types::{
         async_await::GraphQLValueAsync,
         base::{GraphQLType, GraphQLValue},
         marker::IsInputType,
     },
-    value::{ScalarValue, Value},
+    BoxFuture, ScalarValue, Selection,
 };
 
-/// `Nullable` can be used in situations where you need to distinguish between an implicitly and
-/// explicitly null input value.
+/// [`Nullable`] wrapper allowing to distinguish between an implicit and
+/// explicit `null` input value.
 ///
-/// The GraphQL spec states that these two field calls are similar, but are not identical:
+/// [GraphQL spec states][0] that these two field calls are similar, but are not
+/// identical:
 ///
-/// ```graphql
-/// {
-///   field(arg: null)
-///   field
-/// }
-/// ```
+/// > ```graphql
+/// > {
+/// >   field(arg: null)
+/// >   field
+/// > }
+/// > ```
+/// > The first has explicitly provided `null` to the argument "arg", while the
+/// > second has implicitly not provided a value to the argument "arg". These
+/// > two forms may be interpreted differently. For example, a mutation
+/// > representing deleting a field vs not altering a field, respectively.
 ///
-/// The first has explicitly provided null to the argument “arg”, while the second has implicitly
-/// not provided a value to the argument “arg”. These two forms may be interpreted differently. For
-/// example, a mutation representing deleting a field vs not altering a field, respectively.
+/// In cases where there is no need to distinguish between the two types of
+/// `null`, it's better to simply use [`Option`].
 ///
-/// In cases where you do not need to be able to distinguish between the two types of null, you
-/// should simply use `Option<T>`.
+/// [0]: https://spec.graphql.org/October2021#example-1c7eb
 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub enum Nullable<T> {
-    /// No value
+    /// No value specified.
     ImplicitNull,
-    /// No value, explicitly specified to be null
+
+    /// Value explicitly specified to be `null`.
     ExplicitNull,
-    /// Some value `T`
+
+    /// Explicitly specified non-`null` value of `T`.
     Some(T),
 }
 
@@ -45,101 +57,134 @@ impl<T> Default for Nullable<T> {
 }
 
 impl<T> Nullable<T> {
-    /// Returns `true` if the nullable is a `ExplicitNull` value.
+    /// Indicates whether this [`Nullable`] represents an [`ExplicitNull`].
+    ///
+    /// [`ExplicitNull`]: Nullable::ExplicitNull
     #[inline]
     pub fn is_explicit_null(&self) -> bool {
         matches!(self, Self::ExplicitNull)
     }
 
-    /// Returns `true` if the nullable is a `ImplicitNull` value.
+    /// Indicates whether this [`Nullable`] represents an [`ImplicitNull`].
+    ///
+    /// [`ImplicitNull`]: Nullable::ImplicitNull
     #[inline]
     pub fn is_implicit_null(&self) -> bool {
         matches!(self, Self::ImplicitNull)
     }
 
-    /// Returns `true` if the nullable is a `Some` value.
+    /// Indicates whether this [`Nullable`] contains a non-`null` value.
     #[inline]
     pub fn is_some(&self) -> bool {
         matches!(self, Self::Some(_))
     }
 
-    /// Returns `true` if the nullable is not a `Some` value.
+    /// Indicates whether this [`Nullable`] represents a `null`.
     #[inline]
     pub fn is_null(&self) -> bool {
         !matches!(self, Self::Some(_))
     }
 
+    /// Converts from `&Nullable<T>` to `Nullable<&T>`.
+    #[inline]
+    pub fn as_ref(&self) -> Nullable<&T> {
+        match self {
+            Self::Some(x) => Nullable::Some(x),
+            Self::ImplicitNull => Nullable::ImplicitNull,
+            Self::ExplicitNull => Nullable::ExplicitNull,
+        }
+    }
+
     /// Converts from `&mut Nullable<T>` to `Nullable<&mut T>`.
     #[inline]
     pub fn as_mut(&mut self) -> Nullable<&mut T> {
-        match *self {
-            Self::Some(ref mut x) => Nullable::Some(x),
+        match self {
+            Self::Some(x) => Nullable::Some(x),
             Self::ImplicitNull => Nullable::ImplicitNull,
             Self::ExplicitNull => Nullable::ExplicitNull,
         }
     }
 
-    /// Returns the contained `Some` value, consuming the `self` value.
+    /// Returns the contained non-`null` value, consuming the `self` value.
     ///
     /// # Panics
     ///
-    /// Panics if the value is not a `Some` with a custom panic message provided by `msg`.
+    /// With a custom `msg` if this [`Nullable`] represents a `null`.
     #[inline]
     #[track_caller]
     pub fn expect(self, msg: &str) -> T {
         self.some().expect(msg)
     }
 
-    /// Returns the contained `Some` value or a provided default.
+    /// Returns the contained non-`null` value or the provided `default` one.
     #[inline]
     pub fn unwrap_or(self, default: T) -> T {
         self.some().unwrap_or(default)
     }
 
-    /// Returns the contained `Some` value or computes it from a closure.
+    /// Returns thecontained non-`null` value  or computes it from the provided
+    /// `func`tion.
+    #[inline]
+    pub fn unwrap_or_else<F: FnOnce() -> T>(self, func: F) -> T {
+        self.some().unwrap_or_else(func)
+    }
+
+    /// Returns the contained non-`null` value or the [`Default`] one.
     #[inline]
-    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
-        self.some().unwrap_or_else(f)
+    pub fn unwrap_or_default(self) -> T
+    where
+        T: Default,
+    {
+        self.some().unwrap_or_default()
     }
 
-    /// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
+    /// Maps this `Nullable<T>` to `Nullable<U>` by applying the provided
+    /// `func`tion to the contained non-`null` value.
     #[inline]
-    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
+    pub fn map<U, F: FnOnce(T) -> U>(self, func: F) -> Nullable<U> {
         match self {
-            Self::Some(x) => Nullable::Some(f(x)),
+            Self::Some(x) => Nullable::Some(func(x)),
             Self::ImplicitNull => Nullable::ImplicitNull,
             Self::ExplicitNull => Nullable::ExplicitNull,
         }
     }
 
-    /// Applies a function to the contained value (if any), or returns the provided default (if
-    /// not).
+    /// Applies the provided `func`tion to the contained non-`null` value (if
+    /// any), or returns the provided `default` value (if not).
     #[inline]
-    pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
-        self.some().map_or(default, f)
+    pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, func: F) -> U {
+        self.some().map_or(default, func)
     }
 
-    /// Applies a function to the contained value (if any), or computes a default (if not).
+    /// Applies the provided `func`tion to the contained non-`null` value (if
+    /// any), or computes the provided `default` one (if not).
     #[inline]
-    pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
-        self.some().map_or_else(default, f)
+    pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, func: F) -> U {
+        self.some().map_or_else(default, func)
     }
 
-    /// Transforms the `Nullable<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and
-    /// `ImplicitNull` or `ExplicitNull` to `Err(err)`.
+    /// Transforms this `Nullable<T>` into a `Result<T, E>`, mapping `Some(v)`
+    /// to `Ok(v)` and [`ImplicitNull`] or [`ExplicitNull`] to `Err(err)`.
+    ///
+    /// [`ExplicitNull`]: Nullable::ExplicitNull
+    /// [`ImplicitNull`]: Nullable::ImplicitNull
     #[inline]
     pub fn ok_or<E>(self, err: E) -> Result<T, E> {
         self.some().ok_or(err)
     }
 
-    /// Transforms the `Nullable<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and
-    /// `ImplicitNull` or `ExplicitNull` to `Err(err())`.
+    /// Transforms this `Nullable<T>` into a `Result<T, E>`, mapping `Some(v)`
+    /// to `Ok(v)` and [`ImplicitNull`] or [`ExplicitNull`] to `Err(err())`.
+    ///
+    /// [`ExplicitNull`]: Nullable::ExplicitNull
+    /// [`ImplicitNull`]: Nullable::ImplicitNull
     #[inline]
     pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
         self.some().ok_or_else(err)
     }
 
-    /// Returns the nullable if it contains a value, otherwise returns `b`.
+    /// Returns this [`Nullable`] if it contains a non-`null` value, otherwise
+    /// returns the specified `b` [`Nullable`] value.
     #[inline]
     #[must_use]
     pub fn or(self, b: Self) -> Self {
@@ -149,35 +194,43 @@ impl<T> Nullable<T> {
         }
     }
 
-    /// Returns the nullable if it contains a value, otherwise calls `f` and
-    /// returns the result.
+    /// Returns this [`Nullable`] if it contains a non-`null` value, otherwise
+    /// computes a [`Nullable`] value from the specified `func`tion.
     #[inline]
     #[must_use]
-    pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
+    pub fn or_else<F: FnOnce() -> Nullable<T>>(self, func: F) -> Nullable<T> {
         match self {
             Self::Some(_) => self,
-            _ => f(),
+            _ => func(),
         }
     }
 
-    /// Replaces the actual value in the nullable by the value given in parameter, returning the
-    /// old value if present, leaving a `Some` in its place without deinitializing either one.
+    /// Replaces the contained non-`null` value in this [`Nullable`] by the
+    /// provided `value`, returning the old one if present, leaving a [`Some`]
+    /// in its place without deinitializing either one.
+    ///
+    /// [`Some`]: Nullable::Some
     #[inline]
     #[must_use]
     pub fn replace(&mut self, value: T) -> Self {
-        std::mem::replace(self, Self::Some(value))
+        mem::replace(self, Self::Some(value))
     }
 
-    /// Converts from `Nullable<T>` to `Option<T>`.
+    /// Converts this [`Nullable`] to [Option].
+    #[inline]
     pub fn some(self) -> Option<T> {
         match self {
             Self::Some(v) => Some(v),
-            _ => None,
+            Self::ExplicitNull | Self::ImplicitNull => None,
         }
     }
 
-    /// Converts from `Nullable<T>` to `Option<Option<T>>`, mapping `Some(v)` to `Some(Some(v))`,
-    /// `ExplicitNull` to `Some(None)`, and `ImplicitNull` to `None`.
+    /// Converts this [`Nullable`] to `Option<Option<T>>`, mapping `Some(v)` to
+    /// `Some(Some(v))`, [`ExplicitNull`] to `Some(None)`, and [`ImplicitNull`]
+    /// to [`None`].
+    ///
+    /// [`ExplicitNull`]: Nullable::ExplicitNull
+    /// [`ImplicitNull`]: Nullable::ImplicitNull
     pub fn explicit(self) -> Option<Option<T>> {
         match self {
             Self::Some(v) => Some(Some(v)),
@@ -188,33 +241,107 @@ impl<T> Nullable<T> {
 }
 
 impl<T: Copy> Nullable<&T> {
-    /// Maps a `Nullable<&T>` to a `Nullable<T>` by copying the contents of the nullable.
+    /// Maps this `Nullable<&T>` to a `Nullable<T>` by [`Copy`]ing the contents
+    /// of this [`Nullable`].
     pub fn copied(self) -> Nullable<T> {
         self.map(|&t| t)
     }
 }
 
 impl<T: Copy> Nullable<&mut T> {
-    /// Maps a `Nullable<&mut T>` to a `Nullable<T>` by copying the contents of the nullable.
+    /// Maps this `Nullable<&mut T>` to a `Nullable<T>` by [`Copy`]ing the
+    /// contents of this [`Nullable`].
     pub fn copied(self) -> Nullable<T> {
         self.map(|&mut t| t)
     }
 }
 
 impl<T: Clone> Nullable<&T> {
-    /// Maps a `Nullable<&T>` to a `Nullable<T>` by cloning the contents of the nullable.
+    /// Maps this `Nullable<&T>` to a `Nullable<T>` by [`Clone`]ing the contents
+    /// of this [`Nullable`].
     pub fn cloned(self) -> Nullable<T> {
         self.map(|t| t.clone())
     }
 }
 
 impl<T: Clone> Nullable<&mut T> {
-    /// Maps a `Nullable<&mut T>` to a `Nullable<T>` by cloning the contents of the nullable.
+    /// Maps this `Nullable<&mut T>` to a `Nullable<T>` by [`Clone`]ing the
+    /// contents of this [`Nullable`].
     pub fn cloned(self) -> Nullable<T> {
         self.map(|t| t.clone())
     }
 }
 
+impl<T, Info, S> resolve::Type<Info, S> for Nullable<T>
+where
+    T: resolve::Type<Info, S>,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        registry.build_nullable_type_new::<T, _>(info).into_meta()
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Nullable<T>
+where
+    T: resolve::Value<Info, Ctx, S>,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        match self {
+            Self::Some(v) => v.resolve_value(selection_set, info, executor),
+            Self::ExplicitNull | Self::ImplicitNull => Ok(graphql::Value::Null),
+        }
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Nullable<T>
+where
+    T: resolve::ValueAsync<Info, Ctx, S>,
+    Info: ?Sized,
+    Ctx: ?Sized,
+    S: Send,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        match self {
+            Self::Some(v) => v.resolve_value_async(selection_set, info, executor),
+            Self::ExplicitNull | Self::ImplicitNull => Box::pin(future::ok(graphql::Value::Null)),
+        }
+    }
+}
+
+impl<T, S> graphql::InputType<S> for Nullable<T>
+where
+    T: graphql::InputType<S>,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S> graphql::OutputType<S> for Nullable<T>
+where
+    T: graphql::OutputType<S>,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
+
 impl<S, T> GraphQLType<S> for Nullable<T>
 where
     T: GraphQLType<S>,
@@ -252,7 +379,7 @@ where
     ) -> ExecutionResult<S> {
         match *self {
             Self::Some(ref obj) => executor.resolve(info, obj),
-            _ => Ok(Value::null()),
+            _ => Ok(graphql::Value::null()),
         }
     }
 }
@@ -269,11 +396,11 @@ where
         info: &'a Self::TypeInfo,
         _: Option<&'a [Selection<S>]>,
         executor: &'a Executor<Self::Context, S>,
-    ) -> crate::BoxFuture<'a, ExecutionResult<S>> {
+    ) -> BoxFuture<'a, ExecutionResult<S>> {
         let f = async move {
             let value = match self {
                 Self::Some(obj) => executor.resolve_into_value_async(info, obj).await,
-                _ => Value::null(),
+                _ => graphql::Value::null(),
             };
             Ok(value)
         };
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index 98f995c48..be1ceb485 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -1,3 +1,5 @@
+//! GraphQL implementation for [`Option`].
+
 use futures::future;
 
 use crate::{
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 0ac2d2639..3cc1f7355 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -1,3 +1,5 @@
+//! GraphQL implementation for [`Rc`].
+
 use std::rc::Rc;
 
 use crate::{
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 2f0867947..36b27e4d1 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -1,3 +1,7 @@
+//! GraphQL implementation for [reference].
+//!
+//! [reference]: primitive@std::reference
+
 use crate::{
     graphql, meta::MetaType, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry,
     Selection,
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index 566359b65..eee1ae3b4 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -1,3 +1,7 @@
+//! GraphQL implementation for mutable [reference].
+//!
+//! [reference]: primitive@std::reference
+
 use crate::{
     graphql, meta::MetaType, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry,
     Selection,
diff --git a/juniper/src/types/slice.rs b/juniper/src/types/slice.rs
new file mode 100644
index 000000000..e3ad5b49a
--- /dev/null
+++ b/juniper/src/types/slice.rs
@@ -0,0 +1,81 @@
+//! GraphQL implementation for [slice].
+//!
+//! [slice]: primitive@std::slice
+
+use crate::{
+    executor::{ExecutionResult, Executor, Registry},
+    graphql, resolve,
+    schema::meta::MetaType,
+    BoxFuture, Selection,
+};
+
+use super::iter;
+
+impl<T, Info, S> resolve::Type<Info, S> for [T]
+where
+    T: resolve::Type<Info, S>,
+    Info: ?Sized,
+{
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        registry.build_list_type_new::<T, _>(info, None).into_meta()
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for [T]
+where
+    T: resolve::Value<Info, Ctx, S>,
+    Info: ?Sized,
+    Ctx: ?Sized,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, S>]>,
+        info: &Info,
+        executor: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        iter::resolve_list(self.iter(), selection_set, info, executor)
+    }
+}
+
+impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for [T]
+where
+    T: resolve::ValueAsync<Info, Ctx, S> + Sync,
+    Info: Sync + ?Sized,
+    Ctx: Sync + ?Sized,
+    S: Send + Sync,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, S>]>,
+        info: &'r Info,
+        executor: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        Box::pin(iter::resolve_list_async(
+            self.iter(),
+            selection_set,
+            info,
+            executor,
+        ))
+    }
+}
+
+impl<T, S> graphql::InputType<S> for [T]
+where
+    T: graphql::InputType<S>,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<T, S> graphql::OutputType<S> for [T]
+where
+    T: graphql::OutputType<S>,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
index e2374e27f..a085f90ff 100644
--- a/juniper/src/types/vec.rs
+++ b/juniper/src/types/vec.rs
@@ -1,3 +1,5 @@
+//! GraphQL implementation for [`Vec`].
+
 use crate::{
     executor::{ExecutionResult, Executor, Registry},
     graphql, resolve,

From 64cf7adb4f5370f8edc0d59ec8f6f55565ebdeac Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 5 May 2022 18:35:42 +0300
Subject: [PATCH 05/58] Impl basic types, vol.3

---
 juniper/src/executor/mod.rs  | 16 ++++++
 juniper/src/graphql/mod.rs   | 15 +++++-
 juniper/src/resolve/mod.rs   | 47 +++++++++++++++--
 juniper/src/schema/meta.rs   | 42 +++++++++++++---
 juniper/src/types/arc.rs     | 26 ++++++++--
 juniper/src/types/box.rs     | 26 ++++++++--
 juniper/src/types/mod.rs     |  1 +
 juniper/src/types/rc.rs      | 26 ++++++++--
 juniper/src/types/ref.rs     | 24 ++++++++-
 juniper/src/types/ref_mut.rs | 24 ++++++++-
 juniper/src/types/str.rs     | 97 ++++++++++++++++++++++++++++++++++++
 11 files changed, 318 insertions(+), 26 deletions(-)
 create mode 100644 juniper/src/types/str.rs

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 23073222f..d749fc4ae 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -4,6 +4,7 @@ use std::{
     borrow::Cow,
     cmp::Ordering,
     collections::HashMap,
+    convert::TryFrom,
     fmt::{Debug, Display},
     sync::{Arc, RwLock},
 };
@@ -1294,6 +1295,21 @@ impl<'r, S: 'r> Registry<'r, S> {
         ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
     }
 
+    /// Builds a [`ScalarMeta`] information for the specified [`graphql::Type`].
+    ///
+    /// [`graphql::Type`]: resolve::Type
+    pub fn build_scalar_type_new<'info, T, Info>(&mut self, info: &Info) -> ScalarMeta<'r, S>
+    where
+        T: resolve::TypeName<Info>
+            + resolve::ScalarToken<S>
+            + for<'inp> resolve::InputValue<'inp, S>,
+        for<'i> <T as TryFrom<&'i InputValue<S>>>::Error: IntoFieldError<S>,
+        Info: ?Sized,
+    {
+        // TODO: Allow using references.
+        ScalarMeta::new_new::<T, _>(T::type_name(info).to_owned())
+    }
+
     /// Creates a [`ListMeta`] type.
     ///
     /// Specifying `expected_size` will be used to ensure that values of this
diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 4d87480d9..fb1ac95fd 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -2,7 +2,9 @@ pub mod resolve;
 
 use crate::DefaultScalarValue;
 
-pub use crate::value::Value;
+pub use crate::{
+    ast::InputValue, graphql_input_value as input_value, graphql_value as value, value::Value,
+};
 
 pub use self::resolve::Type;
 
@@ -34,6 +36,17 @@ pub trait Object<S = DefaultScalarValue>:
     fn assert_object();
 }
 
+pub trait Scalar<S = DefaultScalarValue>:
+    InputType<S>
+    + OutputType<S>
+    + Type<S>
+    + resolve::TypeName
+    + resolve::Value<S>
+    + resolve::ValueAsync<S>
+{
+    fn assert_scalar();
+}
+
 pub trait Union<S = DefaultScalarValue>:
     OutputType<S>
     + Type<S>
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index e027d0cf5..dd23fd4df 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -1,12 +1,16 @@
+use std::convert::TryFrom;
+
 use crate::{
-    meta::MetaType, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, Registry,
-    Selection,
+    graphql,
+    meta::MetaType,
+    parser::{self, ParseError},
+    Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, Registry, Selection,
 };
 
 pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
     fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
     where
-        S: 'r;
+        S: 'r; // TODO: remove?
 }
 
 pub trait TypeName<Info: ?Sized> {
@@ -74,3 +78,40 @@ pub trait FieldAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
         executor: &'r Executor<Ctx, S>,
     ) -> BoxFuture<'r, ExecutionResult<S>>;
 }
+
+pub trait InputValue<'inp, S: 'inp>: TryFrom<&'inp graphql::InputValue<S>> {
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        Self::try_from(&graphql::InputValue::<S>::Null)
+    }
+}
+
+pub trait InputValueOwned<S>: for<'inp> InputValue<'inp, S> {}
+
+impl<T, S> InputValueOwned<S> for T where T: for<'inp> InputValue<'inp, S> {}
+
+pub trait ValidateInputValue<S>: Sized {
+    fn validate_input_value<'inp>(
+        v: &'inp graphql::InputValue<S>,
+    ) -> Result<(), crate::FieldError<S>>
+    where
+        Self: TryFrom<&'inp graphql::InputValue<S>>,
+        <Self as TryFrom<&'inp graphql::InputValue<S>>>::Error: crate::IntoFieldError<S>;
+}
+
+impl<T, S> ValidateInputValue<S> for T {
+    fn validate_input_value<'inp>(
+        v: &'inp graphql::InputValue<S>,
+    ) -> Result<(), crate::FieldError<S>>
+    where
+        Self: TryFrom<&'inp graphql::InputValue<S>>,
+        <Self as TryFrom<&'inp graphql::InputValue<S>>>::Error: crate::IntoFieldError<S>,
+    {
+        Self::try_from(v)
+            .map(drop)
+            .map_err(crate::IntoFieldError::<S>::into_field_error)
+    }
+}
+
+pub trait ScalarToken<S = DefaultScalarValue> {
+    fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<S, ParseError<'_>>;
+}
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index 2ba1faa49..f80afce35 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -1,18 +1,19 @@
 //! Types used to describe a `GraphQL` schema
 
-use juniper::IntoFieldError;
 use std::{
     borrow::{Cow, ToOwned},
+    convert::TryFrom,
     fmt,
 };
 
 use crate::{
     ast::{FromInputValue, InputValue, Type},
     parser::{ParseError, ScalarToken},
+    resolve,
     schema::model::SchemaType,
     types::base::TypeKind,
     value::{DefaultScalarValue, ParseScalarValue},
-    FieldError,
+    FieldError, IntoFieldError,
 };
 
 /// Whether an item is deprecated, with context.
@@ -28,16 +29,16 @@ impl DeprecationStatus {
     /// If this deprecation status indicates the item is deprecated.
     pub fn is_deprecated(&self) -> bool {
         match self {
-            DeprecationStatus::Current => false,
-            DeprecationStatus::Deprecated(_) => true,
+            Self::Current => false,
+            Self::Deprecated(_) => true,
         }
     }
 
     /// An optional reason for the deprecation, or none if `Current`.
     pub fn reason(&self) -> Option<&str> {
         match self {
-            DeprecationStatus::Current => None,
-            DeprecationStatus::Deprecated(rsn) => rsn.as_deref(),
+            Self::Current => None,
+            Self::Deprecated(rsn) => rsn.as_deref(),
         }
     }
 }
@@ -448,6 +449,27 @@ impl<'a, S> ScalarMeta<'a, S> {
         }
     }
 
+    /// Builds a new [`ScalarMeta`] information with the specified `name`.
+    // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
+    //       `explicit_generic_args_with_impl_trait` hits stable:
+    //       https://github.com/rust-lang/rust/issues/83701
+    pub fn new_new<T, N>(name: N) -> Self
+    where
+        T: resolve::ValidateInputValue<S> + resolve::ScalarToken<S>,
+        //T: for<'inp> resolve::InputValue<'inp, S> + resolve::ScalarToken<S>,
+        //for<'inp> <T as TryFrom<&'inp InputValue<S>>>::Error: IntoFieldError<S>,
+        Cow<'a, str>: From<N>,
+    {
+        Self {
+            name: name.into(),
+            description: None,
+            specified_by_url: None,
+            try_parse_fn: <T as resolve::ValidateInputValue<S>>::validate_input_value,
+            //try_parse_fn: |inp| try_parse_fn_new::<S, T>(inp),
+            parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
+        }
+    }
+
     /// Sets the `description` of this [`ScalarMeta`] type.
     ///
     /// Overwrites any previously set description.
@@ -799,3 +821,11 @@ where
         .map(drop)
         .map_err(T::Error::into_field_error)
 }
+
+fn try_parse_fn_new<'inp, 'b: 'inp, S: 'inp, T>(v: &'b InputValue<S>) -> Result<(), FieldError<S>>
+where
+    T: resolve::InputValue<'inp, S>,
+    T::Error: IntoFieldError<S>,
+{
+    T::try_from(v).map(drop).map_err(T::Error::into_field_error)
+}
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 467951c88..309022d5e 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -3,10 +3,10 @@
 use std::sync::Arc;
 
 use crate::{
-    executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
-    schema::meta::MetaType,
-    Arguments, BoxFuture, Selection,
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Arc<T>
@@ -142,6 +142,15 @@ where
     }
 }
 
+impl<T, S> resolve::ScalarToken<S> for Arc<T>
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Arc<T>
 where
     T: graphql::InputType<S> + ?Sized,
@@ -178,6 +187,15 @@ where
     }
 }
 
+impl<T, S> graphql::Scalar<S> for Arc<T>
+where
+    T: graphql::Scalar<S> + ?Sized,
+{
+    fn assert_scalar() {
+        T::assert_scalar()
+    }
+}
+
 impl<T, S> graphql::Union<S> for Arc<T>
 where
     T: graphql::Union<S> + ?Sized,
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index c8140f3e2..91f2434b5 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -1,10 +1,10 @@
 //! GraphQL implementation for [`Box`].
 
 use crate::{
-    executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
-    schema::meta::MetaType,
-    Arguments, BoxFuture, Selection,
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Box<T>
@@ -140,6 +140,15 @@ where
     }
 }
 
+impl<T, S> resolve::ScalarToken<S> for Box<T>
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Box<T>
 where
     T: graphql::InputType<S> + ?Sized,
@@ -176,6 +185,15 @@ where
     }
 }
 
+impl<T, S> graphql::Scalar<S> for Box<T>
+where
+    T: graphql::Scalar<S> + ?Sized,
+{
+    fn assert_scalar() {
+        T::assert_scalar()
+    }
+}
+
 impl<T, S> graphql::Union<S> for Box<T>
 where
     T: graphql::Union<S> + ?Sized,
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 5fceeb2ba..5823a8a51 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -8,6 +8,7 @@ mod rc;
 mod r#ref;
 mod ref_mut;
 mod slice;
+mod r#str;
 mod vec;
 
 pub mod async_await;
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 3cc1f7355..430790c9e 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -3,10 +3,10 @@
 use std::rc::Rc;
 
 use crate::{
-    executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
-    schema::meta::MetaType,
-    Arguments, BoxFuture, Selection,
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Rc<T>
@@ -142,6 +142,15 @@ where
     }
 }
 
+impl<T, S> resolve::ScalarToken<S> for Rc<T>
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Rc<T>
 where
     T: graphql::InputType<S> + ?Sized,
@@ -178,6 +187,15 @@ where
     }
 }
 
+impl<T, S> graphql::Scalar<S> for Rc<T>
+where
+    T: graphql::Scalar<S> + ?Sized,
+{
+    fn assert_scalar() {
+        T::assert_scalar()
+    }
+}
+
 impl<T, S> graphql::Union<S> for Rc<T>
 where
     T: graphql::Union<S> + ?Sized,
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 36b27e4d1..42204d89e 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -3,8 +3,10 @@
 //! [reference]: primitive@std::reference
 
 use crate::{
-    graphql, meta::MetaType, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry,
-    Selection,
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
 impl<'me, T, Info, S> resolve::Type<Info, S> for &'me T
@@ -140,6 +142,15 @@ where
     }
 }
 
+impl<'me, T, S> resolve::ScalarToken<S> for &'me T
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<'me, T, S> graphql::InputType<S> for &'me T
 where
     T: graphql::InputType<S> + ?Sized,
@@ -176,6 +187,15 @@ where
     }
 }
 
+impl<'me, T, S> graphql::Scalar<S> for &'me T
+where
+    T: graphql::Scalar<S> + ?Sized,
+{
+    fn assert_scalar() {
+        T::assert_scalar()
+    }
+}
+
 impl<'me, T, S> graphql::Union<S> for &'me T
 where
     T: graphql::Union<S> + ?Sized,
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index eee1ae3b4..a9418a0f7 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -3,8 +3,10 @@
 //! [reference]: primitive@std::reference
 
 use crate::{
-    graphql, meta::MetaType, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry,
-    Selection,
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
 impl<'me, T, Info, S> resolve::Type<Info, S> for &'me mut T
@@ -140,6 +142,15 @@ where
     }
 }
 
+impl<'me, T, S> resolve::ScalarToken<S> for &'me mut T
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<'me, T, S> graphql::InputType<S> for &'me mut T
 where
     T: graphql::InputType<S> + ?Sized,
@@ -176,6 +187,15 @@ where
     }
 }
 
+impl<'me, T, S> graphql::Scalar<S> for &'me mut T
+where
+    T: graphql::Scalar<S> + ?Sized,
+{
+    fn assert_scalar() {
+        T::assert_scalar()
+    }
+}
+
 impl<'me, T, S> graphql::Union<S> for &'me mut T
 where
     T: graphql::Union<S> + ?Sized,
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
new file mode 100644
index 000000000..1b62c3c28
--- /dev/null
+++ b/juniper/src/types/str.rs
@@ -0,0 +1,97 @@
+//! GraphQL implementation for [`str`].
+//!
+//! [`str`]: primitive@std::str
+
+use std::convert::TryFrom;
+
+use futures::future;
+
+use crate::{
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    resolve, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry, ScalarValue,
+    Selection,
+};
+
+impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
+    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    where
+        S: 'r,
+    {
+        registry.build_scalar_type_new::<&Self, _>(info).into_meta()
+    }
+}
+
+impl<Info: ?Sized> resolve::TypeName<Info> for str {
+    fn type_name(_: &Info) -> &'static str {
+        // TODO: Reuse from `String`.
+        "String"
+    }
+}
+
+impl<Info, Ctx, S> resolve::Value<Info, Ctx, S> for str
+where
+    Info: ?Sized,
+    Ctx: ?Sized,
+    S: From<String>,
+{
+    fn resolve_value(
+        &self,
+        _: Option<&[Selection<'_, S>]>,
+        _: &Info,
+        _: &Executor<Ctx, S>,
+    ) -> ExecutionResult<S> {
+        // TODO: Remove redundant `.to_owned()` allocation by allowing
+        //       `ScalarValue` creation from reference?
+        Ok(graphql::Value::scalar(self.to_owned()))
+    }
+}
+
+impl<Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for str
+where
+    Info: ?Sized,
+    Ctx: ?Sized,
+    S: From<String> + Send,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        _: Option<&'r [Selection<'_, S>]>,
+        _: &'r Info,
+        _: &'r Executor<Ctx, S>,
+    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        // TODO: Remove redundant `.to_owned()` allocation by allowing
+        //       `ScalarValue` creation from reference?
+        Box::pin(future::ok(graphql::Value::scalar(self.to_owned())))
+    }
+}
+
+impl<'me, S: ScalarValue> resolve::ScalarToken<S> for str {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        // TODO: replace with `resolve::ScalarToken<S>`
+        <String as crate::ParseScalarValue<S>>::from_str(token)
+    }
+}
+
+impl<S> graphql::InputType<S> for str {
+    fn assert_input_type() {}
+}
+
+impl<S> graphql::OutputType<S> for str {
+    fn assert_output_type() {}
+}
+
+impl<S> graphql::Scalar<S> for str {
+    fn assert_scalar() {}
+}
+
+impl<'inp: 'me, 'me, S: ScalarValue> TryFrom<&'inp graphql::InputValue<S>> for &'me str {
+    type Error = String;
+
+    fn try_from(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
+        v.as_string_value()
+            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+    }
+}
+
+impl<'inp: 'me, 'me, S: ScalarValue> resolve::InputValue<'inp, S> for &'me str {}

From bde5b83eafff83b35f8c28035ed36e7d39294115 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Wed, 11 May 2022 19:12:24 +0300
Subject: [PATCH 06/58] Upd

---
 juniper/src/executor/mod.rs |  2 ++
 juniper/src/resolve/mod.rs  | 45 ++++++++++++++++---------------------
 juniper/src/schema/meta.rs  |  4 ++++
 juniper/src/types/ref.rs    | 15 +++++++++++++
 juniper/src/types/str.rs    | 25 ++++++++++-----------
 5 files changed, 52 insertions(+), 39 deletions(-)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index d749fc4ae..3969befbd 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -1295,6 +1295,7 @@ impl<'r, S: 'r> Registry<'r, S> {
         ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
     }
 
+    /*
     /// Builds a [`ScalarMeta`] information for the specified [`graphql::Type`].
     ///
     /// [`graphql::Type`]: resolve::Type
@@ -1309,6 +1310,7 @@ impl<'r, S: 'r> Registry<'r, S> {
         // TODO: Allow using references.
         ScalarMeta::new_new::<T, _>(T::type_name(info).to_owned())
     }
+    */
 
     /// Creates a [`ListMeta`] type.
     ///
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index dd23fd4df..98bc3fb17 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -79,39 +79,32 @@ pub trait FieldAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
     ) -> BoxFuture<'r, ExecutionResult<S>>;
 }
 
-pub trait InputValue<'inp, S: 'inp>: TryFrom<&'inp graphql::InputValue<S>> {
+pub trait ScalarToken<S = DefaultScalarValue> {
+    fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<S, ParseError<'_>>;
+}
+
+pub trait InputValue<'input, S: 'input = DefaultScalarValue>: Sized {
+    type Error;
+
+    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Self, Self::Error>;
+
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        Self::try_from(&graphql::InputValue::<S>::Null)
+        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
     }
 }
 
-pub trait InputValueOwned<S>: for<'inp> InputValue<'inp, S> {}
+pub trait InputValueOwned<S = DefaultScalarValue>: for<'i> InputValue<'i, S> {}
 
-impl<T, S> InputValueOwned<S> for T where T: for<'inp> InputValue<'inp, S> {}
+impl<T, S> InputValueOwned<S> for T where T: for<'i> InputValue<'i, S> {}
 
-pub trait ValidateInputValue<S>: Sized {
-    fn validate_input_value<'inp>(
-        v: &'inp graphql::InputValue<S>,
-    ) -> Result<(), crate::FieldError<S>>
-    where
-        Self: TryFrom<&'inp graphql::InputValue<S>>,
-        <Self as TryFrom<&'inp graphql::InputValue<S>>>::Error: crate::IntoFieldError<S>;
-}
+pub trait InputValueAsRef<S = DefaultScalarValue> {
+    type Error;
 
-impl<T, S> ValidateInputValue<S> for T {
-    fn validate_input_value<'inp>(
-        v: &'inp graphql::InputValue<S>,
-    ) -> Result<(), crate::FieldError<S>>
-    where
-        Self: TryFrom<&'inp graphql::InputValue<S>>,
-        <Self as TryFrom<&'inp graphql::InputValue<S>>>::Error: crate::IntoFieldError<S>,
+    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error>;
+
+    fn try_from_implicit_null() -> Result<&'static Self, Self::Error>
+    where S: 'static
     {
-        Self::try_from(v)
-            .map(drop)
-            .map_err(crate::IntoFieldError::<S>::into_field_error)
+        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
     }
 }
-
-pub trait ScalarToken<S = DefaultScalarValue> {
-    fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<S, ParseError<'_>>;
-}
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index f80afce35..fd9ff96e2 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -449,6 +449,7 @@ impl<'a, S> ScalarMeta<'a, S> {
         }
     }
 
+    /*
     /// Builds a new [`ScalarMeta`] information with the specified `name`.
     // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
     //       `explicit_generic_args_with_impl_trait` hits stable:
@@ -469,6 +470,7 @@ impl<'a, S> ScalarMeta<'a, S> {
             parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
         }
     }
+    */
 
     /// Sets the `description` of this [`ScalarMeta`] type.
     ///
@@ -822,6 +824,7 @@ where
         .map_err(T::Error::into_field_error)
 }
 
+/*
 fn try_parse_fn_new<'inp, 'b: 'inp, S: 'inp, T>(v: &'b InputValue<S>) -> Result<(), FieldError<S>>
 where
     T: resolve::InputValue<'inp, S>,
@@ -829,3 +832,4 @@ where
 {
     T::try_from(v).map(drop).map_err(T::Error::into_field_error)
 }
+*/
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 42204d89e..78407fdb2 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -151,6 +151,21 @@ where
     }
 }
 
+impl<'inp: 'me, 'me, T, S: 'inp> resolve::InputValue<'inp, S> for &'me T
+where
+    T: resolve::InputValueAsRef<S> + ?Sized,
+{
+    type Error = <T as resolve::InputValueAsRef<S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
+        <T as resolve::InputValueAsRef<S>>::try_from_input_value(v)
+    }
+
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        <T as resolve::InputValueAsRef<S>>::try_from_implicit_null()
+    }
+}
+
 impl<'me, T, S> graphql::InputType<S> for &'me T
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 1b62c3c28..08367508e 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -19,7 +19,8 @@ impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
     where
         S: 'r,
     {
-        registry.build_scalar_type_new::<&Self, _>(info).into_meta()
+       // registry.build_scalar_type_new::<&Self, _>(info).into_meta()
+        unimplemented!()
     }
 }
 
@@ -68,11 +69,20 @@ where
 
 impl<'me, S: ScalarValue> resolve::ScalarToken<S> for str {
     fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        // TODO: replace with `resolve::ScalarToken<S>`
+        // TODO: Replace with `resolve::ScalarToken<S>`
         <String as crate::ParseScalarValue<S>>::from_str(token)
     }
 }
 
+impl<'me, S: ScalarValue> resolve::InputValueAsRef<S> for str {
+    type Error = String;
+
+    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error> {
+        v.as_string_value()
+            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+    }
+}
+
 impl<S> graphql::InputType<S> for str {
     fn assert_input_type() {}
 }
@@ -84,14 +94,3 @@ impl<S> graphql::OutputType<S> for str {
 impl<S> graphql::Scalar<S> for str {
     fn assert_scalar() {}
 }
-
-impl<'inp: 'me, 'me, S: ScalarValue> TryFrom<&'inp graphql::InputValue<S>> for &'me str {
-    type Error = String;
-
-    fn try_from(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
-        v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
-    }
-}
-
-impl<'inp: 'me, 'me, S: ScalarValue> resolve::InputValue<'inp, S> for &'me str {}

From 912d31f66b652d342c7c0b4943acd55b9ef3221e Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 12 May 2022 18:53:19 +0300
Subject: [PATCH 07/58] Poking with parsing input

---
 juniper/src/executor/mod.rs   | 23 ++++++++++------
 juniper/src/lib.rs            |  2 +-
 juniper/src/resolve/mod.rs    | 24 ++++++++++++-----
 juniper/src/schema/meta.rs    | 49 +++++++++++++++++++++++++----------
 juniper/src/types/box.rs      | 16 ++++++++++++
 juniper/src/types/mod.rs      |  2 +-
 juniper/src/types/nullable.rs | 19 ++++++++++++++
 juniper/src/types/option.rs   | 15 +++++++++++
 juniper/src/types/str.rs      | 10 +++----
 9 files changed, 123 insertions(+), 37 deletions(-)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 3969befbd..0dc3118b1 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -4,7 +4,6 @@ use std::{
     borrow::Cow,
     cmp::Ordering,
     collections::HashMap,
-    convert::TryFrom,
     fmt::{Debug, Display},
     sync::{Arc, RwLock},
 };
@@ -1295,22 +1294,30 @@ impl<'r, S: 'r> Registry<'r, S> {
         ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
     }
 
-    /*
     /// Builds a [`ScalarMeta`] information for the specified [`graphql::Type`].
     ///
     /// [`graphql::Type`]: resolve::Type
-    pub fn build_scalar_type_new<'info, T, Info>(&mut self, info: &Info) -> ScalarMeta<'r, S>
+    pub fn build_scalar_type_new<T, Info>(&mut self, info: &Info) -> ScalarMeta<'r, S>
     where
-        T: resolve::TypeName<Info>
-            + resolve::ScalarToken<S>
-            + for<'inp> resolve::InputValue<'inp, S>,
-        for<'i> <T as TryFrom<&'i InputValue<S>>>::Error: IntoFieldError<S>,
+        T: resolve::TypeName<Info> + resolve::ScalarToken<S> + resolve::InputValueOwned<S>,
         Info: ?Sized,
     {
         // TODO: Allow using references.
         ScalarMeta::new_new::<T, _>(T::type_name(info).to_owned())
     }
-    */
+
+    /// Builds a [`ScalarMeta`] information for the [`?Sized`] specified
+    /// [`graphql::Type`].
+    ///
+    /// [`graphql::Type`]: resolve::Type
+    pub fn build_scalar_type_unsized<T, Info>(&mut self, info: &Info) -> ScalarMeta<'r, S>
+    where
+        T: resolve::TypeName<Info> + resolve::ScalarToken<S> + resolve::InputValueAsRef<S> + ?Sized,
+        Info: ?Sized,
+    {
+        // TODO: Allow using references.
+        ScalarMeta::new_unsized::<T, _>(T::type_name(info).to_owned())
+    }
 
     /// Creates a [`ListMeta`] type.
     ///
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 9ee509bbc..6e35d2301 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -82,12 +82,12 @@ pub use crate::{
         async_await::{GraphQLTypeAsync, GraphQLValueAsync},
         base::{Arguments, GraphQLType, GraphQLValue, TypeKind},
         marker::{self, GraphQLInterface, GraphQLObject, GraphQLUnion},
-        Nullable,
         scalars::{EmptyMutation, EmptySubscription, ID},
         subscriptions::{
             ExecutionOutput, GraphQLSubscriptionType, GraphQLSubscriptionValue,
             SubscriptionConnection, SubscriptionCoordinator,
         },
+        Nullable,
     },
     validation::RuleError,
     value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value},
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 98bc3fb17..12e108d6c 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -1,10 +1,9 @@
-use std::convert::TryFrom;
-
 use crate::{
     graphql,
     meta::MetaType,
     parser::{self, ParseError},
-    Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, Registry, Selection,
+    Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError, Registry,
+    Selection,
 };
 
 pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
@@ -84,7 +83,7 @@ pub trait ScalarToken<S = DefaultScalarValue> {
 }
 
 pub trait InputValue<'input, S: 'input = DefaultScalarValue>: Sized {
-    type Error;
+    type Error: IntoFieldError<S>;
 
     fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Self, Self::Error>;
 
@@ -98,13 +97,24 @@ pub trait InputValueOwned<S = DefaultScalarValue>: for<'i> InputValue<'i, S> {}
 impl<T, S> InputValueOwned<S> for T where T: for<'i> InputValue<'i, S> {}
 
 pub trait InputValueAsRef<S = DefaultScalarValue> {
-    type Error;
+    type Error: IntoFieldError<S>;
 
     fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error>;
 
-    fn try_from_implicit_null() -> Result<&'static Self, Self::Error>
-    where S: 'static
+    fn try_from_implicit_null<'a>() -> Result<&'a Self, Self::Error>
+    where
+        S: 'a,
     {
         Self::try_from_input_value(&graphql::InputValue::<S>::Null)
     }
 }
+
+/*
+impl<T, S> InputValueAsRef<S> for T where T: InputValueOwned<S> {
+    type Error = <T as InputValueOwned<S>>::Error;
+
+    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error> {
+        <T as InputValueOwned<S>>::try_from_input_value(v).as_ref()
+    }
+}
+*/
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index fd9ff96e2..dfcc838d2 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -2,7 +2,6 @@
 
 use std::{
     borrow::{Cow, ToOwned},
-    convert::TryFrom,
     fmt,
 };
 
@@ -449,28 +448,42 @@ impl<'a, S> ScalarMeta<'a, S> {
         }
     }
 
-    /*
     /// Builds a new [`ScalarMeta`] information with the specified `name`.
     // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
     //       `explicit_generic_args_with_impl_trait` hits stable:
     //       https://github.com/rust-lang/rust/issues/83701
     pub fn new_new<T, N>(name: N) -> Self
     where
-        T: resolve::ValidateInputValue<S> + resolve::ScalarToken<S>,
-        //T: for<'inp> resolve::InputValue<'inp, S> + resolve::ScalarToken<S>,
-        //for<'inp> <T as TryFrom<&'inp InputValue<S>>>::Error: IntoFieldError<S>,
+        T: resolve::InputValueOwned<S> + resolve::ScalarToken<S>,
         Cow<'a, str>: From<N>,
     {
         Self {
             name: name.into(),
             description: None,
             specified_by_url: None,
-            try_parse_fn: <T as resolve::ValidateInputValue<S>>::validate_input_value,
-            //try_parse_fn: |inp| try_parse_fn_new::<S, T>(inp),
+            try_parse_fn: try_parse_fn_new::<S, T>,
+            parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
+        }
+    }
+
+    /// Builds a new [`ScalarMeta`] information with the specified `name` for
+    /// the [`?Sized`] `T`ype that may only be parsed as a reference.
+    // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
+    //       `explicit_generic_args_with_impl_trait` hits stable:
+    //       https://github.com/rust-lang/rust/issues/83701
+    pub fn new_unsized<T, N>(name: N) -> Self
+    where
+        T: resolve::InputValueAsRef<S> + resolve::ScalarToken<S> + ?Sized,
+        Cow<'a, str>: From<N>,
+    {
+        Self {
+            name: name.into(),
+            description: None,
+            specified_by_url: None,
+            try_parse_fn: try_parse_unsized_fn::<S, T>,
             parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
         }
     }
-    */
 
     /// Sets the `description` of this [`ScalarMeta`] type.
     ///
@@ -824,12 +837,20 @@ where
         .map_err(T::Error::into_field_error)
 }
 
-/*
-fn try_parse_fn_new<'inp, 'b: 'inp, S: 'inp, T>(v: &'b InputValue<S>) -> Result<(), FieldError<S>>
+fn try_parse_fn_new<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
 where
-    T: resolve::InputValue<'inp, S>,
-    T::Error: IntoFieldError<S>,
+    T: resolve::InputValueOwned<S>,
 {
-    T::try_from(v).map(drop).map_err(T::Error::into_field_error)
+    T::try_from_input_value(v)
+        .map(drop)
+        .map_err(T::Error::into_field_error)
+}
+
+fn try_parse_unsized_fn<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
+where
+    T: resolve::InputValueAsRef<S> + ?Sized,
+{
+    T::try_from_input_value(v)
+        .map(drop)
+        .map_err(T::Error::into_field_error)
 }
-*/
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 91f2434b5..3354d3991 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -149,6 +149,22 @@ where
     }
 }
 
+// TODO: how to parse unsized?
+impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Box<T>
+where
+    T: resolve::InputValue<'inp, S>,
+{
+    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Self::new)
+    }
+
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Self::new)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Box<T>
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 5823a8a51..31517c72d 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -1,5 +1,5 @@
-mod array;
 mod arc;
+mod array;
 mod r#box;
 pub mod iter;
 mod nullable;
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index 1d2f55839..eb1ee10cb 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -324,6 +324,25 @@ where
     }
 }
 
+impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Nullable<T>
+where
+    T: resolve::InputValue<'inp, S>,
+{
+    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp InputValue<S>) -> Result<Self, Self::Error> {
+        if v.is_null() {
+            Ok(Self::ExplicitNull)
+        } else {
+            <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Self::Some)
+        }
+    }
+
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        Ok(Self::ImplicitNull)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Nullable<T>
 where
     T: graphql::InputType<S>,
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index be1ceb485..ec3f06492 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -61,6 +61,21 @@ where
     }
 }
 
+impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Option<T>
+where
+    T: resolve::InputValue<'inp, S>,
+{
+    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
+        if v.is_null() {
+            Ok(None)
+        } else {
+            <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Some)
+        }
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Option<T>
 where
     T: graphql::InputType<S>,
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 08367508e..b7eb4845a 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -2,16 +2,13 @@
 //!
 //! [`str`]: primitive@std::str
 
-use std::convert::TryFrom;
-
 use futures::future;
 
 use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry, ScalarValue,
-    Selection,
+    resolve, BoxFuture, ExecutionResult, Executor, Registry, ScalarValue, Selection,
 };
 
 impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
@@ -19,8 +16,9 @@ impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
     where
         S: 'r,
     {
-       // registry.build_scalar_type_new::<&Self, _>(info).into_meta()
-        unimplemented!()
+        registry
+            .build_scalar_type_unsized::<Self, _>(info)
+            .into_meta()
     }
 }
 

From 5a3bd6c8a9bc7becdad8bd753d5585a6e98cbcf9 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 17 May 2022 16:59:42 +0200
Subject: [PATCH 08/58] Pave way to parse `?Sized` types from `InputValue`

---
 juniper/src/resolve/mod.rs | 29 +++++-------------------
 juniper/src/types/arc.rs   | 45 +++++++++++++++++++++++++++++++++++++-
 juniper/src/types/box.rs   | 41 ++++++++++++++++++++++++++++------
 juniper/src/types/mod.rs   |  8 +++----
 juniper/src/types/rc.rs    | 45 +++++++++++++++++++++++++++++++++++++-
 juniper/src/types/ref.rs   | 16 +++++++++++++-
 juniper/src/types/str.rs   | 30 +++++++++++++++++++++++--
 7 files changed, 175 insertions(+), 39 deletions(-)

diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 12e108d6c..39c693e3c 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -6,6 +6,12 @@ use crate::{
     Selection,
 };
 
+#[doc(inline)]
+pub use crate::types::{
+    arc::TryFromInputValue as InputValueAsArc, r#box::TryFromInputValue as InputValueAsBox,
+    r#ref::TryFromInputValue as InputValueAsRef, rc::TryFromInputValue as InputValueAsRc,
+};
+
 pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
     fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
     where
@@ -95,26 +101,3 @@ pub trait InputValue<'input, S: 'input = DefaultScalarValue>: Sized {
 pub trait InputValueOwned<S = DefaultScalarValue>: for<'i> InputValue<'i, S> {}
 
 impl<T, S> InputValueOwned<S> for T where T: for<'i> InputValue<'i, S> {}
-
-pub trait InputValueAsRef<S = DefaultScalarValue> {
-    type Error: IntoFieldError<S>;
-
-    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error>;
-
-    fn try_from_implicit_null<'a>() -> Result<&'a Self, Self::Error>
-    where
-        S: 'a,
-    {
-        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
-    }
-}
-
-/*
-impl<T, S> InputValueAsRef<S> for T where T: InputValueOwned<S> {
-    type Error = <T as InputValueOwned<S>>::Error;
-
-    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error> {
-        <T as InputValueOwned<S>>::try_from_input_value(v).as_ref()
-    }
-}
-*/
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 309022d5e..6c9b8faf8 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -6,7 +6,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
+    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
+    Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Arc<T>
@@ -151,6 +152,48 @@ where
     }
 }
 
+impl<'inp, T, S> resolve::InputValue<'inp, S> for Arc<T>
+where
+    T: resolve::InputValueAsArc<'inp, S> + ?Sized,
+    S: 'inp,
+{
+    type Error = <T as resolve::InputValueAsArc<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
+        <T as resolve::InputValueAsArc<'inp, S>>::try_from_input_value(v)
+    }
+
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        <T as resolve::InputValueAsArc<'inp, S>>::try_from_implicit_null()
+    }
+}
+
+pub trait TryFromInputValue<'input, S: 'input = DefaultScalarValue> {
+    type Error: IntoFieldError<S>;
+
+    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Arc<Self>, Self::Error>;
+
+    fn try_from_implicit_null() -> Result<Arc<Self>, Self::Error> {
+        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
+    }
+}
+
+impl<'inp, T, S> TryFromInputValue<'inp, S> for T
+where
+    T: resolve::InputValue<'inp, S>,
+    S: 'inp,
+{
+    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Arc<Self>, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Arc::new)
+    }
+
+    fn try_from_implicit_null() -> Result<Arc<Self>, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Arc::new)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Arc<T>
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 3354d3991..337d15403 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -4,7 +4,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
+    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
+    Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Box<T>
@@ -149,19 +150,45 @@ where
     }
 }
 
-// TODO: how to parse unsized?
-impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Box<T>
+impl<'inp, T, S> resolve::InputValue<'inp, S> for Box<T>
 where
-    T: resolve::InputValue<'inp, S>,
+    T: resolve::InputValueAsBox<'inp, S> + ?Sized,
+    S: 'inp,
 {
-    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+    type Error = <T as resolve::InputValueAsBox<'inp, S>>::Error;
 
     fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Self::new)
+        <T as resolve::InputValueAsBox<'inp, S>>::try_from_input_value(v)
     }
 
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Self::new)
+        <T as resolve::InputValueAsBox<'inp, S>>::try_from_implicit_null()
+    }
+}
+
+pub trait TryFromInputValue<'input, S: 'input = DefaultScalarValue> {
+    type Error: IntoFieldError<S>;
+
+    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Box<Self>, Self::Error>;
+
+    fn try_from_implicit_null() -> Result<Box<Self>, Self::Error> {
+        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
+    }
+}
+
+impl<'inp, T, S> TryFromInputValue<'inp, S> for T
+where
+    T: resolve::InputValue<'inp, S>,
+    S: 'inp,
+{
+    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Box<Self>, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Box::new)
+    }
+
+    fn try_from_implicit_null() -> Result<Box<Self>, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Box::new)
     }
 }
 
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 31517c72d..58dfde7cb 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -1,11 +1,11 @@
-mod arc;
+pub mod arc;
 mod array;
-mod r#box;
+pub mod r#box;
 pub mod iter;
 mod nullable;
 mod option;
-mod rc;
-mod r#ref;
+pub mod rc;
+pub mod r#ref;
 mod ref_mut;
 mod slice;
 mod r#str;
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 430790c9e..8bae30537 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -6,7 +6,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
+    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
+    Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Rc<T>
@@ -151,6 +152,48 @@ where
     }
 }
 
+impl<'inp, T, S> resolve::InputValue<'inp, S> for Rc<T>
+where
+    T: resolve::InputValueAsRc<'inp, S> + ?Sized,
+    S: 'inp,
+{
+    type Error = <T as resolve::InputValueAsRc<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
+        <T as resolve::InputValueAsRc<'inp, S>>::try_from_input_value(v)
+    }
+
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        <T as resolve::InputValueAsRc<'inp, S>>::try_from_implicit_null()
+    }
+}
+
+pub trait TryFromInputValue<'input, S: 'input = DefaultScalarValue> {
+    type Error: IntoFieldError<S>;
+
+    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Rc<Self>, Self::Error>;
+
+    fn try_from_implicit_null() -> Result<Rc<Self>, Self::Error> {
+        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
+    }
+}
+
+impl<'inp, T, S> TryFromInputValue<'inp, S> for T
+where
+    T: resolve::InputValue<'inp, S>,
+    S: 'inp,
+{
+    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Rc<Self>, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Rc::new)
+    }
+
+    fn try_from_implicit_null() -> Result<Rc<Self>, Self::Error> {
+        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Rc::new)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Rc<T>
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 78407fdb2..83d33ac1b 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -6,7 +6,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
+    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
+    Registry, Selection,
 };
 
 impl<'me, T, Info, S> resolve::Type<Info, S> for &'me T
@@ -166,6 +167,19 @@ where
     }
 }
 
+pub trait TryFromInputValue<S = DefaultScalarValue> {
+    type Error: IntoFieldError<S>;
+
+    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error>;
+
+    fn try_from_implicit_null<'a>() -> Result<&'a Self, Self::Error>
+    where
+        S: 'a,
+    {
+        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
+    }
+}
+
 impl<'me, T, S> graphql::InputType<S> for &'me T
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index b7eb4845a..47b26a67f 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -2,6 +2,8 @@
 //!
 //! [`str`]: primitive@std::str
 
+use std::{sync::Arc, rc::Rc};
+
 use futures::future;
 
 use crate::{
@@ -65,14 +67,14 @@ where
     }
 }
 
-impl<'me, S: ScalarValue> resolve::ScalarToken<S> for str {
+impl<S: ScalarValue> resolve::ScalarToken<S> for str {
     fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
         // TODO: Replace with `resolve::ScalarToken<S>`
         <String as crate::ParseScalarValue<S>>::from_str(token)
     }
 }
 
-impl<'me, S: ScalarValue> resolve::InputValueAsRef<S> for str {
+impl<S: ScalarValue> resolve::InputValueAsRef<S> for str {
     type Error = String;
 
     fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error> {
@@ -81,6 +83,30 @@ impl<'me, S: ScalarValue> resolve::InputValueAsRef<S> for str {
     }
 }
 
+impl<'inp, S: ScalarValue> resolve::InputValueAsBox<'inp, S> for str {
+    type Error = String;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Box<Self>, Self::Error> {
+        <str as resolve::InputValueAsRef<S>>::try_from_input_value(v).map(Into::into)
+    }
+}
+
+impl<'inp, S: ScalarValue> resolve::InputValueAsArc<'inp, S> for str {
+    type Error = String;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Arc<Self>, Self::Error> {
+        <str as resolve::InputValueAsRef<S>>::try_from_input_value(v).map(Into::into)
+    }
+}
+
+impl<'inp, S: ScalarValue> resolve::InputValueAsRc<'inp, S> for str {
+    type Error = String;
+
+    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Rc<Self>, Self::Error> {
+        <str as resolve::InputValueAsRef<S>>::try_from_input_value(v).map(Into::into)
+    }
+}
+
 impl<S> graphql::InputType<S> for str {
     fn assert_input_type() {}
 }

From 21c7a3a65376cb1ced390389ffa1575cb0ca80f3 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 17 May 2022 17:13:25 +0200
Subject: [PATCH 09/58] Bootstrap codegen for scalars

---
 juniper/src/types/str.rs                  |  2 +-
 juniper_codegen/src/graphql_scalar/mod.rs | 58 +++++++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 47b26a67f..4177f4da3 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -2,7 +2,7 @@
 //!
 //! [`str`]: primitive@std::str
 
-use std::{sync::Arc, rc::Rc};
+use std::{rc::Rc, sync::Arc};
 
 use futures::future;
 
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 556529805..a0632b9e2 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -330,6 +330,8 @@ impl ToTokens for Definition {
         self.impl_from_input_value_tokens().to_tokens(into);
         self.impl_parse_scalar_value_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
+        ////////////////////////////////////////////////////////////////////////
+        self.impl_resolve_input_value_tokens().to_tokens(into);
     }
 }
 
@@ -524,6 +526,37 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::InputValue`] trait for
+    /// this [GraphQL scalar][1].
+    ///
+    /// [`resolve::InputValue`]: juniper::resolve::InputValue
+    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_input_value_tokens(&self) -> TokenStream {
+        let scalar = &self.scalar;
+
+        let conversion = self.methods.expand_try_from_input_value(scalar);
+
+        let (ty, mut generics) = self.impl_self_and_generics(false);
+        generics.params.push(parse_quote! { '__inp });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::InputValue<'__inp, #scalar> for #ty
+                #where_clause
+            {
+                type Error = ::juniper::FieldError<#scalar>;
+
+                fn try_from_input_value(
+                    input: &'__inp ::juniper::graphql::InputValue<#scalar>,
+                ) -> Result<Self, Self::Error> {
+                    #conversion
+                        .map_err(::juniper::IntoFieldError::<#scalar>::into_field_error)
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`ParseScalarValue`] trait for this
     /// [GraphQL scalar][1].
     ///
@@ -790,6 +823,31 @@ impl Methods {
         }
     }
 
+    /// Expands [`resolve::InputValue::try_from_input_value()`][0] method.
+    ///
+    /// [0]: juniper::resolve::InputValue::try_from_input_value
+    fn expand_try_from_input_value(&self, scalar: &scalar::Type) -> TokenStream {
+        match self {
+            Self::Custom { from_input, .. }
+            | Self::Delegated {
+                from_input: Some(from_input),
+                ..
+            } => {
+                quote! { #from_input(input) }
+            }
+
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+                let self_constructor = field.closure_constructor();
+
+                quote! {
+                    <#field_ty as ::juniper::resolve::InputValue<'__inp, #scalar>>::try_from_input_value(input)
+                        .map(#self_constructor)
+                }
+            }
+        }
+    }
+
     /// Expands [`ParseScalarValue::from_str`] method.
     ///
     /// [`ParseScalarValue::from_str`]: juniper::ParseScalarValue::from_str

From 8ea231f395b210013e96802fee7f94fa9e5d5b71 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 19 May 2022 17:32:43 +0200
Subject: [PATCH 10/58] Building up codegen for scalars, vol.2

---
 juniper/src/types/str.rs                  |   8 +-
 juniper_codegen/src/common/scalar.rs      |   8 +-
 juniper_codegen/src/graphql_scalar/mod.rs | 191 ++++++++++++++++++++--
 3 files changed, 185 insertions(+), 22 deletions(-)

diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 4177f4da3..e4f3e1e35 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -25,9 +25,8 @@ impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
 }
 
 impl<Info: ?Sized> resolve::TypeName<Info> for str {
-    fn type_name(_: &Info) -> &'static str {
-        // TODO: Reuse from `String`.
-        "String"
+    fn type_name(info: &Info) -> &str {
+        <String as resolve::TypeName<Info>>::type_name(info)
     }
 }
 
@@ -69,8 +68,7 @@ where
 
 impl<S: ScalarValue> resolve::ScalarToken<S> for str {
     fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        // TODO: Replace with `resolve::ScalarToken<S>`
-        <String as crate::ParseScalarValue<S>>::from_str(token)
+        <String as resolve::ScalarToken<S>>::parse_scalar_token(token)
     }
 }
 
diff --git a/juniper_codegen/src/common/scalar.rs b/juniper_codegen/src/common/scalar.rs
index 8f11833de..103c3ac07 100644
--- a/juniper_codegen/src/common/scalar.rs
+++ b/juniper_codegen/src/common/scalar.rs
@@ -63,15 +63,17 @@ pub(crate) enum Type {
     /// [`ScalarValue`]: juniper::ScalarValue
     Concrete(syn::Type),
 
-    /// One of type parameters of the original type is specified as [`ScalarValue`].
+    /// One of type parameters of the original type is specified as
+    /// [`ScalarValue`].
     ///
     /// The original type is the type that the code is generated for.
     ///
     /// [`ScalarValue`]: juniper::ScalarValue
     ExplicitGeneric(syn::Ident),
 
-    /// [`ScalarValue`] parametrization is assumed to be generic and is not specified
-    /// explicitly, or specified as bound predicate (like `S: ScalarValue + Send + Sync`).
+    /// [`ScalarValue`] parametrization is assumed to be generic and is not
+    /// specified explicitly, or specified as bound predicate (like
+    /// `S: ScalarValue + Send + Sync`).
     ///
     /// [`ScalarValue`]: juniper::ScalarValue
     ImplicitGeneric(Option<syn::PredicateType>),
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index a0632b9e2..e76540566 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -331,7 +331,9 @@ impl ToTokens for Definition {
         self.impl_parse_scalar_value_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        self.impl_resolve_input_value_tokens().to_tokens(into);
+        self.impl_resolve_type_name().to_tokens(into);
+        self.impl_resolve_input_value().to_tokens(into);
+        self.impl_resolve_scalar_token().to_tokens(into);
     }
 }
 
@@ -406,6 +408,30 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::TypeName`] trait for this
+    /// [GraphQL scalar][1].
+    ///
+    /// [`resolve::TypeName`]: juniper::resolve::TypeName
+    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_type_name(&self) -> TokenStream {
+        let name = &self.name;
+
+        let (ty, generics) = self.ty_and_generics();
+        let (info_ty, generics) = self.mix_info_ty(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::TypeName<#info_ty> for #ty
+                #where_clause
+            {
+                fn type_name(_: &#info_ty) -> &'static str {
+                    #name
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLValue`] trait for this
     /// [GraphQL scalar][1].
     ///
@@ -531,27 +557,28 @@ impl Definition {
     ///
     /// [`resolve::InputValue`]: juniper::resolve::InputValue
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
-    fn impl_resolve_input_value_tokens(&self) -> TokenStream {
-        let scalar = &self.scalar;
+    fn impl_resolve_input_value(&self) -> TokenStream {
+        let conversion = self.methods.expand_try_from_input_value(&self.scalar);
 
-        let conversion = self.methods.expand_try_from_input_value(scalar);
-
-        let (ty, mut generics) = self.impl_self_and_generics(false);
-        generics.params.push(parse_quote! { '__inp });
+        let (ty, generics) = self.ty_and_generics();
+        let (scalar, mut generics) = self.mix_scalar_ty(generics);
+        let lt: syn::GenericParam = parse_quote! { '__inp };
+        generics.params.push(lt.clone());
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::InputValue<'__inp, #scalar> for #ty
+            impl#impl_gens ::juniper::resolve::InputValue<#lt, #scalar> for #ty
                 #where_clause
             {
                 type Error = ::juniper::FieldError<#scalar>;
 
                 fn try_from_input_value(
-                    input: &'__inp ::juniper::graphql::InputValue<#scalar>,
+                    input: &#lt ::juniper::graphql::InputValue<#scalar>,
                 ) -> Result<Self, Self::Error> {
-                    #conversion
-                        .map_err(::juniper::IntoFieldError::<#scalar>::into_field_error)
+                    #conversion.map_err(
+                        ::juniper::IntoFieldError::<#scalar>::into_field_error,
+                    )
                 }
             }
         }
@@ -584,6 +611,35 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::ScalarToken`] trait for
+    /// this [GraphQL scalar][1].
+    ///
+    /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
+    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_scalar_token(&self) -> TokenStream {
+        let body = self.methods.expand_parse_scalar_token(&self.scalar);
+
+        let (ty, generics) = self.ty_and_generics();
+        let (scalar, generics) = self.mix_scalar_ty(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::ScalarToken<#scalar> for #ty
+                #where_clause
+            {
+                fn parse_scalar_token(
+                    token: ::juniper::parser::ScalarToken<'_>,
+                ) -> ::std::result::Result<
+                    #scalar,
+                    ::juniper::parser::ParseError<'_>,
+                > {
+                    #body
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`BaseType`], [`BaseSubTypes`] and
     /// [`WrappedType`] traits for this [GraphQL scalar][1].
     ///
@@ -700,6 +756,57 @@ impl Definition {
 
         (ty, generics)
     }
+
+    #[must_use]
+    fn ty_and_generics(&self) -> (syn::Type, syn::Generics) {
+        let mut generics = self.generics.clone();
+
+        let ty = match &self.ty {
+            TypeOrIdent::Type(ty) => (**ty).clone(),
+            TypeOrIdent::Ident(ident) => {
+                let (_, ty_gen, _) = self.generics.split_for_impl();
+                parse_quote! { #ident#ty_gen }
+            }
+        };
+
+        if !self.where_clause.is_empty() {
+            generics
+                .make_where_clause()
+                .predicates
+                .extend(self.where_clause.clone())
+        }
+
+        (ty, generics)
+    }
+
+    #[must_use]
+    fn mix_info_ty(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let ty = parse_quote! { __Info };
+
+        generics.params.push(parse_quote! { #ty: ?Sized });
+
+        (ty, generics)
+    }
+
+    #[must_use]
+    fn mix_scalar_ty(&self, mut generics: syn::Generics) -> (&scalar::Type, syn::Generics) {
+        let scalar = &self.scalar;
+
+        if scalar.is_implicit_generic() {
+            generics.params.push(parse_quote! { #scalar });
+        }
+        if scalar.is_generic() {
+            generics
+                .make_where_clause()
+                .predicates
+                .push(parse_quote! { #scalar: ::juniper::ScalarValue });
+        }
+        if let Some(bound) = scalar.bounds() {
+            generics.make_where_clause().predicates.push(bound);
+        }
+
+        (scalar, generics)
+    }
 }
 
 /// Adds `__fa__` prefix to all lifetimes to avoid "lifetime name `'a` shadows a
@@ -823,7 +930,8 @@ impl Methods {
         }
     }
 
-    /// Expands [`resolve::InputValue::try_from_input_value()`][0] method.
+    /// Expands body of [`resolve::InputValue::try_from_input_value()`][0]
+    /// method.
     ///
     /// [0]: juniper::resolve::InputValue::try_from_input_value
     fn expand_try_from_input_value(&self, scalar: &scalar::Type) -> TokenStream {
@@ -841,8 +949,9 @@ impl Methods {
                 let self_constructor = field.closure_constructor();
 
                 quote! {
-                    <#field_ty as ::juniper::resolve::InputValue<'__inp, #scalar>>::try_from_input_value(input)
-                        .map(#self_constructor)
+                    <#field_ty as ::juniper::resolve::InputValue<'_, #scalar>>
+                        ::try_from_input_value(input)
+                            .map(#self_constructor)
                 }
             }
         }
@@ -869,6 +978,27 @@ impl Methods {
             }
         }
     }
+
+    /// Expands body of [`resolve::ScalarToken::parse_scalar_token()`][0]
+    /// method.
+    ///
+    /// [0]: resolve::ScalarToken::parse_scalar_token
+    fn expand_parse_scalar_token(&self, scalar: &scalar::Type) -> TokenStream {
+        match self {
+            Self::Custom { parse_token, .. }
+            | Self::Delegated {
+                parse_token: Some(parse_token),
+                ..
+            } => parse_token.expand_parse_scalar_token(scalar),
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+                quote! {
+                    <#field_ty as ::juniper::resolve::ScalarToken<#scalar>>
+                        ::parse_scalar_token(token)
+                }
+            }
+        }
+    }
 }
 
 /// Representation of [`ParseScalarValue::from_str`] method.
@@ -912,6 +1042,39 @@ impl ParseToken {
                 .unwrap_or_default(),
         }
     }
+
+    /// Expands body of [`resolve::ScalarToken::parse_scalar_token()`][0]
+    /// method.
+    ///
+    /// [0]: resolve::ScalarToken::parse_scalar_token
+    fn expand_parse_scalar_token(&self, scalar: &scalar::Type) -> TokenStream {
+        match self {
+            Self::Custom(parse_token) => {
+                quote! { #parse_token(token) }
+            }
+            Self::Delegated(delegated) => delegated
+                .iter()
+                .fold(None, |acc, ty| {
+                    acc.map_or_else(
+                        || {
+                            Some(quote! {
+                                <#ty as ::juniper::resolve::ScalarToken<#scalar>>
+                                    ::parse_scalar_token(token)
+                            })
+                        },
+                        |prev| {
+                            Some(quote! {
+                                #prev.or_else(|_| {
+                                    <#ty as ::juniper::resolve::ScalarToken<#scalar>>
+                                        ::parse_scalar_token(token)
+                                })
+                            })
+                        },
+                    )
+                })
+                .unwrap_or_default(),
+        }
+    }
 }
 
 /// Struct field to resolve not provided methods.

From b381c696ffc5c530c75c7d8f13a4dcd60d86ec85 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Fri, 27 May 2022 18:11:40 +0200
Subject: [PATCH 11/58] Improve and polish codegen for scalars

---
 juniper/src/types/str.rs                  |   5 +-
 juniper_codegen/src/graphql_scalar/mod.rs | 216 +++++++++++++++++++---
 2 files changed, 191 insertions(+), 30 deletions(-)

diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index e4f3e1e35..af7c966cb 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -66,7 +66,10 @@ where
     }
 }
 
-impl<S: ScalarValue> resolve::ScalarToken<S> for str {
+impl<S> resolve::ScalarToken<S> for str
+where
+    String: resolve::ScalarToken<S>,
+{
     fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
         <String as resolve::ScalarToken<S>>::parse_scalar_token(token)
     }
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index e76540566..45a342917 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -332,6 +332,7 @@ impl ToTokens for Definition {
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
         self.impl_resolve_type_name().to_tokens(into);
+        self.impl_resolve_type().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
     }
@@ -409,24 +410,71 @@ impl Definition {
     }
 
     /// Returns generated code implementing [`resolve::TypeName`] trait for this
-    /// [GraphQL scalar][1].
+    /// [GraphQL scalar][0].
     ///
     /// [`resolve::TypeName`]: juniper::resolve::TypeName
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_type_name(&self) -> TokenStream {
+        let (ty, generics) = self.ty_and_generics();
+        let (info, generics) = self.mix_info(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
         let name = &self.name;
 
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::TypeName<#info> for #ty
+                #where_clause
+            {
+                fn type_name(_: &#info) -> &'static str {
+                    #name
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`resolve::Type`] trait for this
+    /// [GraphQL scalar][0].
+    ///
+    /// [`resolve::Type`]: juniper::resolve::Type
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_type(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (info_ty, generics) = self.mix_info_ty(generics);
+        let (info, generics) = self.mix_info(generics);
+        let (scalar, mut generics) = self.mix_scalar(generics);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::resolve::TypeName<#info>
+                  + ::juniper::resolve::ScalarToken<#scalar>
+                  + ::juniper::resolve::InputValueOwned<#scalar>
+        });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
+        let description = self
+            .description
+            .as_ref()
+            .map(|val| quote! { .description(#val) });
+
+        let specified_by_url = self.specified_by_url.as_ref().map(|url| {
+            let url_lit = url.as_str();
+            quote! { .specified_by_url(#url_lit) }
+        });
+
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::TypeName<#info_ty> for #ty
+            impl#impl_gens ::juniper::resolve::Type<#info, #scalar> for #ty
                 #where_clause
             {
-                fn type_name(_: &#info_ty) -> &'static str {
-                    #name
+                fn meta<'r>(
+                    registry: &mut ::juniper::Registry<'r, #scalar>,
+                    info: &#info,
+                ) -> ::juniper::meta::MetaType<'r, #scalar>
+                where
+                    #scalar: 'r,
+                {
+                    registry.build_scalar_type_new::<Self, _>(info)
+                        #description
+                        #specified_by_url
+                        .into_meta()
                 }
             }
         }
@@ -553,19 +601,23 @@ impl Definition {
     }
 
     /// Returns generated code implementing [`resolve::InputValue`] trait for
-    /// this [GraphQL scalar][1].
+    /// this [GraphQL scalar][0].
     ///
     /// [`resolve::InputValue`]: juniper::resolve::InputValue
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_input_value(&self) -> TokenStream {
-        let conversion = self.methods.expand_try_from_input_value(&self.scalar);
-
         let (ty, generics) = self.ty_and_generics();
-        let (scalar, mut generics) = self.mix_scalar_ty(generics);
+        let (scalar, mut generics) = self.mix_scalar(generics);
         let lt: syn::GenericParam = parse_quote! { '__inp };
         generics.params.push(lt.clone());
+        generics
+            .make_where_clause()
+            .predicates
+            .push(self.methods.bound_try_from_input_value(scalar, &lt));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
+        let conversion = self.methods.expand_try_from_input_value(scalar);
+
         quote! {
             #[automatically_derived]
             impl#impl_gens ::juniper::resolve::InputValue<#lt, #scalar> for #ty
@@ -575,7 +627,7 @@ impl Definition {
 
                 fn try_from_input_value(
                     input: &#lt ::juniper::graphql::InputValue<#scalar>,
-                ) -> Result<Self, Self::Error> {
+                ) -> ::std::result::Result<Self, Self::Error> {
                     #conversion.map_err(
                         ::juniper::IntoFieldError::<#scalar>::into_field_error,
                     )
@@ -612,17 +664,21 @@ impl Definition {
     }
 
     /// Returns generated code implementing [`resolve::ScalarToken`] trait for
-    /// this [GraphQL scalar][1].
+    /// this [GraphQL scalar][0].
     ///
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_scalar_token(&self) -> TokenStream {
-        let body = self.methods.expand_parse_scalar_token(&self.scalar);
-
         let (ty, generics) = self.ty_and_generics();
-        let (scalar, generics) = self.mix_scalar_ty(generics);
+        let (scalar, mut generics) = self.mix_scalar(generics);
+        generics
+            .make_where_clause()
+            .predicates
+            .extend(self.methods.bound_parse_scalar_token(scalar));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
+        let body = self.methods.expand_parse_scalar_token(scalar);
+
         quote! {
             #[automatically_derived]
             impl#impl_gens ::juniper::resolve::ScalarToken<#scalar> for #ty
@@ -757,6 +813,8 @@ impl Definition {
         (ty, 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 mut generics = self.generics.clone();
@@ -779,8 +837,10 @@ impl Definition {
         (ty, generics)
     }
 
+    /// Mixes a type info [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`syn::Ident`].
     #[must_use]
-    fn mix_info_ty(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+    fn mix_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
         let ty = parse_quote! { __Info };
 
         generics.params.push(parse_quote! { #ty: ?Sized });
@@ -788,19 +848,32 @@ impl Definition {
         (ty, generics)
     }
 
+    /// Mixes a context [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`syn::Ident`].
     #[must_use]
-    fn mix_scalar_ty(&self, mut generics: syn::Generics) -> (&scalar::Type, syn::Generics) {
+    fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let ty = parse_quote! { __Ctx };
+
+        generics.params.push(parse_quote! { #ty: ?Sized });
+
+        (ty, generics)
+    }
+
+    /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`scalar::Type`].
+    ///
+    /// [`ScalarValue`] trait bound is not made here, because some trait
+    /// implementations may not require it depending on the generated code or
+    /// even at all.
+    ///
+    /// [`ScalarValue`]: juniper::ScalarValue
+    #[must_use]
+    fn mix_scalar(&self, mut generics: syn::Generics) -> (&scalar::Type, syn::Generics) {
         let scalar = &self.scalar;
 
         if scalar.is_implicit_generic() {
             generics.params.push(parse_quote! { #scalar });
         }
-        if scalar.is_generic() {
-            generics
-                .make_where_clause()
-                .predicates
-                .push(parse_quote! { #scalar: ::juniper::ScalarValue });
-        }
         if let Some(bound) = scalar.bounds() {
             generics.make_where_clause().predicates.push(bound);
         }
@@ -957,6 +1030,38 @@ impl Methods {
         }
     }
 
+    /// Generates additional trait bounds for [`resolve::InputValue`]
+    /// implementation allowing to execute
+    /// [`resolve::InputValue::try_from_input_value()`][0] method.
+    ///
+    /// [`resolve::InputValue`]: juniper::resolve::InputValue
+    /// [0]: juniper::resolve::InputValue::try_from_input_value
+    fn bound_try_from_input_value(
+        &self,
+        scalar: &scalar::Type,
+        lt: &syn::GenericParam,
+    ) -> syn::WherePredicate {
+        match self {
+            Self::Custom { .. }
+            | Self::Delegated {
+                from_input: Some(_),
+                ..
+            } => {
+                parse_quote! {
+                    #scalar: ::juniper::ScalarValue
+                }
+            }
+
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+
+                parse_quote! {
+                    #field_ty: ::juniper::resolve::InputValue<#lt, #scalar>
+                }
+            }
+        }
+    }
+
     /// Expands [`ParseScalarValue::from_str`] method.
     ///
     /// [`ParseScalarValue::from_str`]: juniper::ParseScalarValue::from_str
@@ -982,7 +1087,7 @@ impl Methods {
     /// Expands body of [`resolve::ScalarToken::parse_scalar_token()`][0]
     /// method.
     ///
-    /// [0]: resolve::ScalarToken::parse_scalar_token
+    /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
     fn expand_parse_scalar_token(&self, scalar: &scalar::Type) -> TokenStream {
         match self {
             Self::Custom { parse_token, .. }
@@ -990,8 +1095,10 @@ impl Methods {
                 parse_token: Some(parse_token),
                 ..
             } => parse_token.expand_parse_scalar_token(scalar),
+
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+
                 quote! {
                     <#field_ty as ::juniper::resolve::ScalarToken<#scalar>>
                         ::parse_scalar_token(token)
@@ -999,6 +1106,30 @@ impl Methods {
             }
         }
     }
+
+    /// Generates additional trait bounds for [`resolve::ScalarToken`]
+    /// implementation allowing to execute
+    /// [`resolve::ScalarToken::parse_scalar_token()`][0] method.
+    ///
+    /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
+    /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
+    fn bound_parse_scalar_token(&self, scalar: &scalar::Type) -> Vec<syn::WherePredicate> {
+        match self {
+            Self::Custom { parse_token, .. }
+            | Self::Delegated {
+                parse_token: Some(parse_token),
+                ..
+            } => parse_token.bound_parse_scalar_token(scalar),
+
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+
+                vec![parse_quote! {
+                    #field_ty: ::juniper::resolve::ScalarToken<#scalar>
+                }]
+            }
+        }
+    }
 }
 
 /// Representation of [`ParseScalarValue::from_str`] method.
@@ -1046,12 +1177,13 @@ impl ParseToken {
     /// Expands body of [`resolve::ScalarToken::parse_scalar_token()`][0]
     /// method.
     ///
-    /// [0]: resolve::ScalarToken::parse_scalar_token
+    /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
     fn expand_parse_scalar_token(&self, scalar: &scalar::Type) -> TokenStream {
         match self {
             Self::Custom(parse_token) => {
                 quote! { #parse_token(token) }
             }
+
             Self::Delegated(delegated) => delegated
                 .iter()
                 .fold(None, |acc, ty| {
@@ -1075,6 +1207,31 @@ impl ParseToken {
                 .unwrap_or_default(),
         }
     }
+
+    /// Generates additional trait bounds for [`resolve::ScalarToken`]
+    /// implementation allowing to execute
+    /// [`resolve::ScalarToken::parse_scalar_token()`][0] method.
+    ///
+    /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
+    /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
+    fn bound_parse_scalar_token(&self, scalar: &scalar::Type) -> Vec<syn::WherePredicate> {
+        match self {
+            Self::Custom(_) => {
+                vec![parse_quote! {
+                    #scalar: ::juniper::ScalarValue
+                }]
+            }
+
+            Self::Delegated(delegated) => delegated
+                .iter()
+                .map(|ty| {
+                    parse_quote! {
+                        #ty: ::juniper::resolve::ScalarToken<#scalar>
+                    }
+                })
+                .collect(),
+        }
+    }
 }
 
 /// Struct field to resolve not provided methods.
@@ -1103,9 +1260,10 @@ impl Field {
         }
     }
 
-    /// Closure to construct [GraphQL scalar][1] struct from [`Field`].
+    /// Generates closure to construct a [GraphQL scalar][0] struct from a
+    /// [`Field`] value.
     ///
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn closure_constructor(&self) -> TokenStream {
         match self {
             Field::Named(syn::Field { ident, .. }) => {

From b1be8f1d29cdfb640ef1bfd4e205ac4a7798382f Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 30 May 2022 19:09:15 +0200
Subject: [PATCH 12/58] Improve codegen for scalars, vol.2

---
 juniper/src/lib.rs                        |  1 +
 juniper/src/reflect/mod.rs                |  1 +
 juniper/src/types/scalars.rs              | 12 ---
 juniper/src/types/str.rs                  | 18 ++++-
 juniper_codegen/src/graphql_scalar/mod.rs | 93 ++++++++++++++++++-----
 5 files changed, 90 insertions(+), 35 deletions(-)
 create mode 100644 juniper/src/reflect/mod.rs

diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 6e35d2301..9340608a2 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -36,6 +36,7 @@ pub mod http;
 pub mod integrations;
 mod introspection;
 pub mod parser;
+pub mod reflect;
 pub mod resolve;
 pub(crate) mod schema;
 mod types;
diff --git a/juniper/src/reflect/mod.rs b/juniper/src/reflect/mod.rs
new file mode 100644
index 000000000..e91f009a8
--- /dev/null
+++ b/juniper/src/reflect/mod.rs
@@ -0,0 +1 @@
+pub use crate::macros::reflect::*;
diff --git a/juniper/src/types/scalars.rs b/juniper/src/types/scalars.rs
index 66e26e74f..ac7817705 100644
--- a/juniper/src/types/scalars.rs
+++ b/juniper/src/types/scalars.rs
@@ -196,18 +196,6 @@ where
     })
 }
 
-impl<S> reflect::WrappedType<S> for str {
-    const VALUE: reflect::WrappedValue = 1;
-}
-
-impl<S> reflect::BaseType<S> for str {
-    const NAME: reflect::Type = "String";
-}
-
-impl<S> reflect::BaseSubTypes<S> for str {
-    const NAMES: reflect::Types = &[<Self as reflect::BaseType<S>>::NAME];
-}
-
 impl<S> GraphQLType<S> for str
 where
     S: ScalarValue,
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index af7c966cb..24861e6bb 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -7,7 +7,7 @@ use std::{rc::Rc, sync::Arc};
 use futures::future;
 
 use crate::{
-    graphql,
+    graphql, reflect,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
     resolve, BoxFuture, ExecutionResult, Executor, Registry, ScalarValue, Selection,
@@ -25,8 +25,8 @@ impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
 }
 
 impl<Info: ?Sized> resolve::TypeName<Info> for str {
-    fn type_name(info: &Info) -> &str {
-        <String as resolve::TypeName<Info>>::type_name(info)
+    fn type_name(_: &Info) -> &'static str {
+        <Self as reflect::BaseType<()>>::NAME
     }
 }
 
@@ -119,3 +119,15 @@ impl<S> graphql::OutputType<S> for str {
 impl<S> graphql::Scalar<S> for str {
     fn assert_scalar() {}
 }
+
+impl<S> reflect::BaseType<S> for str {
+    const NAME: reflect::Type = <String as reflect::BaseType<S>>::NAME;
+}
+
+impl<S> reflect::BaseSubTypes<S> for str {
+    const NAMES: reflect::Types = &[<Self as reflect::BaseType<S>>::NAME];
+}
+
+impl<S> reflect::WrappedType<S> for str {
+    const VALUE: reflect::WrappedValue = 1;
+}
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 45a342917..7e98eae3f 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -329,12 +329,14 @@ impl ToTokens for Definition {
         self.impl_to_input_value_tokens().to_tokens(into);
         self.impl_from_input_value_tokens().to_tokens(into);
         self.impl_parse_scalar_value_tokens().to_tokens(into);
-        self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_type().to_tokens(into);
+        self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
+        self.impl_input_and_output_type().to_tokens(into);
+        //self.impl_scalar().to_tokens(into);
+        self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -363,6 +365,56 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`graphql::InputType`] and
+    /// [`graphql::OutputType`] traits for this [GraphQL scalar][0].
+    ///
+    /// [`graphql::InputType`]: juniper::graphql::InputType
+    /// [`graphql::OutputType`]: juniper::graphql::OutputType
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    #[must_use]
+    fn impl_input_and_output_type(&self) -> TokenStream {
+        let (ty, generics) = self.ty_and_generics();
+        let (scalar, generics) = self.mix_scalar(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::graphql::InputType<#scalar> for #ty
+                #where_clause
+            {
+                fn assert_input_type() {}
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::graphql::OutputType<#scalar> for #ty
+                #where_clause
+            {
+                fn assert_output_type() {}
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`graphql::Scalar`] trait for this
+    /// [GraphQL scalar][0].
+    ///
+    /// [`graphql::Scalar`]: juniper::graphql::Scalar
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    #[must_use]
+    fn impl_scalar(&self) -> TokenStream {
+        let (ty, generics) = self.ty_and_generics();
+        let (scalar, generics) = self.mix_scalar(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::graphql::Scalar<#scalar> for #ty
+                #where_clause
+            {
+                fn assert_scalar() {}
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLType`] trait for this
     /// [GraphQL scalar][1].
     ///
@@ -696,41 +748,42 @@ impl Definition {
         }
     }
 
-    /// Returns generated code implementing [`BaseType`], [`BaseSubTypes`] and
-    /// [`WrappedType`] traits for this [GraphQL scalar][1].
+    /// Returns generated code implementing [`reflect::BaseType`],
+    /// [`reflect::BaseSubTypes`] and [`reflect::WrappedType`] traits for this
+    /// [GraphQL scalar][0].
     ///
-    /// [`BaseSubTypes`]: juniper::macros::reflection::BaseSubTypes
-    /// [`BaseType`]: juniper::macros::reflection::BaseType
-    /// [`WrappedType`]: juniper::macros::reflection::WrappedType
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
-    fn impl_reflection_traits_tokens(&self) -> TokenStream {
-        let scalar = &self.scalar;
-        let name = &self.name;
-
-        let (ty, generics) = self.impl_self_and_generics(false);
+    /// [`reflect::BaseSubTypes`]: juniper::reflection::BaseSubTypes
+    /// [`reflect::BaseType`]: juniper::reflection::BaseType
+    /// [`reflect::WrappedType`]: juniper::reflection::WrappedType
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_reflect(&self) -> TokenStream {
+        let (ty, generics) = self.ty_and_generics();
+        let (scalar, generics) = self.mix_scalar(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
+        let name = &self.name;
+
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::macros::reflect::BaseType<#scalar> for #ty
+            impl#impl_gens ::juniper::reflect::BaseType<#scalar> for #ty
                 #where_clause
             {
-                const NAME: ::juniper::macros::reflect::Type = #name;
+                const NAME: ::juniper::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::macros::reflect::BaseSubTypes<#scalar> for #ty
+            impl#impl_gens ::juniper::reflect::BaseSubTypes<#scalar> for #ty
                 #where_clause
             {
-                const NAMES: ::juniper::macros::reflect::Types =
-                    &[<Self as ::juniper::macros::reflect::BaseType<#scalar>>::NAME];
+                const NAMES: ::juniper::reflect::Types =
+                    &[<Self as ::juniper::reflect::BaseType<#scalar>>::NAME];
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::macros::reflect::WrappedType<#scalar> for #ty
+            impl#impl_gens ::juniper::reflect::WrappedType<#scalar> for #ty
                 #where_clause
             {
-                const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
+                const VALUE: ::juniper::reflect::WrappedValue = 1;
             }
         }
     }

From 22f3f1887ea8f0e93c0a3f49768a7af751274e79 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 31 May 2022 00:29:14 +0200
Subject: [PATCH 13/58] Bikeshed reflection, vol.1

---
 juniper/src/macros/reflect.rs             | 126 ++--------------------
 juniper/src/types/arc.rs                  |  25 ++++-
 juniper/src/types/array.rs                |  23 +++-
 juniper/src/types/box.rs                  |  25 ++++-
 juniper/src/types/mod.rs                  |   1 +
 juniper/src/types/nullable.rs             |  25 ++++-
 juniper/src/types/option.rs               |  23 +++-
 juniper/src/types/rc.rs                   |  25 ++++-
 juniper/src/types/ref.rs                  |  25 ++++-
 juniper/src/types/ref_mut.rs              |  23 +++-
 juniper/src/types/result.rs               |  24 +++++
 juniper/src/types/slice.rs                |  23 +++-
 juniper/src/types/str.rs                  |   6 +-
 juniper/src/types/vec.rs                  |  23 +++-
 juniper_codegen/src/graphql_scalar/mod.rs |   7 +-
 15 files changed, 267 insertions(+), 137 deletions(-)
 create mode 100644 juniper/src/types/result.rs

diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs
index 4cba097f8..912a25241 100644
--- a/juniper/src/macros/reflect.rs
+++ b/juniper/src/macros/reflect.rs
@@ -44,10 +44,6 @@ pub trait BaseType<S> {
     const NAME: Type;
 }
 
-impl<'a, S, T: BaseType<S> + ?Sized> BaseType<S> for &'a T {
-    const NAME: Type = T::NAME;
-}
-
 impl<'ctx, S, T> BaseType<S> for (&'ctx T::Context, T)
 where
     S: ScalarValue,
@@ -56,42 +52,6 @@ where
     const NAME: Type = T::NAME;
 }
 
-impl<S, T: BaseType<S>> BaseType<S> for Option<T> {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S>> BaseType<S> for Nullable<T> {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S>, E> BaseType<S> for Result<T, E> {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S>> BaseType<S> for Vec<T> {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S>> BaseType<S> for [T] {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S>, const N: usize> BaseType<S> for [T; N] {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S> + ?Sized> BaseType<S> for Box<T> {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S> + ?Sized> BaseType<S> for Arc<T> {
-    const NAME: Type = T::NAME;
-}
-
-impl<S, T: BaseType<S> + ?Sized> BaseType<S> for Rc<T> {
-    const NAME: Type = T::NAME;
-}
-
 /// [Sub-types][2] of a [GraphQL object][1].
 ///
 /// This trait is transparent to [`Option`], [`Vec`] and other containers.
@@ -105,10 +65,6 @@ pub trait BaseSubTypes<S> {
     const NAMES: Types;
 }
 
-impl<'a, S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for &'a T {
-    const NAMES: Types = T::NAMES;
-}
-
 impl<'ctx, S, T> BaseSubTypes<S> for (&'ctx T::Context, T)
 where
     S: ScalarValue,
@@ -117,42 +73,6 @@ where
     const NAMES: Types = T::NAMES;
 }
 
-impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for Option<T> {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for Nullable<T> {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S>, E> BaseSubTypes<S> for Result<T, E> {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for Vec<T> {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for [T] {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S>, const N: usize> BaseSubTypes<S> for [T; N] {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for Box<T> {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for Arc<T> {
-    const NAMES: Types = T::NAMES;
-}
-
-impl<S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for Rc<T> {
-    const NAMES: Types = T::NAMES;
-}
-
 /// Alias for a value of a [`WrappedType`] (composed GraphQL type).
 pub type WrappedValue = u128;
 
@@ -163,7 +83,7 @@ pub type WrappedValue = u128;
 /// because of the [wrapping types][2]. To work around this we use a
 /// [`WrappedValue`] which is represented via [`u128`] number in the following
 /// encoding:
-/// - In base case of non-nullable [object][1] [`VALUE`] is `1`.
+/// - In base case of non-nullable singular [object][1] [`VALUE`] is `1`.
 /// - To represent nullability we "append" `2` to the [`VALUE`], so
 ///   [`Option`]`<`[object][1]`>` has [`VALUE`] of `12`.
 /// - To represent list we "append" `3` to the [`VALUE`], so
@@ -213,44 +133,18 @@ where
     const VALUE: u128 = T::VALUE;
 }
 
-impl<S, T: WrappedType<S>> WrappedType<S> for Option<T> {
-    const VALUE: u128 = T::VALUE * 10 + 2;
-}
+pub mod wrap {
+    use super::WrappedValue;
 
-impl<S, T: WrappedType<S>> WrappedType<S> for Nullable<T> {
-    const VALUE: u128 = T::VALUE * 10 + 2;
-}
+    pub const SINGULAR: WrappedValue = 1;
 
-impl<S, T: WrappedType<S>, E> WrappedType<S> for Result<T, E> {
-    const VALUE: u128 = T::VALUE;
-}
-
-impl<S, T: WrappedType<S>> WrappedType<S> for Vec<T> {
-    const VALUE: u128 = T::VALUE * 10 + 3;
-}
-
-impl<S, T: WrappedType<S>> WrappedType<S> for [T] {
-    const VALUE: u128 = T::VALUE * 10 + 3;
-}
-
-impl<S, T: WrappedType<S>, const N: usize> WrappedType<S> for [T; N] {
-    const VALUE: u128 = T::VALUE * 10 + 3;
-}
-
-impl<'a, S, T: WrappedType<S> + ?Sized> WrappedType<S> for &'a T {
-    const VALUE: u128 = T::VALUE;
-}
-
-impl<S, T: WrappedType<S> + ?Sized> WrappedType<S> for Box<T> {
-    const VALUE: u128 = T::VALUE;
-}
-
-impl<S, T: WrappedType<S> + ?Sized> WrappedType<S> for Arc<T> {
-    const VALUE: u128 = T::VALUE;
-}
+    pub const fn nullable(val: WrappedValue) -> WrappedValue {
+        val * 10 + 2
+    }
 
-impl<S, T: WrappedType<S> + ?Sized> WrappedType<S> for Rc<T> {
-    const VALUE: u128 = T::VALUE;
+    pub const fn list(val: WrappedValue) -> WrappedValue {
+        val * 10 + 3
+    }
 }
 
 /// Alias for a [GraphQL object][1] or [interface][2] [field argument][3] name.
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 6c9b8faf8..33804c3fe 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -6,8 +6,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
-    Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
+    IntoFieldError, Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Arc<T>
@@ -247,3 +247,24 @@ where
         T::assert_union()
     }
 }
+
+impl<T, S> reflect::BaseType<S> for Arc<T>
+where
+    T: reflect::BaseType<S> + ?Sized,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S> reflect::BaseSubTypes<S> for Arc<T>
+where
+    T: reflect::BaseSubTypes<S> + ?Sized,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S> reflect::WrappedType<S> for Arc<T>
+where
+    T: reflect::WrappedType<S> + ?Sized,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
index e018148da..4cd5856bb 100644
--- a/juniper/src/types/array.rs
+++ b/juniper/src/types/array.rs
@@ -4,7 +4,7 @@
 
 use crate::{
     executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
+    graphql, reflect, resolve,
     schema::meta::MetaType,
     BoxFuture, Selection,
 };
@@ -81,3 +81,24 @@ where
         T::assert_output_type()
     }
 }
+
+impl<T, S, const N: usize> reflect::BaseType<S> for [T; N]
+where
+    T: reflect::BaseType<S>,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S, const N: usize> reflect::BaseSubTypes<S> for [T; N]
+where
+    T: reflect::BaseSubTypes<S>,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S, const N: usize> reflect::WrappedType<S> for [T; N]
+where
+    T: reflect::WrappedType<S>,
+{
+    const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
+}
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 337d15403..1237ed6ea 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -4,8 +4,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
-    Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
+    IntoFieldError, Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Box<T>
@@ -245,3 +245,24 @@ where
         T::assert_union()
     }
 }
+
+impl<T, S> reflect::BaseType<S> for Box<T>
+where
+    T: reflect::BaseType<S> + ?Sized,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S> reflect::BaseSubTypes<S> for Box<T>
+where
+    T: reflect::BaseSubTypes<S> + ?Sized,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S> reflect::WrappedType<S> for Box<T>
+where
+    T: reflect::WrappedType<S> + ?Sized,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 58dfde7cb..5e529d61a 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -7,6 +7,7 @@ mod option;
 pub mod rc;
 pub mod r#ref;
 mod ref_mut;
+mod result;
 mod slice;
 mod r#str;
 mod vec;
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index eb1ee10cb..4113ea812 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -7,7 +7,7 @@ use futures::future;
 use crate::{
     ast::{FromInputValue, InputValue, ToInputValue},
     executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
+    graphql, reflect, resolve,
     schema::meta::MetaType,
     types::{
         async_await::GraphQLValueAsync,
@@ -361,6 +361,29 @@ where
     }
 }
 
+impl<T, S> reflect::BaseType<S> for Nullable<T>
+where
+    T: reflect::BaseType<S>,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S> reflect::BaseSubTypes<S> for Nullable<T>
+where
+    T: reflect::BaseSubTypes<S>,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S> reflect::WrappedType<S> for Nullable<T>
+where
+    T: reflect::WrappedType<S>,
+{
+    const VALUE: reflect::WrappedValue = reflect::wrap::nullable(T::VALUE);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 impl<S, T> GraphQLType<S> for Nullable<T>
 where
     T: GraphQLType<S>,
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index ec3f06492..75320f82f 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -4,7 +4,7 @@ use futures::future;
 
 use crate::{
     executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
+    graphql, reflect, resolve,
     schema::meta::MetaType,
     BoxFuture, Selection,
 };
@@ -93,3 +93,24 @@ where
         T::assert_output_type()
     }
 }
+
+impl<T, S> reflect::BaseType<S> for Option<T>
+where
+    T: reflect::BaseType<S>,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S> reflect::BaseSubTypes<S> for Option<T>
+where
+    T: reflect::BaseSubTypes<S>,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S> reflect::WrappedType<S> for Option<T>
+where
+    T: reflect::WrappedType<S>,
+{
+    const VALUE: reflect::WrappedValue = reflect::wrap::nullable(T::VALUE);
+}
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 8bae30537..515290b12 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -6,8 +6,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
-    Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
+    IntoFieldError, Registry, Selection,
 };
 
 impl<T, Info, S> resolve::Type<Info, S> for Rc<T>
@@ -247,3 +247,24 @@ where
         T::assert_union()
     }
 }
+
+impl<T, S> reflect::BaseType<S> for Rc<T>
+where
+    T: reflect::BaseType<S> + ?Sized,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S> reflect::BaseSubTypes<S> for Rc<T>
+where
+    T: reflect::BaseSubTypes<S> + ?Sized,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S> reflect::WrappedType<S> for Rc<T>
+where
+    T: reflect::WrappedType<S> + ?Sized,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 83d33ac1b..646b45661 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -6,8 +6,8 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError,
-    Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
+    IntoFieldError, Registry, Selection,
 };
 
 impl<'me, T, Info, S> resolve::Type<Info, S> for &'me T
@@ -233,3 +233,24 @@ where
         T::assert_union()
     }
 }
+
+impl<'me, T, S> reflect::BaseType<S> for &'me T
+where
+    T: reflect::BaseType<S> + ?Sized,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<'me, T, S> reflect::BaseSubTypes<S> for &'me T
+where
+    T: reflect::BaseSubTypes<S> + ?Sized,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<'me, T, S> reflect::WrappedType<S> for &'me T
+where
+    T: reflect::WrappedType<S> + ?Sized,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index a9418a0f7..36a576d72 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -6,7 +6,7 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
 impl<'me, T, Info, S> resolve::Type<Info, S> for &'me mut T
@@ -204,3 +204,24 @@ where
         T::assert_union()
     }
 }
+
+impl<'me, T, S> reflect::BaseType<S> for &'me mut T
+where
+    T: reflect::BaseType<S> + ?Sized,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<'me, T, S> reflect::BaseSubTypes<S> for &'me mut T
+where
+    T: reflect::BaseSubTypes<S> + ?Sized,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<'me, T, S> reflect::WrappedType<S> for &'me mut T
+where
+    T: reflect::WrappedType<S> + ?Sized,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
diff --git a/juniper/src/types/result.rs b/juniper/src/types/result.rs
new file mode 100644
index 000000000..1077f979c
--- /dev/null
+++ b/juniper/src/types/result.rs
@@ -0,0 +1,24 @@
+//! GraphQL implementation for [`Result`].
+
+use crate::reflect;
+
+impl<T, E, S> reflect::BaseType<S> for Result<T, E>
+where
+    T: reflect::BaseType<S>,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, E, S> reflect::BaseSubTypes<S> for Result<T, E>
+where
+    T: reflect::BaseSubTypes<S>,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, E, S> reflect::WrappedType<S> for Result<T, E>
+where
+    T: reflect::WrappedType<S>,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
diff --git a/juniper/src/types/slice.rs b/juniper/src/types/slice.rs
index e3ad5b49a..5a5b6b52b 100644
--- a/juniper/src/types/slice.rs
+++ b/juniper/src/types/slice.rs
@@ -4,7 +4,7 @@
 
 use crate::{
     executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
+    graphql, reflect, resolve,
     schema::meta::MetaType,
     BoxFuture, Selection,
 };
@@ -79,3 +79,24 @@ where
         T::assert_output_type()
     }
 }
+
+impl<T, S> reflect::BaseType<S> for [T]
+where
+    T: reflect::BaseType<S>,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S> reflect::BaseSubTypes<S> for [T]
+where
+    T: reflect::BaseSubTypes<S>,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S> reflect::WrappedType<S> for [T]
+where
+    T: reflect::WrappedType<S>,
+{
+    const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
+}
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 24861e6bb..b8f269851 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -7,10 +7,10 @@ use std::{rc::Rc, sync::Arc};
 use futures::future;
 
 use crate::{
-    graphql, reflect,
+    graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, BoxFuture, ExecutionResult, Executor, Registry, ScalarValue, Selection,
+    reflect, resolve, BoxFuture, ExecutionResult, Executor, Registry, ScalarValue, Selection,
 };
 
 impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
@@ -129,5 +129,5 @@ impl<S> reflect::BaseSubTypes<S> for str {
 }
 
 impl<S> reflect::WrappedType<S> for str {
-    const VALUE: reflect::WrappedValue = 1;
+    const VALUE: reflect::WrappedValue = reflect::wrap::SINGULAR;
 }
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
index a085f90ff..8a96f5ad7 100644
--- a/juniper/src/types/vec.rs
+++ b/juniper/src/types/vec.rs
@@ -2,7 +2,7 @@
 
 use crate::{
     executor::{ExecutionResult, Executor, Registry},
-    graphql, resolve,
+    graphql, reflect, resolve,
     schema::meta::MetaType,
     BoxFuture, Selection,
 };
@@ -77,3 +77,24 @@ where
         T::assert_output_type()
     }
 }
+
+impl<T, S> reflect::BaseType<S> for Vec<T>
+where
+    T: reflect::BaseType<S>,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, S> reflect::BaseSubTypes<S> for Vec<T>
+where
+    T: reflect::BaseSubTypes<S>,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, S> reflect::WrappedType<S> for Vec<T>
+where
+    T: reflect::WrappedType<S>,
+{
+    const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
+}
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 7e98eae3f..d094b3d13 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -471,15 +471,13 @@ impl Definition {
         let (info, generics) = self.mix_info(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let name = &self.name;
-
         quote! {
             #[automatically_derived]
             impl#impl_gens ::juniper::resolve::TypeName<#info> for #ty
                 #where_clause
             {
                 fn type_name(_: &#info) -> &'static str {
-                    #name
+                    <Self as ::juniper::reflect::BaseType<()>>::NAME
                 }
             }
         }
@@ -783,7 +781,8 @@ impl Definition {
             impl#impl_gens ::juniper::reflect::WrappedType<#scalar> for #ty
                 #where_clause
             {
-                const VALUE: ::juniper::reflect::WrappedValue = 1;
+                const VALUE: ::juniper::reflect::WrappedValue =
+                    ::juniper::reflect::wrap::SINGULAR;
             }
         }
     }

From 113b112daf83e0d9090347885280efc6fc501e2f Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 31 May 2022 19:08:36 +0200
Subject: [PATCH 14/58] Impl codegen for scalars (`resolve::Value` trait),
 vol.3

---
 juniper/src/macros/reflect.rs             |   2 -
 juniper/src/types/scalars.rs              |   1 -
 juniper_codegen/src/graphql_scalar/mod.rs | 107 ++++++++++++++++++++--
 3 files changed, 100 insertions(+), 10 deletions(-)

diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs
index 912a25241..f40a8c7d8 100644
--- a/juniper/src/macros/reflect.rs
+++ b/juniper/src/macros/reflect.rs
@@ -1,7 +1,5 @@
 //! Compile-time reflection of Rust types into GraphQL types.
 
-use std::{rc::Rc, sync::Arc};
-
 use futures::future::BoxFuture;
 
 use crate::{
diff --git a/juniper/src/types/scalars.rs b/juniper/src/types/scalars.rs
index ac7817705..0f8bb4089 100644
--- a/juniper/src/types/scalars.rs
+++ b/juniper/src/types/scalars.rs
@@ -8,7 +8,6 @@ use crate::{
     ast::{InputValue, Selection, ToInputValue},
     executor::{ExecutionResult, Executor, Registry},
     graphql_scalar,
-    macros::reflect,
     parser::{LexerError, ParseError, ScalarToken, Token},
     schema::meta::MetaType,
     types::{
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index d094b3d13..d85069c70 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -332,6 +332,7 @@ impl ToTokens for Definition {
         ////////////////////////////////////////////////////////////////////////
         self.impl_resolve_type().to_tokens(into);
         self.impl_resolve_type_name().to_tokens(into);
+        self.impl_resolve_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
         self.impl_input_and_output_type().to_tokens(into);
@@ -468,15 +469,15 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_type_name(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (info, generics) = self.mix_info(generics);
+        let (inf, generics) = self.mix_info(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::TypeName<#info> for #ty
+            impl#impl_gens ::juniper::resolve::TypeName<#inf> for #ty
                 #where_clause
             {
-                fn type_name(_: &#info) -> &'static str {
+                fn type_name(_: &#inf) -> &'static str {
                     <Self as ::juniper::reflect::BaseType<()>>::NAME
                 }
             }
@@ -490,10 +491,10 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_type(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (info, generics) = self.mix_info(generics);
+        let (inf, generics) = self.mix_info(generics);
         let (scalar, mut generics) = self.mix_scalar(generics);
         generics.make_where_clause().predicates.push(parse_quote! {
-            Self: ::juniper::resolve::TypeName<#info>
+            Self: ::juniper::resolve::TypeName<#inf>
                   + ::juniper::resolve::ScalarToken<#scalar>
                   + ::juniper::resolve::InputValueOwned<#scalar>
         });
@@ -511,12 +512,12 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Type<#info, #scalar> for #ty
+            impl#impl_gens ::juniper::resolve::Type<#inf, #scalar> for #ty
                 #where_clause
             {
                 fn meta<'r>(
                     registry: &mut ::juniper::Registry<'r, #scalar>,
-                    info: &#info,
+                    info: &#inf,
                 ) -> ::juniper::meta::MetaType<'r, #scalar>
                 where
                     #scalar: 'r,
@@ -567,6 +568,41 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::Value`] trait for this
+    /// [GraphQL scalar][0].
+    ///
+    /// [`resolve::Value`]: juniper::resolve::Value
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_value(&self) -> TokenStream {
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (scalar, mut generics) = self.mix_scalar(generics);
+        generics
+            .make_where_clause()
+            .predicates
+            .push(self.methods.bound_resolve_value(&inf, &cx, scalar));
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let body = self.methods.expand_resolve_value(scalar);
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #scalar> for #ty
+                #where_clause
+            {
+                fn resolve_value(
+                    &self,
+                    selection: Option<&[::juniper::Selection<'_, #scalar>]>,
+                    info: &#inf,
+                    executor: &::juniper::Executor<'_, '_, #cx, #scalar>,
+                ) -> ::juniper::ExecutionResult<#scalar> {
+                    #body
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLValueAsync`] trait for this
     /// [GraphQL scalar][1].
     ///
@@ -1009,6 +1045,63 @@ impl Methods {
         }
     }
 
+    /// Expands [`resolve::Value::resolve_value()`][0] method.
+    ///
+    /// [0]: juniper::resolve::Value::resolve_value
+    fn expand_resolve_value(&self, scalar: &scalar::Type) -> TokenStream {
+        match self {
+            Self::Custom { to_output, .. }
+            | Self::Delegated {
+                to_output: Some(to_output),
+                ..
+            } => {
+                quote! { Ok(#to_output(self)) }
+            }
+
+            Self::Delegated { field, .. } => {
+                quote! {
+                    ::juniper::resolve::Value::<#scalar>::resolve_value(
+                        &self.#field,
+                        info,
+                        selection,
+                        executor,
+                    )
+                }
+            }
+        }
+    }
+
+    /// Generates additional trait bounds for [`resolve::Value`] implementation
+    /// allowing to execute [`resolve::Value::resolve_value()`][0] method.
+    ///
+    /// [`resolve::Value`]: juniper::resolve::Value
+    /// [0]: juniper::resolve::Value::resolve_value
+    fn bound_resolve_value(
+        &self,
+        inf: &syn::Ident,
+        cx: &syn::Ident,
+        scalar: &scalar::Type,
+    ) -> syn::WherePredicate {
+        match self {
+            Self::Custom { .. }
+            | Self::Delegated {
+                to_output: Some(_), ..
+            } => {
+                parse_quote! {
+                    #scalar: ::juniper::ScalarValue
+                }
+            }
+
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+
+                parse_quote! {
+                    #field_ty: ::juniper::resolve::Value<#inf, #cx, #scalar>
+                }
+            }
+        }
+    }
+
     /// Expands [`ToInputValue::to_input_value`] method.
     ///
     /// [`ToInputValue::to_input_value`]: juniper::ToInputValue::to_input_value

From 740aa9061e112e909dc1e4579b304f95e026f6b3 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Wed, 1 Jun 2022 16:20:19 +0200
Subject: [PATCH 15/58] Impl codegen for scalars (`resolve::ValueAsync` trait),
 vol.4

---
 juniper_codegen/src/graphql_scalar/mod.rs | 185 ++++++++++++++--------
 1 file changed, 116 insertions(+), 69 deletions(-)

diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index d85069c70..17508bc0a 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -333,6 +333,7 @@ impl ToTokens for Definition {
         self.impl_resolve_type().to_tokens(into);
         self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_value().to_tokens(into);
+        self.impl_resolve_value_async().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
         self.impl_input_and_output_type().to_tokens(into);
@@ -375,19 +376,19 @@ impl Definition {
     #[must_use]
     fn impl_input_and_output_type(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (scalar, generics) = self.mix_scalar(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::InputType<#scalar> for #ty
+            impl#impl_gens ::juniper::graphql::InputType<#sv> for #ty
                 #where_clause
             {
                 fn assert_input_type() {}
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::OutputType<#scalar> for #ty
+            impl#impl_gens ::juniper::graphql::OutputType<#sv> for #ty
                 #where_clause
             {
                 fn assert_output_type() {}
@@ -403,12 +404,12 @@ impl Definition {
     #[must_use]
     fn impl_scalar(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (scalar, generics) = self.mix_scalar(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::Scalar<#scalar> for #ty
+            impl#impl_gens ::juniper::graphql::Scalar<#sv> for #ty
                 #where_clause
             {
                 fn assert_scalar() {}
@@ -469,7 +470,7 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_type_name(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_info(generics);
+        let (inf, generics) = self.mix_type_info(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
@@ -491,12 +492,12 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_type(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_info(generics);
-        let (scalar, mut generics) = self.mix_scalar(generics);
+        let (inf, generics) = self.mix_type_info(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::resolve::TypeName<#inf>
-                  + ::juniper::resolve::ScalarToken<#scalar>
-                  + ::juniper::resolve::InputValueOwned<#scalar>
+                  + ::juniper::resolve::ScalarToken<#sv>
+                  + ::juniper::resolve::InputValueOwned<#sv>
         });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
@@ -512,15 +513,15 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Type<#inf, #scalar> for #ty
+            impl#impl_gens ::juniper::resolve::Type<#inf, #sv> for #ty
                 #where_clause
             {
-                fn meta<'r>(
-                    registry: &mut ::juniper::Registry<'r, #scalar>,
+                fn meta<'__r>(
+                    registry: &mut ::juniper::Registry<'__r, #sv>,
                     info: &#inf,
-                ) -> ::juniper::meta::MetaType<'r, #scalar>
+                ) -> ::juniper::meta::MetaType<'__r, #sv>
                 where
-                    #scalar: 'r,
+                    #sv: '__r,
                 {
                     registry.build_scalar_type_new::<Self, _>(info)
                         #description
@@ -575,28 +576,28 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_value(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_info(generics);
+        let (inf, generics) = self.mix_type_info(generics);
         let (cx, generics) = self.mix_context(generics);
-        let (scalar, mut generics) = self.mix_scalar(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
         generics
             .make_where_clause()
             .predicates
-            .push(self.methods.bound_resolve_value(&inf, &cx, scalar));
+            .push(self.methods.bound_resolve_value(&inf, &cx, sv));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let body = self.methods.expand_resolve_value(scalar);
+        let body = self.methods.expand_resolve_value(&inf, &cx, sv);
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #scalar> for #ty
+            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #sv> for #ty
                 #where_clause
             {
                 fn resolve_value(
                     &self,
-                    selection: Option<&[::juniper::Selection<'_, #scalar>]>,
+                    selection: Option<&[::juniper::Selection<'_, #sv>]>,
                     info: &#inf,
-                    executor: &::juniper::Executor<'_, '_, #cx, #scalar>,
-                ) -> ::juniper::ExecutionResult<#scalar> {
+                    executor: &::juniper::Executor<'_, '_, #cx, #sv>,
+                ) -> ::juniper::ExecutionResult<#sv> {
                     #body
                 }
             }
@@ -633,6 +634,44 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::ValueAsync`] trait for
+    /// this [GraphQL scalar][0].
+    ///
+    /// [`resolve::ValueAsync`]: juniper::resolve::ValueAsync
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_value_async(&self) -> TokenStream {
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let preds = &mut generics.make_where_clause().predicates;
+        preds.push(parse_quote! {
+            Self: ::juniper::resolve::Value<#inf, #cx, #sv>
+        });
+        preds.push(parse_quote! {
+            #sv: Send
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv> for #ty
+                #where_clause
+            {
+                fn resolve_value_async<'__r>(
+                    &'__r self,
+                    selection: Option<&'__r [::juniper::Selection<'_, #sv>]>,
+                    info: &'__r #inf,
+                    executor: &'__r ::juniper::Executor<'_, '_, #cx, #sv>,
+                ) -> ::juniper::BoxFuture<'__r, ::juniper::ExecutionResult<#sv>> {
+                    let v = <Self as ::juniper::resolve::Value<#inf, #cx, #sv>>
+                        ::resolve_value(self, selection, info, executor);
+                    ::std::boxed::Box::pin(::juniper::futures::future::ready(v))
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`InputValue`] trait for this
     /// [GraphQL scalar][1].
     ///
@@ -693,29 +732,29 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_input_value(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (scalar, mut generics) = self.mix_scalar(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
         let lt: syn::GenericParam = parse_quote! { '__inp };
         generics.params.push(lt.clone());
         generics
             .make_where_clause()
             .predicates
-            .push(self.methods.bound_try_from_input_value(scalar, &lt));
+            .push(self.methods.bound_try_from_input_value(sv, &lt));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let conversion = self.methods.expand_try_from_input_value(scalar);
+        let conversion = self.methods.expand_try_from_input_value(sv);
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::InputValue<#lt, #scalar> for #ty
+            impl#impl_gens ::juniper::resolve::InputValue<#lt, #sv> for #ty
                 #where_clause
             {
-                type Error = ::juniper::FieldError<#scalar>;
+                type Error = ::juniper::FieldError<#sv>;
 
                 fn try_from_input_value(
-                    input: &#lt ::juniper::graphql::InputValue<#scalar>,
+                    input: &#lt ::juniper::graphql::InputValue<#sv>,
                 ) -> ::std::result::Result<Self, Self::Error> {
                     #conversion.map_err(
-                        ::juniper::IntoFieldError::<#scalar>::into_field_error,
+                        ::juniper::IntoFieldError::<#sv>::into_field_error,
                     )
                 }
             }
@@ -756,24 +795,24 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_scalar_token(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (scalar, mut generics) = self.mix_scalar(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
         generics
             .make_where_clause()
             .predicates
-            .extend(self.methods.bound_parse_scalar_token(scalar));
+            .extend(self.methods.bound_parse_scalar_token(sv));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let body = self.methods.expand_parse_scalar_token(scalar);
+        let body = self.methods.expand_parse_scalar_token(sv);
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ScalarToken<#scalar> for #ty
+            impl#impl_gens ::juniper::resolve::ScalarToken<#sv> for #ty
                 #where_clause
             {
                 fn parse_scalar_token(
                     token: ::juniper::parser::ScalarToken<'_>,
                 ) -> ::std::result::Result<
-                    #scalar,
+                    #sv,
                     ::juniper::parser::ParseError<'_>,
                 > {
                     #body
@@ -792,29 +831,29 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_reflect(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
-        let (scalar, generics) = self.mix_scalar(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         let name = &self.name;
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseType<#scalar> for #ty
+            impl#impl_gens ::juniper::reflect::BaseType<#sv> for #ty
                 #where_clause
             {
                 const NAME: ::juniper::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseSubTypes<#scalar> for #ty
+            impl#impl_gens ::juniper::reflect::BaseSubTypes<#sv> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
-                    &[<Self as ::juniper::reflect::BaseType<#scalar>>::NAME];
+                    &[<Self as ::juniper::reflect::BaseType<#sv>>::NAME];
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::WrappedType<#scalar> for #ty
+            impl#impl_gens ::juniper::reflect::WrappedType<#sv> for #ty
                 #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
@@ -928,7 +967,7 @@ impl Definition {
     /// Mixes a type info [`syn::GenericParam`] into the provided
     /// [`syn::Generics`] and returns its [`syn::Ident`].
     #[must_use]
-    fn mix_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
         let ty = parse_quote! { __Info };
 
         generics.params.push(parse_quote! { #ty: ?Sized });
@@ -956,7 +995,7 @@ impl Definition {
     ///
     /// [`ScalarValue`]: juniper::ScalarValue
     #[must_use]
-    fn mix_scalar(&self, mut generics: syn::Generics) -> (&scalar::Type, syn::Generics) {
+    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (&scalar::Type, syn::Generics) {
         let scalar = &self.scalar;
 
         if scalar.is_implicit_generic() {
@@ -1048,7 +1087,12 @@ impl Methods {
     /// Expands [`resolve::Value::resolve_value()`][0] method.
     ///
     /// [0]: juniper::resolve::Value::resolve_value
-    fn expand_resolve_value(&self, scalar: &scalar::Type) -> TokenStream {
+    fn expand_resolve_value(
+        &self,
+        inf: &syn::Ident,
+        cx: &syn::Ident,
+        sv: &scalar::Type,
+    ) -> TokenStream {
         match self {
             Self::Custom { to_output, .. }
             | Self::Delegated {
@@ -1059,13 +1103,16 @@ impl Methods {
             }
 
             Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+
                 quote! {
-                    ::juniper::resolve::Value::<#scalar>::resolve_value(
-                        &self.#field,
-                        info,
-                        selection,
-                        executor,
-                    )
+                    <#field_ty as ::juniper::resolve::Value<#inf, #cx, #sv>>
+                        ::resolve_value(
+                            &self.#field,
+                            info,
+                            selection,
+                            executor,
+                        )
                 }
             }
         }
@@ -1080,7 +1127,7 @@ impl Methods {
         &self,
         inf: &syn::Ident,
         cx: &syn::Ident,
-        scalar: &scalar::Type,
+        sv: &scalar::Type,
     ) -> syn::WherePredicate {
         match self {
             Self::Custom { .. }
@@ -1088,7 +1135,7 @@ impl Methods {
                 to_output: Some(_), ..
             } => {
                 parse_quote! {
-                    #scalar: ::juniper::ScalarValue
+                    #sv: ::juniper::ScalarValue
                 }
             }
 
@@ -1096,7 +1143,7 @@ impl Methods {
                 let field_ty = field.ty();
 
                 parse_quote! {
-                    #field_ty: ::juniper::resolve::Value<#inf, #cx, #scalar>
+                    #field_ty: ::juniper::resolve::Value<#inf, #cx, #sv>
                 }
             }
         }
@@ -1152,7 +1199,7 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::InputValue::try_from_input_value
-    fn expand_try_from_input_value(&self, scalar: &scalar::Type) -> TokenStream {
+    fn expand_try_from_input_value(&self, sv: &scalar::Type) -> TokenStream {
         match self {
             Self::Custom { from_input, .. }
             | Self::Delegated {
@@ -1167,7 +1214,7 @@ impl Methods {
                 let self_constructor = field.closure_constructor();
 
                 quote! {
-                    <#field_ty as ::juniper::resolve::InputValue<'_, #scalar>>
+                    <#field_ty as ::juniper::resolve::InputValue<'_, #sv>>
                         ::try_from_input_value(input)
                             .map(#self_constructor)
                 }
@@ -1183,7 +1230,7 @@ impl Methods {
     /// [0]: juniper::resolve::InputValue::try_from_input_value
     fn bound_try_from_input_value(
         &self,
-        scalar: &scalar::Type,
+        sv: &scalar::Type,
         lt: &syn::GenericParam,
     ) -> syn::WherePredicate {
         match self {
@@ -1193,7 +1240,7 @@ impl Methods {
                 ..
             } => {
                 parse_quote! {
-                    #scalar: ::juniper::ScalarValue
+                    #sv: ::juniper::ScalarValue
                 }
             }
 
@@ -1201,7 +1248,7 @@ impl Methods {
                 let field_ty = field.ty();
 
                 parse_quote! {
-                    #field_ty: ::juniper::resolve::InputValue<#lt, #scalar>
+                    #field_ty: ::juniper::resolve::InputValue<#lt, #sv>
                 }
             }
         }
@@ -1233,19 +1280,19 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, scalar: &scalar::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &scalar::Type) -> TokenStream {
         match self {
             Self::Custom { parse_token, .. }
             | Self::Delegated {
                 parse_token: Some(parse_token),
                 ..
-            } => parse_token.expand_parse_scalar_token(scalar),
+            } => parse_token.expand_parse_scalar_token(sv),
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
 
                 quote! {
-                    <#field_ty as ::juniper::resolve::ScalarToken<#scalar>>
+                    <#field_ty as ::juniper::resolve::ScalarToken<#sv>>
                         ::parse_scalar_token(token)
                 }
             }
@@ -1258,19 +1305,19 @@ impl Methods {
     ///
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn bound_parse_scalar_token(&self, scalar: &scalar::Type) -> Vec<syn::WherePredicate> {
+    fn bound_parse_scalar_token(&self, sv: &scalar::Type) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom { parse_token, .. }
             | Self::Delegated {
                 parse_token: Some(parse_token),
                 ..
-            } => parse_token.bound_parse_scalar_token(scalar),
+            } => parse_token.bound_parse_scalar_token(sv),
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
 
                 vec![parse_quote! {
-                    #field_ty: ::juniper::resolve::ScalarToken<#scalar>
+                    #field_ty: ::juniper::resolve::ScalarToken<#sv>
                 }]
             }
         }
@@ -1323,7 +1370,7 @@ impl ParseToken {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, scalar: &scalar::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &scalar::Type) -> TokenStream {
         match self {
             Self::Custom(parse_token) => {
                 quote! { #parse_token(token) }
@@ -1335,14 +1382,14 @@ impl ParseToken {
                     acc.map_or_else(
                         || {
                             Some(quote! {
-                                <#ty as ::juniper::resolve::ScalarToken<#scalar>>
+                                <#ty as ::juniper::resolve::ScalarToken<#sv>>
                                     ::parse_scalar_token(token)
                             })
                         },
                         |prev| {
                             Some(quote! {
                                 #prev.or_else(|_| {
-                                    <#ty as ::juniper::resolve::ScalarToken<#scalar>>
+                                    <#ty as ::juniper::resolve::ScalarToken<#sv>>
                                         ::parse_scalar_token(token)
                                 })
                             })
@@ -1359,11 +1406,11 @@ impl ParseToken {
     ///
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn bound_parse_scalar_token(&self, scalar: &scalar::Type) -> Vec<syn::WherePredicate> {
+    fn bound_parse_scalar_token(&self, sv: &scalar::Type) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom(_) => {
                 vec![parse_quote! {
-                    #scalar: ::juniper::ScalarValue
+                    #sv: ::juniper::ScalarValue
                 }]
             }
 
@@ -1371,7 +1418,7 @@ impl ParseToken {
                 .iter()
                 .map(|ty| {
                     parse_quote! {
-                        #ty: ::juniper::resolve::ScalarToken<#scalar>
+                        #ty: ::juniper::resolve::ScalarToken<#sv>
                     }
                 })
                 .collect(),

From 97d2da581a2a7ff535f5b837775a74496a12ff35 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Wed, 1 Jun 2022 17:31:02 +0200
Subject: [PATCH 16/58] Impl codegen for scalars (`resolve::ToInputValue`
 trait), vol.5

---
 juniper/src/ast.rs                        | 35 ++++++---
 juniper/src/macros/reflect.rs             |  4 +-
 juniper/src/resolve/mod.rs                |  4 +
 juniper/src/types/arc.rs                  | 17 ++++-
 juniper/src/types/array.rs                |  9 +++
 juniper/src/types/box.rs                  | 17 ++++-
 juniper/src/types/containers.rs           |  6 +-
 juniper/src/types/nullable.rs             | 12 +++
 juniper/src/types/option.rs               | 12 +++
 juniper/src/types/rc.rs                   | 17 ++++-
 juniper/src/types/ref.rs                  | 17 ++++-
 juniper/src/types/ref_mut.rs              |  9 +++
 juniper/src/types/slice.rs                |  9 +++
 juniper/src/types/str.rs                  | 17 ++++-
 juniper/src/types/vec.rs                  |  9 +++
 juniper/src/value/mod.rs                  | 22 ++++++
 juniper_codegen/src/graphql_scalar/mod.rs | 89 ++++++++++++++++++++++-
 17 files changed, 265 insertions(+), 40 deletions(-)

diff --git a/juniper/src/ast.rs b/juniper/src/ast.rs
index ea2c0fec2..b535f9215 100644
--- a/juniper/src/ast.rs
+++ b/juniper/src/ast.rs
@@ -256,13 +256,17 @@ impl<S> InputValue<S> {
         Self::Variable(v.as_ref().to_owned())
     }
 
-    /// Construct a [`Spanning::unlocated`] list.
+    /// Constructs a [`Spanning::unlocated`] [`InputValue::List`].
     ///
-    /// Convenience function to make each [`InputValue`] in the input vector
-    /// not contain any location information. Can be used from [`ToInputValue`]
-    /// implementations, where no source code position information is available.
-    pub fn list(l: Vec<Self>) -> Self {
-        Self::List(l.into_iter().map(Spanning::unlocated).collect())
+    /// Convenience function to make each [`InputValue`] in the input `list` to
+    /// not contain any location information.
+    ///
+    /// Intended for [`resolve::ToInputValue`] implementations, where no source
+    /// code position information is available.
+    ///
+    /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
+    pub fn list(list: impl IntoIterator<Item = Self>) -> Self {
+        Self::List(list.into_iter().map(Spanning::unlocated).collect())
     }
 
     /// Construct a located list.
@@ -270,16 +274,25 @@ impl<S> InputValue<S> {
         Self::List(l)
     }
 
-    /// Construct aa [`Spanning::unlocated`] object.
+    /// Construct a [`Spanning::unlocated`] [`InputValue::Onject`].
+    ///
+    /// Similarly to [`InputValue::list()`] it makes each key and value in the
+    /// given `obj`ect to not contain any location information.
+    ///
+    /// Intended for [`resolve::ToInputValue`] implementations, where no source
+    /// code position information is available.
     ///
-    /// Similarly to [`InputValue::list`] it makes each key and value in the
-    /// given hash map not contain any location information.
-    pub fn object<K>(o: IndexMap<K, Self>) -> Self
+    /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
+    // TODO: Use `impl IntoIterator<Item = (K, Self)>` argument once feature
+    //       `explicit_generic_args_with_impl_trait` hits stable:
+    //       https://github.com/rust-lang/rust/issues/83701
+    pub fn object<K, O>(obj: O) -> Self
     where
         K: AsRef<str> + Eq + Hash,
+        O: IntoIterator<Item = (K, Self)>,
     {
         Self::Object(
-            o.into_iter()
+            obj.into_iter()
                 .map(|(k, v)| {
                     (
                         Spanning::unlocated(k.as_ref().to_owned()),
diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs
index f40a8c7d8..b967d958f 100644
--- a/juniper/src/macros/reflect.rs
+++ b/juniper/src/macros/reflect.rs
@@ -2,9 +2,7 @@
 
 use futures::future::BoxFuture;
 
-use crate::{
-    Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, Nullable, ScalarValue,
-};
+use crate::{Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue};
 
 /// Alias for a [GraphQL object][1], [scalar][2] or [interface][3] type's name
 /// in a GraphQL schema.
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 39c693e3c..87564555e 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -101,3 +101,7 @@ pub trait InputValue<'input, S: 'input = DefaultScalarValue>: Sized {
 pub trait InputValueOwned<S = DefaultScalarValue>: for<'i> InputValue<'i, S> {}
 
 impl<T, S> InputValueOwned<S> for T where T: for<'i> InputValue<'i, S> {}
+
+pub trait ToInputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<S>;
+}
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 33804c3fe..cb5a44ee3 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -143,12 +143,12 @@ where
     }
 }
 
-impl<T, S> resolve::ScalarToken<S> for Arc<T>
+impl<T, S> resolve::ToInputValue<S> for Arc<T>
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ToInputValue<S> + ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        T::parse_scalar_token(token)
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        (**self).to_input_value()
     }
 }
 
@@ -194,6 +194,15 @@ where
     }
 }
 
+impl<T, S> resolve::ScalarToken<S> for Arc<T>
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Arc<T>
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
index 4cd5856bb..0f0197fac 100644
--- a/juniper/src/types/array.rs
+++ b/juniper/src/types/array.rs
@@ -64,6 +64,15 @@ where
     }
 }
 
+impl<T, S, const N: usize> resolve::ToInputValue<S> for [T; N]
+where
+    T: resolve::ToInputValue<S>,
+{
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        graphql::InputValue::list(self.iter().map(T::to_input_value))
+    }
+}
+
 impl<T, S, const N: usize> graphql::InputType<S> for [T; N]
 where
     T: graphql::InputType<S>,
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 1237ed6ea..be725c5d7 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -141,12 +141,12 @@ where
     }
 }
 
-impl<T, S> resolve::ScalarToken<S> for Box<T>
+impl<T, S> resolve::ToInputValue<S> for Box<T>
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ToInputValue<S> + ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        T::parse_scalar_token(token)
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        (**self).to_input_value()
     }
 }
 
@@ -192,6 +192,15 @@ where
     }
 }
 
+impl<T, S> resolve::ScalarToken<S> for Box<T>
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Box<T>
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/containers.rs b/juniper/src/types/containers.rs
index ab5383a4f..bda6d4dbe 100644
--- a/juniper/src/types/containers.rs
+++ b/juniper/src/types/containers.rs
@@ -183,7 +183,7 @@ where
     S: ScalarValue,
 {
     fn to_input_value(&self) -> InputValue<S> {
-        InputValue::list(self.iter().map(T::to_input_value).collect())
+        InputValue::list(self.iter().map(T::to_input_value))
     }
 }
 
@@ -283,7 +283,7 @@ where
     S: ScalarValue,
 {
     fn to_input_value(&self) -> InputValue<S> {
-        InputValue::list(self.iter().map(T::to_input_value).collect())
+        InputValue::list(self.iter().map(T::to_input_value))
     }
 }
 
@@ -481,7 +481,7 @@ where
     S: ScalarValue,
 {
     fn to_input_value(&self) -> InputValue<S> {
-        InputValue::list(self.iter().map(T::to_input_value).collect())
+        InputValue::list(self.iter().map(T::to_input_value))
     }
 }
 
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index 4113ea812..a87367810 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -324,6 +324,18 @@ where
     }
 }
 
+impl<T, S> resolve::ToInputValue<S> for Nullable<T>
+where
+    T: resolve::ToInputValue<S>,
+{
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        match self {
+            Self::Some(v) => v.to_input_value(),
+            Self::ExplicitNull | Self::ImplicitNull => graphql::InputValue::Null,
+        }
+    }
+}
+
 impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Nullable<T>
 where
     T: resolve::InputValue<'inp, S>,
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index 75320f82f..4b475182f 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -61,6 +61,18 @@ where
     }
 }
 
+impl<T, S> resolve::ToInputValue<S> for Option<T>
+where
+    T: resolve::ToInputValue<S>,
+{
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        match self {
+            Some(v) => v.to_input_value(),
+            None => graphql::InputValue::Null,
+        }
+    }
+}
+
 impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Option<T>
 where
     T: resolve::InputValue<'inp, S>,
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 515290b12..76d148d71 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -143,12 +143,12 @@ where
     }
 }
 
-impl<T, S> resolve::ScalarToken<S> for Rc<T>
+impl<T, S> resolve::ToInputValue<S> for Rc<T>
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ToInputValue<S> + ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        T::parse_scalar_token(token)
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        (**self).to_input_value()
     }
 }
 
@@ -194,6 +194,15 @@ where
     }
 }
 
+impl<T, S> resolve::ScalarToken<S> for Rc<T>
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Rc<T>
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 646b45661..55ed18bea 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -143,12 +143,12 @@ where
     }
 }
 
-impl<'me, T, S> resolve::ScalarToken<S> for &'me T
+impl<'me, T, S> resolve::ToInputValue<S> for &'me T
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ToInputValue<S> + ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        T::parse_scalar_token(token)
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        (**self).to_input_value()
     }
 }
 
@@ -180,6 +180,15 @@ pub trait TryFromInputValue<S = DefaultScalarValue> {
     }
 }
 
+impl<'me, T, S> resolve::ScalarToken<S> for &'me T
+where
+    T: resolve::ScalarToken<S> + ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
 impl<'me, T, S> graphql::InputType<S> for &'me T
 where
     T: graphql::InputType<S> + ?Sized,
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index 36a576d72..607b4ba45 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -142,6 +142,15 @@ where
     }
 }
 
+impl<'me, T, S> resolve::ToInputValue<S> for &'me mut T
+where
+    T: resolve::ToInputValue<S> + ?Sized,
+{
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        (**self).to_input_value()
+    }
+}
+
 impl<'me, T, S> resolve::ScalarToken<S> for &'me mut T
 where
     T: resolve::ScalarToken<S> + ?Sized,
diff --git a/juniper/src/types/slice.rs b/juniper/src/types/slice.rs
index 5a5b6b52b..7dcdfe356 100644
--- a/juniper/src/types/slice.rs
+++ b/juniper/src/types/slice.rs
@@ -62,6 +62,15 @@ where
     }
 }
 
+impl<T, S> resolve::ToInputValue<S> for [T]
+where
+    T: resolve::ToInputValue<S>,
+{
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        graphql::InputValue::list(self.iter().map(T::to_input_value))
+    }
+}
+
 impl<T, S> graphql::InputType<S> for [T]
 where
     T: graphql::InputType<S>,
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index b8f269851..65ebcf615 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -66,12 +66,12 @@ where
     }
 }
 
-impl<S> resolve::ScalarToken<S> for str
+impl<S> resolve::ToInputValue<S> for str
 where
-    String: resolve::ScalarToken<S>,
+    S: From<String>,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        <String as resolve::ScalarToken<S>>::parse_scalar_token(token)
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        graphql::InputValue::scalar(self.to_owned())
     }
 }
 
@@ -108,6 +108,15 @@ impl<'inp, S: ScalarValue> resolve::InputValueAsRc<'inp, S> for str {
     }
 }
 
+impl<S> resolve::ScalarToken<S> for str
+where
+    String: resolve::ScalarToken<S>,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+        <String as resolve::ScalarToken<S>>::parse_scalar_token(token)
+    }
+}
+
 impl<S> graphql::InputType<S> for str {
     fn assert_input_type() {}
 }
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
index 8a96f5ad7..bf1735128 100644
--- a/juniper/src/types/vec.rs
+++ b/juniper/src/types/vec.rs
@@ -60,6 +60,15 @@ where
     }
 }
 
+impl<T, S> resolve::ToInputValue<S> for Vec<T>
+where
+    T: resolve::ToInputValue<S>,
+{
+    fn to_input_value(&self) -> graphql::InputValue<S> {
+        graphql::InputValue::list(self.iter().map(T::to_input_value))
+    }
+}
+
 impl<T, S> graphql::InputType<S> for Vec<T>
 where
     T: graphql::InputType<S>,
diff --git a/juniper/src/value/mod.rs b/juniper/src/value/mod.rs
index e3457c8eb..9d8ca2b34 100644
--- a/juniper/src/value/mod.rs
+++ b/juniper/src/value/mod.rs
@@ -6,6 +6,7 @@ use std::{any::TypeId, borrow::Cow, fmt, mem};
 use crate::{
     ast::{InputValue, ToInputValue},
     parser::Spanning,
+    resolve,
 };
 
 pub use self::{
@@ -190,6 +191,27 @@ impl<S: Clone> ToInputValue<S> for Value<S> {
     }
 }
 
+impl<S: Clone> resolve::ToInputValue<S> for Value<S> {
+    fn to_input_value(&self) -> InputValue<S> {
+        // TODO: Simplify recursive calls syntax, once old `ToInputValue` trait
+        //       is removed.
+        match self {
+            Self::Null => InputValue::Null,
+            Self::Scalar(s) => InputValue::Scalar(s.clone()),
+            Self::List(l) => InputValue::list(
+                l.iter()
+                    .map(<Self as resolve::ToInputValue<S>>::to_input_value),
+            ),
+            Self::Object(o) => InputValue::object(o.iter().map(|(k, v)| {
+                (
+                    k.clone(),
+                    <Self as resolve::ToInputValue<S>>::to_input_value(v),
+                )
+            })),
+        }
+    }
+}
+
 impl<S: ScalarValue> fmt::Display for Value<S> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 17508bc0a..daecafe81 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -334,6 +334,7 @@ impl ToTokens for Definition {
         self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_value().to_tokens(into);
         self.impl_resolve_value_async().to_tokens(into);
+        self.impl_resolve_to_input_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
         self.impl_input_and_output_type().to_tokens(into);
@@ -680,7 +681,7 @@ impl Definition {
     fn impl_to_input_value_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
 
-        let to_input_value = self.methods.expand_to_input_value(scalar);
+        let to_input_value = self.methods.expand_old_to_input_value(scalar);
 
         let (ty, generics) = self.impl_self_and_generics(false);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
@@ -697,6 +698,34 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::ToInputValue`] trait for
+    /// this [GraphQL scalar][0].
+    ///
+    /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_to_input_value(&self) -> TokenStream {
+        let (ty, generics) = self.ty_and_generics();
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        generics
+            .make_where_clause()
+            .predicates
+            .push(self.methods.bound_to_input_value(sv));
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let body = self.methods.expand_to_input_value(sv);
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::ToInputValue<#sv> for #ty
+                #where_clause
+            {
+                fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
+                    #body
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`FromInputValue`] trait for this
     /// [GraphQL scalar][1].
     ///
@@ -1084,7 +1113,7 @@ impl Methods {
         }
     }
 
-    /// Expands [`resolve::Value::resolve_value()`][0] method.
+    /// Expands body of [`resolve::Value::resolve_value()`][0] method.
     ///
     /// [0]: juniper::resolve::Value::resolve_value
     fn expand_resolve_value(
@@ -1152,7 +1181,7 @@ impl Methods {
     /// Expands [`ToInputValue::to_input_value`] method.
     ///
     /// [`ToInputValue::to_input_value`]: juniper::ToInputValue::to_input_value
-    fn expand_to_input_value(&self, scalar: &scalar::Type) -> TokenStream {
+    fn expand_old_to_input_value(&self, scalar: &scalar::Type) -> TokenStream {
         match self {
             Self::Custom { to_output, .. }
             | Self::Delegated {
@@ -1172,6 +1201,60 @@ impl Methods {
         }
     }
 
+    /// Expands body of [`resolve::ToInputValue::to_input_value()`][0] method.
+    ///
+    /// [0]: juniper::resolve::ToInputValue::to_input_value
+    fn expand_to_input_value(&self, sv: &scalar::Type) -> TokenStream {
+        match self {
+            Self::Custom { to_output, .. }
+            | Self::Delegated {
+                to_output: Some(to_output),
+                ..
+            } => {
+                quote! {
+                    let v = #to_output(self);
+                    ::juniper::resolve::ToInputValue::<#sv>::to_input_value(&v)
+                }
+            }
+
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+
+                quote! {
+                    <#field_ty as ::juniper::resolve::ToInputValue<#sv>>
+                        ::to_input_value(&self.#field)
+                }
+            }
+        }
+    }
+
+    /// Generates additional trait bounds for [`resolve::ToInputValue`]
+    /// implementation allowing to execute
+    /// [`resolve::ToInputValue::to_input_value()`][0] method.
+    ///
+    /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
+    /// [0]: juniper::resolve::ToInputValue::to_input_value
+    fn bound_to_input_value(&self, sv: &scalar::Type) -> syn::WherePredicate {
+        match self {
+            Self::Custom { .. }
+            | Self::Delegated {
+                to_output: Some(_), ..
+            } => {
+                parse_quote! {
+                    #sv: ::juniper::ScalarValue
+                }
+            }
+
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+
+                parse_quote! {
+                    #field_ty: ::juniper::resolve::ToInputValue<#sv>>
+                }
+            }
+        }
+    }
+
     /// Expands [`FromInputValue::from_input_value`][1] method.
     ///
     /// [1]: juniper::FromInputValue::from_input_value

From 8235ac22c03cd6729288e0c4b303dc1647620564 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 6 Jun 2022 19:06:59 +0200
Subject: [PATCH 17/58] Reworking base traits, vol.1 [skip ci]

---
 juniper/src/behavior.rs                   |   5 +
 juniper/src/graphql/mod.rs                |  42 ++--
 juniper/src/graphql/resolve.rs            | 230 ----------------------
 juniper/src/lib.rs                        |   1 +
 juniper/src/macros/reflect.rs             |  23 +--
 juniper/src/reflect/mod.rs                |  55 +++++-
 juniper/src/resolve/mod.rs                | 139 ++++++++-----
 juniper/src/types/arc.rs                  |   5 +-
 juniper/src/types/array.rs                |   7 +-
 juniper/src/types/box.rs                  |   5 +-
 juniper/src/types/nullable.rs             |   5 +-
 juniper/src/types/option.rs               |   5 +-
 juniper/src/types/rc.rs                   |   5 +-
 juniper/src/types/ref.rs                  |   8 +-
 juniper/src/types/ref_mut.rs              |   9 -
 juniper/src/types/slice.rs                |   2 +
 juniper/src/types/str.rs                  |   8 +-
 juniper/src/types/vec.rs                  |   7 +-
 juniper_codegen/src/graphql_scalar/mod.rs |   8 +-
 19 files changed, 216 insertions(+), 353 deletions(-)
 create mode 100644 juniper/src/behavior.rs
 delete mode 100644 juniper/src/graphql/resolve.rs

diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
new file mode 100644
index 000000000..3c6c84a41
--- /dev/null
+++ b/juniper/src/behavior.rs
@@ -0,0 +1,5 @@
+//! Default GraphQL behaviors.
+
+/// Default standard behavior of GraphQL types implementation.
+#[derive(Debug)]
+pub enum Standard {}
diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index fb1ac95fd..8c3d3b660 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -1,16 +1,10 @@
-pub mod resolve;
-
-use crate::DefaultScalarValue;
-
 pub use crate::{
     ast::InputValue, graphql_input_value as input_value, graphql_value as value, value::Value,
 };
 
-pub use self::resolve::Type;
-
-pub trait Interface<S = DefaultScalarValue>:
+pub trait Interface<S>:
     OutputType<S>
-    + Type<S>
+/*
     + resolve::TypeName
     + resolve::ConcreteTypeName
     + resolve::Value<S>
@@ -19,51 +13,55 @@ pub trait Interface<S = DefaultScalarValue>:
     + resolve::ConcreteValueAsync<S>
     + resolve::Field<S>
     + resolve::FieldAsync<S>
+
+ */
 {
     fn assert_interface();
 }
 
-pub trait Object<S = DefaultScalarValue>:
+pub trait Object<S>:
     OutputType<S>
-    + Type<S>
+/*
     + resolve::TypeName
     + resolve::ConcreteTypeName
     + resolve::Value<S>
     + resolve::ValueAsync<S>
     + resolve::Field<S>
     + resolve::FieldAsync<S>
+
+ */
 {
     fn assert_object();
 }
 
-pub trait Scalar<S = DefaultScalarValue>:
-    InputType<S>
-    + OutputType<S>
-    + Type<S>
-    + resolve::TypeName
-    + resolve::Value<S>
-    + resolve::ValueAsync<S>
+pub trait Scalar<S>:
+    OutputType<S> + /*
+    resolve::TypeName + resolve::Value<S> + resolve::ValueAsync<S> */
 {
     fn assert_scalar();
 }
 
-pub trait Union<S = DefaultScalarValue>:
+pub trait Union<S>:
     OutputType<S>
-    + Type<S>
+/*
     + resolve::TypeName
     + resolve::ConcreteTypeName
     + resolve::Value<S>
     + resolve::ValueAsync<S>
     + resolve::ConcreteValue<S>
-    + resolve::ConcreteValueAsync<S>
+    + resolve::ConcreteValueAsync<S> */
 {
     fn assert_union();
 }
 
-pub trait InputType<S = DefaultScalarValue> {
+pub trait InputType<'inp, Info: ?Sized, S: 'inp> /*:
+    crate::resolve::Type<Info, S>
+    + crate::resolve::ToInputValue<S>
+    + crate::resolve::InputValue<'inp, S>*/
+{
     fn assert_input_type();
 }
 
-pub trait OutputType<S = DefaultScalarValue> {
+pub trait OutputType<S>: /*Type<S>*/ {
     fn assert_output_type();
 }
diff --git a/juniper/src/graphql/resolve.rs b/juniper/src/graphql/resolve.rs
deleted file mode 100644
index 22fe5342b..000000000
--- a/juniper/src/graphql/resolve.rs
+++ /dev/null
@@ -1,230 +0,0 @@
-use crate::{
-    meta::MetaType, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
-    Registry, Selection,
-};
-
-pub trait Type<S = DefaultScalarValue> {
-    fn meta<'r, Info: ?Sized>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
-    where
-        S: 'r,
-        Self: resolve::Type<Info, S>;
-}
-
-impl<T: ?Sized, S> Type<S> for T {
-    fn meta<'r, Info: ?Sized>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
-    where
-        S: 'r,
-        Self: resolve::Type<Info, S>,
-    {
-        <Self as resolve::Type<Info, S>>::meta(registry, info)
-    }
-}
-
-pub trait TypeName {
-    fn type_name<Info: ?Sized>(info: &Info) -> &str
-    where
-        Self: resolve::TypeName<Info>;
-}
-
-impl<T: ?Sized> TypeName for T {
-    fn type_name<Info: ?Sized>(info: &Info) -> &str
-    where
-        Self: resolve::TypeName<Info>,
-    {
-        <Self as resolve::TypeName<Info>>::type_name(info)
-    }
-}
-
-pub trait ConcreteTypeName {
-    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
-    where
-        Self: resolve::ConcreteTypeName<Info>;
-}
-
-impl<T: ?Sized> ConcreteTypeName for T {
-    fn concrete_type_name<'i, Info: ?Sized>(&self, info: &'i Info) -> &'i str
-    where
-        Self: resolve::ConcreteTypeName<Info>,
-    {
-        <Self as resolve::ConcreteTypeName<Info>>::concrete_type_name(self, info)
-    }
-}
-
-pub trait Value<S = DefaultScalarValue> {
-    fn resolve_value<Info: ?Sized, Ctx: ?Sized>(
-        &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>
-    where
-        Self: resolve::Value<Info, Ctx, S>;
-}
-
-impl<T: ?Sized, S> Value<S> for T {
-    fn resolve_value<Info: ?Sized, Ctx: ?Sized>(
-        &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>
-    where
-        Self: resolve::Value<Info, Ctx, S>,
-    {
-        <Self as resolve::Value<Info, Ctx, S>>::resolve_value(self, selection_set, info, executor)
-    }
-}
-
-pub trait ValueAsync<S = DefaultScalarValue> {
-    fn resolve_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
-        &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>
-    where
-        Self: resolve::ValueAsync<Info, Ctx, S>;
-}
-
-impl<T: ?Sized, S> ValueAsync<S> for T {
-    fn resolve_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
-        &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>
-    where
-        Self: resolve::ValueAsync<Info, Ctx, S>,
-    {
-        <Self as resolve::ValueAsync<Info, Ctx, S>>::resolve_value_async(
-            self,
-            selection_set,
-            info,
-            executor,
-        )
-    }
-}
-
-pub trait ConcreteValue<S = DefaultScalarValue> {
-    fn resolve_concrete_value<Info: ?Sized, Ctx: ?Sized>(
-        &self,
-        type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>
-    where
-        Self: resolve::ConcreteValue<Info, Ctx, S>;
-}
-
-impl<T: ?Sized, S> ConcreteValue<S> for T {
-    fn resolve_concrete_value<Info: ?Sized, Ctx: ?Sized>(
-        &self,
-        type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>
-    where
-        Self: resolve::ConcreteValue<Info, Ctx, S>,
-    {
-        <Self as resolve::ConcreteValue<Info, Ctx, S>>::resolve_concrete_value(
-            self,
-            type_name,
-            selection_set,
-            info,
-            executor,
-        )
-    }
-}
-
-pub trait ConcreteValueAsync<S = DefaultScalarValue> {
-    fn resolve_concrete_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
-        &'r self,
-        type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>
-    where
-        Self: resolve::ConcreteValueAsync<Info, Ctx, S>;
-}
-
-impl<T: ?Sized, S> ConcreteValueAsync<S> for T {
-    fn resolve_concrete_value_async<'r, Info: ?Sized, Ctx: ?Sized>(
-        &'r self,
-        type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>
-    where
-        Self: resolve::ConcreteValueAsync<Info, Ctx, S>,
-    {
-        <Self as resolve::ConcreteValueAsync<Info, Ctx, S>>::resolve_concrete_value_async(
-            self,
-            type_name,
-            selection_set,
-            info,
-            executor,
-        )
-    }
-}
-
-pub trait Field<S = DefaultScalarValue> {
-    fn resolve_field<Info: ?Sized, Ctx: ?Sized>(
-        &self,
-        field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>
-    where
-        Self: resolve::Field<Info, Ctx, S>;
-}
-
-impl<T: ?Sized, S> Field<S> for T {
-    fn resolve_field<Info: ?Sized, Ctx: ?Sized>(
-        &self,
-        field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>
-    where
-        Self: resolve::Field<Info, Ctx, S>,
-    {
-        <Self as resolve::Field<Info, Ctx, S>>::resolve_field(
-            self, field_name, arguments, info, executor,
-        )
-    }
-}
-
-pub trait FieldAsync<S = DefaultScalarValue> {
-    fn resolve_field_async<'r, Info: ?Sized, Ctx: ?Sized>(
-        &'r self,
-        field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>
-    where
-        Self: resolve::FieldAsync<Info, Ctx, S>;
-}
-
-impl<T: ?Sized, S> FieldAsync<S> for T {
-    fn resolve_field_async<'r, Info: ?Sized, Ctx: ?Sized>(
-        &'r self,
-        field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>
-    where
-        Self: resolve::FieldAsync<Info, Ctx, S>,
-    {
-        <Self as resolve::FieldAsync<Info, Ctx, S>>::resolve_field_async(
-            self, field_name, arguments, info, executor,
-        )
-    }
-}
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 9340608a2..04ac5d69c 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -30,6 +30,7 @@ pub use juniper_codegen::{
 pub mod macros;
 
 mod ast;
+pub mod behavior;
 pub mod executor;
 pub mod graphql;
 pub mod http;
diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs
index b967d958f..2a1ccca80 100644
--- a/juniper/src/macros/reflect.rs
+++ b/juniper/src/macros/reflect.rs
@@ -2,22 +2,10 @@
 
 use futures::future::BoxFuture;
 
-use crate::{Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue};
-
-/// Alias for a [GraphQL object][1], [scalar][2] or [interface][3] type's name
-/// in a GraphQL schema.
-///
-/// See [`BaseType`] for more info.
-///
-/// [1]: https://spec.graphql.org/October2021#sec-Objects
-/// [2]: https://spec.graphql.org/October2021#sec-Scalars
-/// [3]: https://spec.graphql.org/October2021#sec-Interfaces
-pub type Type = &'static str;
-
-/// Alias for a slice of [`Type`]s.
-///
-/// See [`BaseSubTypes`] for more info.
-pub type Types = &'static [Type];
+use crate::{
+    reflect::{Type, Types, WrappedValue},
+    Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue,
+};
 
 /// Naming of a [GraphQL object][1], [scalar][2] or [interface][3] [`Type`].
 ///
@@ -69,9 +57,6 @@ where
     const NAMES: Types = T::NAMES;
 }
 
-/// Alias for a value of a [`WrappedType`] (composed GraphQL type).
-pub type WrappedValue = u128;
-
 // TODO: Just use `&str`s once they're allowed in `const` generics.
 /// Encoding of a composed GraphQL type in numbers.
 ///
diff --git a/juniper/src/reflect/mod.rs b/juniper/src/reflect/mod.rs
index e91f009a8..d4e1d8b67 100644
--- a/juniper/src/reflect/mod.rs
+++ b/juniper/src/reflect/mod.rs
@@ -1 +1,54 @@
-pub use crate::macros::reflect::*;
+//! Compile-time reflection of Rust types into GraphQL types.
+
+use crate::behavior;
+
+/// Alias for a [GraphQL type][0]'s name in a GraphQL schema.
+///
+/// See [`BaseType`] for more info.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Types
+pub type Type = &'static str;
+
+/// Alias for a slice of [`Type`]s.
+///
+/// See [`BaseSubTypes`] for more info.
+pub type Types = &'static [Type];
+
+/// Basic reflection of a [GraphQL type][0].
+///
+/// This trait is transparent to [`Option`], [`Vec`] and other containers, so to
+/// fully represent a [GraphQL object][1] we additionally use [`WrappedType`].
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Types
+pub trait BaseType<Behavior: ?Sized = behavior::Standard> {
+    /// [`Type`] of this [GraphQL type][0].
+    ///
+    /// Different Rust types may have the same [`NAME`]. For example, [`String`]
+    /// and [`&str`](prim@str) share the `String!` GraphQL [`Type`].
+    ///
+    /// [`NAME`]: Self::NAME
+    /// [0]: https://spec.graphql.org/October2021#sec-Types
+    const NAME: Type;
+}
+
+/// Reflection of [sub-types][2] of a [GraphQL type][0].
+///
+/// This trait is transparent to [`Option`], [`Vec`] and other containers.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Types
+/// [2]: https://spec.graphql.org/October2021#sel-JAHZhCHCDEJDAAAEEFDBtzC
+pub trait BaseSubTypes<Behavior: ?Sized = behavior::Standard> {
+    /// Sub-[`Types`] of this [GraphQL type][0].
+    ///
+    /// Contains [at least][2] the [`BaseType::NAME`] of this [GraphQL type][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Types
+    /// [2]: https://spec.graphql.org/October2021#sel-JAHZhCHCDEJDAAAEEFDBtzC
+    const NAMES: Types;
+}
+
+/// Alias for a value of a [`WrappedType`] (composed
+/// [GraphQL wrapping type][0]).
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Wrapping-Types
+pub type WrappedValue = u128;
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 87564555e..8e823117e 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -1,9 +1,8 @@
 use crate::{
-    graphql,
+    behavior, graphql,
     meta::MetaType,
     parser::{self, ParseError},
-    Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor, IntoFieldError, Registry,
-    Selection,
+    Arguments, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry, Selection,
 };
 
 #[doc(inline)]
@@ -12,96 +11,136 @@ pub use crate::types::{
     r#ref::TryFromInputValue as InputValueAsRef, rc::TryFromInputValue as InputValueAsRc,
 };
 
-pub trait Type<Info: ?Sized, S = DefaultScalarValue> {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+pub trait Type<TypeInfo: ?Sized, ScalarValue, Behavior: ?Sized = behavior::Standard> {
+    fn meta<'r>(
+        registry: &mut Registry<'r, ScalarValue>,
+        type_info: &TypeInfo,
+    ) -> MetaType<'r, ScalarValue>
     where
-        S: 'r; // TODO: remove?
+        ScalarValue: 'r; // TODO: remove?
 }
 
-pub trait TypeName<Info: ?Sized> {
-    fn type_name(info: &Info) -> &str;
+pub trait TypeName<TypeInfo: ?Sized, Behavior: ?Sized = behavior::Standard> {
+    fn type_name(type_info: &TypeInfo) -> &str;
 }
 
-pub trait ConcreteTypeName<Info: ?Sized> {
-    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str;
+pub trait ConcreteTypeName<TypeInfo: ?Sized> {
+    fn concrete_type_name<'i>(&self, type_info: &'i TypeInfo) -> &'i str;
 }
 
-pub trait Value<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+pub trait Value<
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>;
+        selection_set: Option<&[Selection<'_, ScalarValue>]>,
+        type_info: &TypeInfo,
+        executor: &Executor<Context, ScalarValue>,
+    ) -> ExecutionResult<ScalarValue>;
 }
 
-pub trait ValueAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+pub trait ValueAsync<
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>;
+        selection_set: Option<&'r [Selection<'_, ScalarValue>]>,
+        type_info: &'r TypeInfo,
+        executor: &'r Executor<Context, ScalarValue>,
+    ) -> BoxFuture<'r, ExecutionResult<ScalarValue>>;
 }
 
-pub trait ConcreteValue<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+pub trait ConcreteValue<
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
     fn resolve_concrete_value(
         &self,
         type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>;
+        selection_set: Option<&[Selection<'_, ScalarValue>]>,
+        type_info: &TypeInfo,
+        executor: &Executor<Context, ScalarValue>,
+    ) -> ExecutionResult<ScalarValue>;
 }
 
-pub trait ConcreteValueAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+pub trait ConcreteValueAsync<TypeInfo: ?Sized, Context: ?Sized, ScalarValue> {
     fn resolve_concrete_value_async<'r>(
         &'r self,
         type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>;
+        selection_set: Option<&'r [Selection<'_, ScalarValue>]>,
+        type_info: &'r TypeInfo,
+        executor: &'r Executor<Context, ScalarValue>,
+    ) -> BoxFuture<'r, ExecutionResult<ScalarValue>>;
 }
 
-pub trait Field<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+pub trait Field<
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
     fn resolve_field(
         &self,
         field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S>;
+        arguments: &Arguments<ScalarValue>,
+        type_info: &TypeInfo,
+        executor: &Executor<Context, ScalarValue>,
+    ) -> ExecutionResult<ScalarValue>;
 }
 
-pub trait FieldAsync<Info: ?Sized, Ctx: ?Sized, S = DefaultScalarValue> {
+pub trait FieldAsync<
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
     fn resolve_field_async<'r>(
         &'r self,
         field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>>;
+        arguments: &'r Arguments<ScalarValue>,
+        type_info: &'r TypeInfo,
+        executor: &'r Executor<Context, ScalarValue>,
+    ) -> BoxFuture<'r, ExecutionResult<ScalarValue>>;
 }
 
-pub trait ScalarToken<S = DefaultScalarValue> {
-    fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<S, ParseError<'_>>;
+pub trait ToInputValue<ScalarValue, Behavior: ?Sized = behavior::Standard> {
+    fn to_input_value(&self) -> graphql::InputValue<ScalarValue>;
 }
 
-pub trait InputValue<'input, S: 'input = DefaultScalarValue>: Sized {
-    type Error: IntoFieldError<S>;
+pub trait InputValue<'input, ScalarValue: 'input, Behavior: ?Sized = behavior::Standard>:
+    Sized
+{
+    type Error: IntoFieldError<ScalarValue>;
 
-    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Self, Self::Error>;
+    fn try_from_input_value(
+        v: &'input graphql::InputValue<ScalarValue>,
+    ) -> Result<Self, Self::Error>;
 
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
+        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
     }
 }
 
-pub trait InputValueOwned<S = DefaultScalarValue>: for<'i> InputValue<'i, S> {}
+pub trait InputValueOwned<ScalarValue, Behavior: ?Sized = behavior::Standard>:
+    for<'i> InputValue<'i, ScalarValue, Behavior>
+{
+}
 
-impl<T, S> InputValueOwned<S> for T where T: for<'i> InputValue<'i, S> {}
+impl<T, S, B: ?Sized> InputValueOwned<S, B> for T where T: for<'i> InputValue<'i, S, B> {}
 
-pub trait ToInputValue<S> {
-    fn to_input_value(&self) -> graphql::InputValue<S>;
+pub trait ScalarToken<ScalarValue, Behavior: ?Sized = behavior::Standard> {
+    fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<ScalarValue, ParseError<'_>>;
 }
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index cb5a44ee3..38f0f2187 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -203,9 +203,10 @@ where
     }
 }
 
-impl<T, S> graphql::InputType<S> for Arc<T>
+impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Arc<T>
 where
-    T: graphql::InputType<S> + ?Sized,
+    T: graphql::InputType<'i, Info, S> + ?Sized,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
index 0f0197fac..77ef5f9be 100644
--- a/juniper/src/types/array.rs
+++ b/juniper/src/types/array.rs
@@ -73,14 +73,17 @@ where
     }
 }
 
-impl<T, S, const N: usize> graphql::InputType<S> for [T; N]
+/*
+impl<'i, T, Info, S, const N: usize> graphql::InputType<'i, Info, S> for [T; N]
 where
-    T: graphql::InputType<S>,
+    T: graphql::InputType<'i, Info, S>,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
+*/
 
 impl<T, S, const N: usize> graphql::OutputType<S> for [T; N]
 where
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index be725c5d7..b30936972 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -201,9 +201,10 @@ where
     }
 }
 
-impl<T, S> graphql::InputType<S> for Box<T>
+impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Box<T>
 where
-    T: graphql::InputType<S> + ?Sized,
+    T: graphql::InputType<'i, Info, S> + resolve::InputValueAsBox<'i, S> + ?Sized,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index a87367810..04165f3bf 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -355,9 +355,10 @@ where
     }
 }
 
-impl<T, S> graphql::InputType<S> for Nullable<T>
+impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Nullable<T>
 where
-    T: graphql::InputType<S>,
+    T: graphql::InputType<'i, Info, S>,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index 4b475182f..0d8ebb6aa 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -88,9 +88,10 @@ where
     }
 }
 
-impl<T, S> graphql::InputType<S> for Option<T>
+impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Option<T>
 where
-    T: graphql::InputType<S>,
+    T: graphql::InputType<'i, Info, S>,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 76d148d71..ebecc3f27 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -203,9 +203,10 @@ where
     }
 }
 
-impl<T, S> graphql::InputType<S> for Rc<T>
+impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Rc<T>
 where
-    T: graphql::InputType<S> + ?Sized,
+    T: graphql::InputType<'i, Info, S> + ?Sized,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 55ed18bea..5b84d54f6 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -189,14 +189,16 @@ where
     }
 }
 
-impl<'me, T, S> graphql::InputType<S> for &'me T
+/*
+impl<'me, 'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for &'me T
 where
-    T: graphql::InputType<S> + ?Sized,
+    Self: resolve::Type<Info, S> + resolve::ToInputValue<S> + resolve::InputValue<'i, S>,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
-}
+}*/
 
 impl<'me, T, S> graphql::OutputType<S> for &'me T
 where
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index 607b4ba45..77f8b602e 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -160,15 +160,6 @@ where
     }
 }
 
-impl<'me, T, S> graphql::InputType<S> for &'me mut T
-where
-    T: graphql::InputType<S> + ?Sized,
-{
-    fn assert_input_type() {
-        T::assert_input_type()
-    }
-}
-
 impl<'me, T, S> graphql::OutputType<S> for &'me mut T
 where
     T: graphql::OutputType<S> + ?Sized,
diff --git a/juniper/src/types/slice.rs b/juniper/src/types/slice.rs
index 7dcdfe356..022a335bb 100644
--- a/juniper/src/types/slice.rs
+++ b/juniper/src/types/slice.rs
@@ -71,6 +71,7 @@ where
     }
 }
 
+/*
 impl<T, S> graphql::InputType<S> for [T]
 where
     T: graphql::InputType<S>,
@@ -79,6 +80,7 @@ where
         T::assert_input_type()
     }
 }
+*/
 
 impl<T, S> graphql::OutputType<S> for [T]
 where
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 65ebcf615..c1a559a0c 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -117,9 +117,15 @@ where
     }
 }
 
-impl<S> graphql::InputType<S> for str {
+/*
+impl<'i, Info, S: 'i> graphql::InputType<'i, Info, S> for str
+where
+    Self: resolve::Type<Info, S> + resolve::ToInputValue<S> + resolve::InputValue<'i, S>,
+    Info: ?Sized,
+{
     fn assert_input_type() {}
 }
+*/
 
 impl<S> graphql::OutputType<S> for str {
     fn assert_output_type() {}
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
index bf1735128..a3022e412 100644
--- a/juniper/src/types/vec.rs
+++ b/juniper/src/types/vec.rs
@@ -69,14 +69,17 @@ where
     }
 }
 
-impl<T, S> graphql::InputType<S> for Vec<T>
+/*
+impl<'i, T, Info, S> graphql::InputType<'i, Info, S> for Vec<T>
 where
-    T: graphql::InputType<S>,
+    T: graphql::InputType<'i, Info, S>,
+    Info: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
+ */
 
 impl<T, S> graphql::OutputType<S> for Vec<T>
 where
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index daecafe81..9e6e49cff 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -337,8 +337,8 @@ impl ToTokens for Definition {
         self.impl_resolve_to_input_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
-        self.impl_input_and_output_type().to_tokens(into);
-        //self.impl_scalar().to_tokens(into);
+        //self.impl_graphql_input_and_output_type().to_tokens(into);
+        //self.impl_graphql_scalar().to_tokens(into);
         self.impl_reflect().to_tokens(into);
     }
 }
@@ -375,7 +375,7 @@ impl Definition {
     /// [`graphql::OutputType`]: juniper::graphql::OutputType
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     #[must_use]
-    fn impl_input_and_output_type(&self) -> TokenStream {
+    fn impl_graphql_input_and_output_type(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
         let (sv, generics) = self.mix_scalar_value(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
@@ -403,7 +403,7 @@ impl Definition {
     /// [`graphql::Scalar`]: juniper::graphql::Scalar
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     #[must_use]
-    fn impl_scalar(&self) -> TokenStream {
+    fn impl_graphql_scalar(&self) -> TokenStream {
         let (ty, generics) = self.ty_and_generics();
         let (sv, generics) = self.mix_scalar_value(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();

From 97c88d219cc9587fe47545624a6b698ce711f302 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 7 Jun 2022 18:19:44 +0200
Subject: [PATCH 18/58] Reworking base traits, vol.2

---
 juniper/src/macros/reflect.rs | 309 +------------
 juniper/src/reflect/mod.rs    | 796 +++++++++++++++++++++++++++++++++-
 juniper/src/resolve/mod.rs    |  34 +-
 3 files changed, 843 insertions(+), 296 deletions(-)

diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs
index 2a1ccca80..b24ba4f58 100644
--- a/juniper/src/macros/reflect.rs
+++ b/juniper/src/macros/reflect.rs
@@ -3,7 +3,10 @@
 use futures::future::BoxFuture;
 
 use crate::{
-    reflect::{Type, Types, WrappedValue},
+    reflect::{
+        can_be_subtype, fnv1a128, str_eq, str_exists_in_arr, type_len_with_wrapped_val, wrap,
+        Argument, Arguments, FieldName, Name, Names, Type, Types, WrappedValue,
+    },
     Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue,
 };
 
@@ -78,7 +81,7 @@ where
 ///
 /// ```rust
 /// # use juniper::{
-/// #     format_type,
+/// #     reflect::format_type,
 /// #     macros::reflect::{WrappedType, BaseType, WrappedValue, Type},
 /// #     DefaultScalarValue,
 /// # };
@@ -114,48 +117,6 @@ where
     const VALUE: u128 = T::VALUE;
 }
 
-pub mod wrap {
-    use super::WrappedValue;
-
-    pub const SINGULAR: WrappedValue = 1;
-
-    pub const fn nullable(val: WrappedValue) -> WrappedValue {
-        val * 10 + 2
-    }
-
-    pub const fn list(val: WrappedValue) -> WrappedValue {
-        val * 10 + 3
-    }
-}
-
-/// Alias for a [GraphQL object][1] or [interface][2] [field argument][3] name.
-///
-/// See [`Fields`] for more info.
-///
-/// [1]: https://spec.graphql.org/October2021#sec-Objects
-/// [2]: https://spec.graphql.org/October2021#sec-Interfaces
-/// [3]: https://spec.graphql.org/October2021#sec-Language.Arguments
-pub type Name = &'static str;
-
-/// Alias for a slice of [`Name`]s.
-///
-/// See [`Fields`] for more info.
-pub type Names = &'static [Name];
-
-/// Alias for [field argument][1]s [`Name`], [`Type`] and [`WrappedValue`].
-///
-/// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
-pub type Argument = (Name, Type, WrappedValue);
-
-/// Alias for a slice of [field argument][1]s [`Name`], [`Type`] and
-/// [`WrappedValue`].
-///
-/// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
-pub type Arguments = &'static [(Name, Type, WrappedValue)];
-
-/// Alias for a `const`-hashed [`Name`] used in a `const` context.
-pub type FieldName = u128;
-
 /// [GraphQL object][1] or [interface][2] [field arguments][3] [`Names`].
 ///
 /// [1]: https://spec.graphql.org/October2021#sec-Objects
@@ -269,107 +230,6 @@ pub trait AsyncField<S, const N: FieldName>: FieldMeta<S, N> {
     ) -> BoxFuture<'b, ExecutionResult<S>>;
 }
 
-/// Non-cryptographic hash with good dispersion to use as a [`str`](prim@str) in
-/// `const` generics. See [spec] for more info.
-///
-/// [spec]: https://datatracker.ietf.org/doc/html/draft-eastlake-fnv-17.html
-#[must_use]
-pub const fn fnv1a128(str: Name) -> u128 {
-    const FNV_OFFSET_BASIS: u128 = 0x6c62272e07bb014262b821756295c58d;
-    const FNV_PRIME: u128 = 0x0000000001000000000000000000013b;
-
-    let bytes = str.as_bytes();
-    let mut hash = FNV_OFFSET_BASIS;
-    let mut i = 0;
-    while i < bytes.len() {
-        hash ^= bytes[i] as u128;
-        hash = hash.wrapping_mul(FNV_PRIME);
-        i += 1;
-    }
-    hash
-}
-
-/// Length __in bytes__ of the [`format_type!`] macro result.
-#[must_use]
-pub const fn type_len_with_wrapped_val(ty: Type, val: WrappedValue) -> usize {
-    let mut len = ty.as_bytes().len() + "!".as_bytes().len(); // Type!
-
-    let mut curr = val;
-    while curr % 10 != 0 {
-        match curr % 10 {
-            2 => len -= "!".as_bytes().len(),   // remove !
-            3 => len += "[]!".as_bytes().len(), // [Type]!
-            _ => {}
-        }
-        curr /= 10;
-    }
-
-    len
-}
-
-/// Checks whether the given GraphQL [object][1] represents a `subtype` of the
-/// given GraphQL `ty`pe, basing on the [`WrappedType`] encoding.
-///
-/// To fully determine the sub-typing relation the [`Type`] should be one of the
-/// [`BaseSubTypes::NAMES`].
-///
-/// [1]: https://spec.graphql.org/October2021#sec-Objects
-#[must_use]
-pub const fn can_be_subtype(ty: WrappedValue, subtype: WrappedValue) -> bool {
-    let ty_curr = ty % 10;
-    let sub_curr = subtype % 10;
-
-    if ty_curr == sub_curr {
-        if ty_curr == 1 {
-            true
-        } else {
-            can_be_subtype(ty / 10, subtype / 10)
-        }
-    } else if ty_curr == 2 {
-        can_be_subtype(ty / 10, subtype)
-    } else {
-        false
-    }
-}
-
-/// Checks whether the given `val` exists in the given `arr`.
-#[must_use]
-pub const fn str_exists_in_arr(val: &str, arr: &[&str]) -> bool {
-    let mut i = 0;
-    while i < arr.len() {
-        if str_eq(val, arr[i]) {
-            return true;
-        }
-        i += 1;
-    }
-    false
-}
-
-/// Compares strings in a `const` context.
-///
-/// As there is no `const impl Trait` and `l == r` calls [`Eq`], we have to
-/// write custom comparison function.
-///
-/// [`Eq`]: std::cmp::Eq
-// TODO: Remove once `Eq` trait is allowed in `const` context.
-pub const fn str_eq(l: &str, r: &str) -> bool {
-    let (l, r) = (l.as_bytes(), r.as_bytes());
-
-    if l.len() != r.len() {
-        return false;
-    }
-
-    let mut i = 0;
-    while i < l.len() {
-        if l[i] != r[i] {
-            return false;
-        }
-        i += 1;
-    }
-
-    true
-}
-
 /// Asserts that `#[graphql_interface(for = ...)]` has all the types referencing
 /// this interface in the `impl = ...` attribute argument.
 ///
@@ -384,7 +244,7 @@ macro_rules! assert_implemented_for {
                     <$interfaces as ::juniper::macros::reflect::BaseSubTypes<$scalar>>::NAMES,
                 );
                 if !is_present {
-                    const MSG: &str = $crate::const_concat!(
+                    const MSG: &str = $crate::reflect::const_concat!(
                         "Failed to implement interface `",
                         <$interfaces as $crate::macros::reflect::BaseType<$scalar>>::NAME,
                         "` on `",
@@ -412,7 +272,7 @@ macro_rules! assert_interfaces_impls {
                     <$implementers as ::juniper::macros::reflect::Implements<$scalar>>::NAMES,
                 );
                 if !is_present {
-                    const MSG: &str = $crate::const_concat!(
+                    const MSG: &str = $crate::reflect::const_concat!(
                         "Failed to implement interface `",
                         <$interface as $crate::macros::reflect::BaseType<$scalar>>::NAME,
                         "` on `",
@@ -465,7 +325,7 @@ macro_rules! assert_subtype {
                 <$base_ty as $crate::macros::reflect::BaseType<$scalar>>::NAME;
             const IMPL_TY: $crate::macros::reflect::Type =
                 <$impl_ty as $crate::macros::reflect::BaseType<$scalar>>::NAME;
-            const ERR_PREFIX: &str = $crate::const_concat!(
+            const ERR_PREFIX: &str = $crate::reflect::const_concat!(
                 "Failed to implement interface `",
                 BASE_TY,
                 "` on `",
@@ -507,14 +367,14 @@ macro_rules! assert_subtype {
             let is_subtype = $crate::macros::reflect::str_exists_in_arr(IMPL_RETURN_TY, BASE_RETURN_SUB_TYPES)
                 && $crate::macros::reflect::can_be_subtype(BASE_RETURN_WRAPPED_VAL, IMPL_RETURN_WRAPPED_VAL);
             if !is_subtype {
-                const MSG: &str = $crate::const_concat!(
+                const MSG: &str = $crate::reflect::const_concat!(
                     ERR_PREFIX,
                     "Field `",
                     FIELD_NAME,
                     "`: implementor is expected to return a subtype of interface's return object: `",
-                    $crate::format_type!(IMPL_RETURN_TY, IMPL_RETURN_WRAPPED_VAL),
+                    $crate::reflect::format_type!(IMPL_RETURN_TY, IMPL_RETURN_WRAPPED_VAL),
                     "` is not a subtype of `",
-                    $crate::format_type!(BASE_RETURN_TY, BASE_RETURN_WRAPPED_VAL),
+                    $crate::reflect::format_type!(BASE_RETURN_TY, BASE_RETURN_WRAPPED_VAL),
                     "`.",
                 );
                 ::std::panic!("{}", MSG);
@@ -538,7 +398,7 @@ macro_rules! assert_field_args {
         const _: () = {
             const BASE_NAME: &str = <$base_ty as $crate::macros::reflect::BaseType<$scalar>>::NAME;
             const IMPL_NAME: &str = <$impl_ty as $crate::macros::reflect::BaseType<$scalar>>::NAME;
-            const ERR_PREFIX: &str = $crate::const_concat!(
+            const ERR_PREFIX: &str = $crate::reflect::const_concat!(
                 "Failed to implement interface `",
                 BASE_NAME,
                 "` on `",
@@ -661,13 +521,14 @@ macro_rules! assert_field_args {
                 const BASE_ARG_NAME: &str = ERROR.base.0;
                 const IMPL_ARG_NAME: &str = ERROR.implementation.0;
 
-                const BASE_TYPE_FORMATTED: &str = $crate::format_type!(ERROR.base.1, ERROR.base.2);
+                const BASE_TYPE_FORMATTED: &str =
+                    $crate::reflect::format_type!(ERROR.base.1, ERROR.base.2);
                 const IMPL_TYPE_FORMATTED: &str =
-                    $crate::format_type!(ERROR.implementation.1, ERROR.implementation.2);
+                    $crate::reflect::format_type!(ERROR.implementation.1, ERROR.implementation.2);
 
                 const MSG: &str = match ERROR.cause {
                     Cause::TypeMismatch => {
-                        $crate::const_concat!(
+                        $crate::reflect::const_concat!(
                             "Argument `",
                             BASE_ARG_NAME,
                             "`: expected type `",
@@ -678,7 +539,7 @@ macro_rules! assert_field_args {
                         )
                     }
                     Cause::RequiredField => {
-                        $crate::const_concat!(
+                        $crate::reflect::const_concat!(
                             "Argument `",
                             BASE_ARG_NAME,
                             "` of type `",
@@ -687,7 +548,7 @@ macro_rules! assert_field_args {
                         )
                     }
                     Cause::AdditionalNonNullableField => {
-                        $crate::const_concat!(
+                        $crate::reflect::const_concat!(
                             "Argument `",
                             IMPL_ARG_NAME,
                             "` of type `",
@@ -697,43 +558,13 @@ macro_rules! assert_field_args {
                     }
                 };
                 const ERROR_MSG: &str =
-                    $crate::const_concat!(ERR_PREFIX, "Field `", FIELD_NAME, "`: ", MSG);
+                    $crate::reflect::const_concat!(ERR_PREFIX, "Field `", FIELD_NAME, "`: ", MSG);
                 ::std::panic!("{}", ERROR_MSG);
             }
         };
     };
 }
 
-/// Concatenates `const` [`str`](prim@str)s in a `const` context.
-#[macro_export]
-macro_rules! const_concat {
-    ($($s:expr),* $(,)?) => {{
-        const LEN: usize = 0 $(+ $s.as_bytes().len())*;
-        const CNT: usize = [$($s),*].len();
-        const fn concat(input: [&str; CNT]) -> [u8; LEN] {
-            let mut bytes = [0; LEN];
-            let (mut i, mut byte) = (0, 0);
-            while i < CNT {
-                let mut b = 0;
-                while b < input[i].len() {
-                    bytes[byte] = input[i].as_bytes()[b];
-                    byte += 1;
-                    b += 1;
-                }
-                i += 1;
-            }
-            bytes
-        }
-        const CON: [u8; LEN] = concat([$($s),*]);
-
-        // TODO: Use `str::from_utf8()` once it becomes `const`.
-        // SAFETY: This is safe, as we concatenate multiple UTF-8 strings one
-        //         after another byte-by-byte.
-        #[allow(unsafe_code)]
-        unsafe { ::std::str::from_utf8_unchecked(&CON) }
-    }};
-}
-
 /// Ensures that the given `$impl_ty` implements [`Field`] and returns a
 /// [`fnv1a128`] hash for it, otherwise panics with understandable message.
 #[macro_export]
@@ -746,7 +577,7 @@ macro_rules! checked_hash {
         if exists {
             $crate::macros::reflect::fnv1a128(FIELD_NAME)
         } else {
-            const MSG: &str = $crate::const_concat!(
+            const MSG: &str = $crate::reflect::const_concat!(
                 $($prefix,)?
                 "Field `",
                 $field_name,
@@ -758,103 +589,3 @@ macro_rules! checked_hash {
         }
     }};
 }
-
-/// Formats the given [`Type`] and [`WrappedValue`] into a readable GraphQL type
-/// name.
-///
-/// # Examples
-///
-/// ```rust
-/// # use juniper::format_type;
-/// #
-/// assert_eq!(format_type!("String", 123), "[String]!");
-/// assert_eq!(format_type!("🦀", 123), "[🦀]!");
-/// ```
-#[macro_export]
-macro_rules! format_type {
-    ($ty: expr, $wrapped_value: expr $(,)?) => {{
-        const TYPE: (
-            $crate::macros::reflect::Type,
-            $crate::macros::reflect::WrappedValue,
-        ) = ($ty, $wrapped_value);
-        const RES_LEN: usize = $crate::macros::reflect::type_len_with_wrapped_val(TYPE.0, TYPE.1);
-
-        const OPENING_BRACKET: &str = "[";
-        const CLOSING_BRACKET: &str = "]";
-        const BANG: &str = "!";
-
-        const fn format_type_arr() -> [u8; RES_LEN] {
-            let (ty, wrap_val) = TYPE;
-            let mut type_arr: [u8; RES_LEN] = [0; RES_LEN];
-
-            let mut current_start = 0;
-            let mut current_end = RES_LEN - 1;
-            let mut current_wrap_val = wrap_val;
-            let mut is_null = false;
-            while current_wrap_val % 10 != 0 {
-                match current_wrap_val % 10 {
-                    2 => is_null = true, // Skips writing `BANG` later.
-                    3 => {
-                        // Write `OPENING_BRACKET` at `current_start`.
-                        let mut i = 0;
-                        while i < OPENING_BRACKET.as_bytes().len() {
-                            type_arr[current_start + i] = OPENING_BRACKET.as_bytes()[i];
-                            i += 1;
-                        }
-                        current_start += i;
-                        if !is_null {
-                            // Write `BANG` at `current_end`.
-                            i = 0;
-                            while i < BANG.as_bytes().len() {
-                                type_arr[current_end - BANG.as_bytes().len() + i + 1] =
-                                    BANG.as_bytes()[i];
-                                i += 1;
-                            }
-                            current_end -= i;
-                        }
-                        // Write `CLOSING_BRACKET` at `current_end`.
-                        i = 0;
-                        while i < CLOSING_BRACKET.as_bytes().len() {
-                            type_arr[current_end - CLOSING_BRACKET.as_bytes().len() + i + 1] =
-                                CLOSING_BRACKET.as_bytes()[i];
-                            i += 1;
-                        }
-                        current_end -= i;
-                        is_null = false;
-                    }
-                    _ => {}
-                }
-
-                current_wrap_val /= 10;
-            }
-
-            // Writes `Type` at `current_start`.
-            let mut i = 0;
-            while i < ty.as_bytes().len() {
-                type_arr[current_start + i] = ty.as_bytes()[i];
-                i += 1;
-            }
-            i = 0;
-            if !is_null {
-                // Writes `BANG` at `current_end`.
-                while i < BANG.as_bytes().len() {
-                    type_arr[current_end - BANG.as_bytes().len() + i + 1] = BANG.as_bytes()[i];
-                    i += 1;
-                }
-            }
-
-            type_arr
-        }
-
-        const TYPE_ARR: [u8; RES_LEN] = format_type_arr();
-
-        // TODO: Use `str::from_utf8()` once it becomes `const`.
-        // SAFETY: This is safe, as we concatenate multiple UTF-8 strings one
-        //         after another byte-by-byte.
-        #[allow(unsafe_code)]
-        const TYPE_FORMATTED: &str =
-            unsafe { ::std::str::from_utf8_unchecked(TYPE_ARR.as_slice()) };
-
-        TYPE_FORMATTED
-    }};
-}
diff --git a/juniper/src/reflect/mod.rs b/juniper/src/reflect/mod.rs
index d4e1d8b67..2304e6a2b 100644
--- a/juniper/src/reflect/mod.rs
+++ b/juniper/src/reflect/mod.rs
@@ -2,16 +2,22 @@
 
 use crate::behavior;
 
-/// Alias for a [GraphQL type][0]'s name in a GraphQL schema.
+#[doc(inline)]
+pub use self::macros::{
+    assert_field, assert_field_args, assert_field_type, assert_has_field, assert_implemented_for,
+    assert_interfaces_impls, checked_hash, const_concat, format_type,
+};
+
+/// Name of a [GraphQL type][0] in a GraphQL schema.
 ///
-/// See [`BaseType`] for more info.
+/// See [`BaseType`] for details.
 ///
 /// [0]: https://spec.graphql.org/October2021#sec-Types
 pub type Type = &'static str;
 
-/// Alias for a slice of [`Type`]s.
+/// List of [`Type`]s.
 ///
-/// See [`BaseSubTypes`] for more info.
+/// See [`BaseSubTypes`] for details.
 pub type Types = &'static [Type];
 
 /// Basic reflection of a [GraphQL type][0].
@@ -47,8 +53,786 @@ pub trait BaseSubTypes<Behavior: ?Sized = behavior::Standard> {
     const NAMES: Types;
 }
 
-/// Alias for a value of a [`WrappedType`] (composed
-/// [GraphQL wrapping type][0]).
+/// Reflection of [GraphQL interfaces][1] implementations for a
+/// [GraphQL type][0].
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Types
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+pub trait Implements<Behavior: ?Sized = behavior::Standard> {
+    /// [`Types`] of the [GraphQL interfaces][1] implemented by this
+    /// [GraphQL type][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Types
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    const NAMES: Types;
+}
+
+/// Encoded value of a [`WrappedType`] (composed [GraphQL wrapping type][0]).
+///
+/// See [`WrappedType`] for details.
 ///
 /// [0]: https://spec.graphql.org/October2021#sec-Wrapping-Types
+// TODO: Just use `&str`s once they're allowed in `const` generics.
 pub type WrappedValue = u128;
+
+/// [`WrappedValue`] encoding helpers.
+pub mod wrap {
+    use super::WrappedValue;
+
+    /// [`WrappedValue`] of a singular non-nullable [GraphQL type][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Types
+    pub const SINGULAR: WrappedValue = 1;
+
+    /// Performs wrapping into a nullable [`WrappedValue`].
+    pub const fn nullable(val: WrappedValue) -> WrappedValue {
+        val * 10 + 2
+    }
+
+    /// Performs wrapping into a list [`WrappedValue`].
+    pub const fn list(val: WrappedValue) -> WrappedValue {
+        val * 10 + 3
+    }
+}
+
+/// Reflection of a composed [GraphQL wrapping type][1], encoded in numbers.
+///
+/// To fully represent a [GraphQL type][0] it's not enough to use [`Type`],
+/// because of the [wrapping types][1]. To work around this, a [`WrappedValue`]
+/// is used, which is represented via [`u128`] number in the following encoding:
+/// - In base case of non-nullable singular [type][0] [`VALUE`] is `1`.
+/// - To represent nullability we "append" `2` to the [`VALUE`], so
+///   [`Option`]`<`[type][0]`>` has [`VALUE`] of `12`.
+/// - To represent a list we "append" `3` to the [`VALUE`], so
+///   [`Vec`]`<`[type][0]`>` has [`VALUE`] of `13`.
+///
+/// Note, that due to Rust type system, the encoding here differs from the one
+/// of [GraphQL wrapping types][1], as it takes nullability as wrapping, while
+/// GraphQL [does the opposite][1] (takes non-nullability as wrapping).
+///
+/// This approach allows to uniquely represent any [GraphQL type][0] with a
+/// combination of a [`Type`] and a [`WrappedValue`], and even format it via
+/// [`format_type!`] macro in a `const` context.
+///
+/// # Example
+///
+/// ```rust
+/// # use juniper::reflect::{
+/// #     format_type, BaseType, Type, WrappedType, WrappedValue,
+/// # };
+/// #
+/// assert_eq!(<Option<i32> as WrappedType>::VALUE, 12);
+/// assert_eq!(<Vec<i32> as WrappedType>::VALUE, 13);
+/// assert_eq!(<Vec<Option<i32>> as WrappedType>::VALUE, 123);
+/// assert_eq!(<Option<Vec<i32>> as WrappedType>::VALUE, 132);
+/// assert_eq!(<Option<Vec<Option<i32>>> as WrappedType>::VALUE, 1232);
+///
+/// const TYPE_STRING: Type = <Option<Vec<Option<String>>> as BaseType>::NAME;
+/// const WRAP_VAL_STRING: WrappedValue = <Option<Vec<Option<String>>> as WrappedType>::VALUE;
+/// assert_eq!(format_type!(TYPE_STRING, WRAP_VAL_STRING), "[String]");
+///
+/// const TYPE_STR: Type = <Option<Vec<Option<&str>>> as BaseType>::NAME;
+/// const WRAP_VAL_STR: WrappedValue = <Option<Vec<Option<&str>>> as WrappedType>::VALUE;
+/// assert_eq!(format_type!(TYPE_STR, WRAP_VAL_STR), "[String]");
+/// ```
+///
+/// [`VALUE`]: Self::VALUE
+/// [0]: https://spec.graphql.org/October2021#sec-Types
+/// [1]: https://spec.graphql.org/October2021#sec-Wrapping-Types
+pub trait WrappedType<Behavior: ?Sized = behavior::Standard> {
+    /// [`WrappedValue`] of this this [GraphQL type][0], encoded in a number.
+    ///
+    /// Use [`format_type!`] macro on this number to represent it as a
+    /// human-readable [GraphQL type][0] string.
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Types
+    const VALUE: WrappedValue;
+}
+
+/// Name of a [GraphQL field][0] or a [field argument][1].
+///
+/// See [`Fields`] for details.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
+pub type Name = &'static str;
+
+/// List of [`Name`]s.
+///
+/// See [`Fields`] for details.
+pub type Names = &'static [Name];
+
+/// Reflection of [fields][0] for a [GraphQL object][1] or an [interface][2].
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+/// [1]: https://spec.graphql.org/October2021#sec-Objects
+/// [2]: https://spec.graphql.org/October2021#sec-Interfaces
+pub trait Fields<Behavior: ?Sized = behavior::Standard> {
+    /// [`Names`] of this [GraphQL object][1]/[interface][2] [fields][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
+    /// [2]: https://spec.graphql.org/October2021#sec-Interfaces
+    const NAMES: Names;
+}
+
+/// [GraphQL field argument][0], represented as its [`Name`], [`Type`] and
+/// [`WrappedValue`].
+///
+/// See [`Field`] for details.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Language.Arguments
+pub type Argument = (Name, Type, WrappedValue);
+
+/// List of [`Argument`]s.
+///
+/// See [`Field`] for details.
+pub type Arguments = &'static [(Name, Type, WrappedValue)];
+
+/// Alias for a `const`-hashed [`Name`] used in a `const` context.
+// TODO: Just use `&str`s once they're allowed in `const` generics.
+pub type FieldName = u128;
+
+/// Reflection of a single [GraphQL field][0].
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+pub trait Field<const N: FieldName, Behavior: ?Sized = behavior::Standard> {
+    /// [`Type`] of this [GraphQL field][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    const TYPE: Type;
+
+    /// [Sub-types][1] this [GraphQL field][0] is coercible into.
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [1]: BaseSubTypes
+    const SUB_TYPES: Types;
+
+    /// [`WrappedValue`] of this [GraphQL field][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    const WRAPPED_VALUE: WrappedValue;
+
+    /// [`Arguments`] of this [GraphQL field][0] .
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    const ARGUMENTS: Arguments;
+}
+
+/// Non-cryptographic hash with good dispersion to use as a [`str`](prim@str) in
+/// `const` generics. See [spec] for more info.
+///
+/// [spec]: https://datatracker.ietf.org/doc/html/draft-eastlake-fnv-17.html
+#[must_use]
+pub const fn fnv1a128(str: Name) -> FieldName {
+    const FNV_OFFSET_BASIS: u128 = 0x6c62272e07bb014262b821756295c58d;
+    const FNV_PRIME: u128 = 0x0000000001000000000000000000013b;
+
+    let bytes = str.as_bytes();
+    let mut hash = FNV_OFFSET_BASIS;
+    let mut i = 0;
+    while i < bytes.len() {
+        hash ^= bytes[i] as u128;
+        hash = hash.wrapping_mul(FNV_PRIME);
+        i += 1;
+    }
+    hash
+}
+
+/// Length __in bytes__ of the [`format_type!`] macro result.
+#[must_use]
+pub const fn type_len_with_wrapped_val(ty: Type, val: WrappedValue) -> usize {
+    let mut len = ty.as_bytes().len() + "!".as_bytes().len(); // Type!
+
+    let mut curr = val;
+    while curr % 10 != 0 {
+        match curr % 10 {
+            2 => len -= "!".as_bytes().len(),   // remove !
+            3 => len += "[]!".as_bytes().len(), // [Type]!
+            _ => {}
+        }
+        curr /= 10;
+    }
+
+    len
+}
+
+/// Checks whether the specified `subtype` [GraphQL type][0] represents a
+/// [sub-type][1] of the specified `supertype`, basing on the [`WrappedType`]
+/// encoding.
+///
+/// To fully determine the [sub-typing][1] relation the [`Type`] should be one
+/// of the [`BaseSubTypes::NAMES`].
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Types
+/// [1]: https://spec.graphql.org/October2021#sel-JAHZhCHCDEJDAAAEEFDBtzC
+#[must_use]
+pub const fn can_be_subtype(supertype: WrappedValue, subtype: WrappedValue) -> bool {
+    let super_curr = supertype % 10;
+    let sub_curr = subtype % 10;
+
+    if super_curr == sub_curr {
+        if super_curr == 1 {
+            true
+        } else {
+            can_be_subtype(supertype / 10, subtype / 10)
+        }
+    } else if super_curr == 2 {
+        can_be_subtype(supertype / 10, subtype)
+    } else {
+        false
+    }
+}
+
+/// Checks whether the given `val` exists in the given `arr`.
+// TODO: Remove once `slice::contains()` method is allowed in `const` context.
+#[must_use]
+pub const fn str_exists_in_arr(val: &str, arr: &[&str]) -> bool {
+    let mut i = 0;
+    while i < arr.len() {
+        if str_eq(val, arr[i]) {
+            return true;
+        }
+        i += 1;
+    }
+    false
+}
+
+/// Compares strings in a `const` context.
+///
+/// As there is no `const impl Trait` and `l == r` calls [`Eq`], we have to
+/// provide a custom comparison function.
+///
+/// [`Eq`]: std::cmp::Eq
+// TODO: Remove once `Eq` trait is allowed in `const` context.
+#[must_use]
+pub const fn str_eq(l: &str, r: &str) -> bool {
+    let (l, r) = (l.as_bytes(), r.as_bytes());
+
+    if l.len() != r.len() {
+        return false;
+    }
+
+    let mut i = 0;
+    while i < l.len() {
+        if l[i] != r[i] {
+            return false;
+        }
+        i += 1;
+    }
+
+    true
+}
+
+mod macros {
+    /// Asserts that `#[graphql::interface(for = ...)]` attribute has all the
+    /// types referencing this interface in the `impl = ...` attribute argument.
+    ///
+    /// Symmetrical to [`assert_interfaces_impls!`].
+    macro_rules! assert_implemented_for {
+        ($behavior: ty, $implementor: ty $(, $interfaces: ty)* $(,)?) => {
+            const _: () = {
+                $({
+                    let is_present = $crate::reflect::str_exists_in_arr(
+                        <$implementor as $crate::reflect::BaseType<$behavior>>::NAME,
+                        <$interfaces as $crate::reflect::BaseSubTypes<$behavior>>::NAMES,
+                    );
+                    if !is_present {
+                        const MSG: &str = $crate::reflect::const_concat!(
+                            "Failed to implement interface `",
+                            <$interfaces as $crate::reflect::BaseType<$behavior>>::NAME,
+                            "` on `",
+                            <$implementor as $crate::reflect::BaseType<$behavior>>::NAME,
+                            "`: missing implementer reference in interface's `for` attribute.",
+                        );
+                        ::std::panic!("{}", MSG);
+                    }
+                })*
+            };
+        };
+    }
+
+    /// Asserts that `impl = ...` attribute argument has all the interfaces
+    /// referencing this type in `#[graphql::interface(for = ...)]` attribute.
+    ///
+    /// Symmetrical to [`assert_implemented_for!`].
+    macro_rules! assert_interfaces_impls {
+        ($behavior: ty, $interface: ty $(, $implementers: ty)* $(,)?) => {
+            const _: () = {
+                $({
+                    let is_present = $crate::reflect::str_exists_in_arr(
+                        <$interface as $crate::reflect::BaseType<$behavior>>::NAME,
+                        <$implementers as $crate::reflect::Implements<$behavior>>::NAMES,
+                    );
+                    if !is_present {
+                        const MSG: &str = $crate::reflect::const_concat!(
+                            "Failed to implement interface `",
+                            <$interface as $crate::reflect::BaseType<$behavior>>::NAME,
+                            "` on `",
+                            <$implementers as $crate::reflect::BaseType<$behavior>>::NAME,
+                            "`: missing interface reference in implementer's `impl` attribute.",
+                        );
+                        ::std::panic!("{}", MSG);
+                    }
+                })*
+            };
+        };
+    }
+
+    /// Asserts validness of [`Field`] [`Arguments`] and its returned [`Type`].
+    ///
+    /// This assertion is a combination of [`assert_field_type!`] and
+    /// [`assert_field_args!`].
+    ///
+    /// See [spec][0] for assertion algorithm details.
+    ///
+    /// [`Arguments`]: super::Arguments
+    /// [`Field`]: super::Field
+    /// [`Type`]: super::Type
+    /// [0]: https://spec.graphql.org/October2021#IsValidImplementation()
+    macro_rules! assert_field {
+        (
+            $base_ty: ty,
+            $impl_ty: ty,
+            $behavior: ty,
+            $field_name: expr $(,)?
+        ) => {
+            $crate::reflect::assert_field_type!($base_ty, $impl_ty, $behavior, $field_name);
+            $crate::reflect::assert_field_args!($base_ty, $impl_ty, $behavior, $field_name);
+        };
+    }
+
+    /// Asserts validness of a [`Field`] type.
+    ///
+    /// See [spec][0] for assertion algorithm details.
+    ///
+    /// [`Field`]: super::Field
+    /// [0]: https://spec.graphql.org/October2021#IsValidImplementationFieldType()
+    #[macro_export]
+    macro_rules! assert_field_type {
+        (
+            $base_ty: ty,
+            $impl_ty: ty,
+            $behavior: ty,
+            $field_name: expr $(,)?
+        ) => {
+            const _: () = {
+                const BASE_TY: $crate::reflect::Type =
+                    <$base_ty as $crate::reflect::BaseType<$behavior>>::NAME;
+                const IMPL_TY: $crate::reflect::Type =
+                    <$impl_ty as $crate::reflect::BaseType<$behavior>>::NAME;
+                const ERR_PREFIX: &str = $crate::reflect::const_concat!(
+                    "Failed to implement interface `",
+                    BASE_TY,
+                    "` on `",
+                    IMPL_TY,
+                    "`: ",
+                );
+
+                const FIELD_NAME: $crate::reflect::Name = $field_name;
+                const FIELD_NAME_HASH: $crate::reflect::FieldName =
+                    $crate::reflect::fnv1a128(FIELD_NAME);
+
+                $crate::reflect::assert_has_field!(
+                    FIELD_NAME, $base_ty, $behavior, ERR_PREFIX,
+                );
+                $crate::reflect::assert_has_field!(
+                    FIELD_NAME, $impl_ty, $behavior, ERR_PREFIX,
+                );
+
+                const BASE_RETURN_WRAPPED_VAL: $crate::reflect::WrappedValue =
+                    <$base_ty as $crate::reflect::Field<
+                        FIELD_NAME_HASH, $behavior,
+                    >>::WRAPPED_VALUE;
+                const IMPL_RETURN_WRAPPED_VAL: $crate::reflect::WrappedValue =
+                    <$impl_ty as $crate::reflect::Field<
+                        FIELD_NAME_HASH, $behavior,
+                    >>::WRAPPED_VALUE;
+
+                const BASE_RETURN_TY: $crate::reflect::Type =
+                    <$base_ty as $crate::reflect::Field<
+                        FIELD_NAME_HASH, $behavior,
+                    >>::TYPE;
+                const IMPL_RETURN_TY: $crate::reflect::Type =
+                    <$impl_ty as $crate::reflect::Field<
+                        FIELD_NAME_HASH, $behavior,
+                    >>::TYPE;
+
+                const BASE_RETURN_SUB_TYPES: $crate::reflect::Types =
+                    <$base_ty as $crate::reflect::Field<
+                        FIELD_NAME_HASH, $behavior,
+                    >>::SUB_TYPES;
+
+                let is_subtype = $crate::reflect::str_exists_in_arr(
+                    IMPL_RETURN_TY, BASE_RETURN_SUB_TYPES,
+                ) && $crate::reflect::can_be_subtype(
+                    BASE_RETURN_WRAPPED_VAL, IMPL_RETURN_WRAPPED_VAL,
+                );
+                if !is_subtype {
+                    const MSG: &str = $crate::reflect::const_concat!(
+                        ERR_PREFIX,
+                        "Field `",
+                        FIELD_NAME,
+                        "`: implementor is expected to return a subtype of interface's return object: `",
+                        $crate::reflect::format_type!(IMPL_RETURN_TY, IMPL_RETURN_WRAPPED_VAL),
+                        "` is not a subtype of `",
+                        $crate::reflect::format_type!(BASE_RETURN_TY, BASE_RETURN_WRAPPED_VAL),
+                        "`.",
+                    );
+                    ::std::panic!("{}", MSG);
+                }
+            };
+        };
+    }
+
+    /// Asserts validness of a [`Field`] arguments.
+    ///
+    /// See [spec][0] for assertion algorithm details.
+    ///
+    /// [`Field`]: super::Field
+    /// [0]: https://spec.graphql.org/October2021#sel-IAHZhCHCDEEFAAADHD8Cxob
+    #[macro_export]
+    macro_rules! assert_field_args {
+        (
+            $base_ty: ty,
+            $impl_ty: ty,
+            $behavior: ty,
+            $field_name: expr $(,)?
+        ) => {
+            const _: () = {
+                const BASE_TY: $crate::reflect::Type =
+                    <$base_ty as $crate::reflect::BaseType<$behavior>>::NAME;
+                const IMPL_TY: $crate::reflect::Type =
+                    <$impl_ty as $crate::reflect::BaseType<$behavior>>::NAME;
+                const ERR_PREFIX: &str = $crate::reflect::const_concat!(
+                    "Failed to implement interface `",
+                    BASE_TY,
+                    "` on `",
+                    IMPL_TY,
+                    "`: ",
+                );
+
+                const FIELD_NAME: $crate::reflect::Name = $field_name;
+                const FIELD_NAME_HASH: $crate::reflect::FieldName =
+                    $crate::reflect::fnv1a128(FIELD_NAME);
+
+                $crate::reflect::assert_has_field!(FIELD_NAME, $base_ty, $behavior, ERR_PREFIX);
+                $crate::reflect::assert_has_field!(FIELD_NAME, $impl_ty, $behavior, ERR_PREFIX);
+
+                const BASE_ARGS: ::juniper::reflect::Arguments =
+                    <$base_ty as $crate::reflect::Field<FIELD_NAME_HASH, $behavior>>::ARGUMENTS;
+                const IMPL_ARGS: ::juniper::reflect::Arguments =
+                    <$impl_ty as $crate::reflect::Field<FIELD_NAME_HASH, $behavior>>::ARGUMENTS;
+
+                struct Error {
+                    cause: Cause,
+                    base: ::juniper::reflect::Argument,
+                    implementation: ::juniper::reflect::Argument,
+                }
+
+                enum Cause {
+                    RequiredField,
+                    AdditionalNonNullableField,
+                    TypeMismatch,
+                }
+
+                const fn unwrap_error(v: ::std::result::Result<(), Error>) -> Error {
+                    match v {
+                        // Unfortunately, we cannot use `unreachable!()` here,
+                        // as this branch will be executed either way.
+                        Ok(()) => Error {
+                            cause: Cause::RequiredField,
+                            base: ("unreachable", "unreachable", 1),
+                            implementation: ("unreachable", "unreachable", 1),
+                        },
+                        Err(e) => e,
+                    }
+                }
+
+                const fn check() -> Result<(), Error> {
+                    let mut base_i = 0;
+                    while base_i < BASE_ARGS.len() {
+                        let (base_name, base_type, base_wrap_val) = BASE_ARGS[base_i];
+
+                        let mut impl_i = 0;
+                        let mut was_found = false;
+                        while impl_i < IMPL_ARGS.len() {
+                            let (impl_name, impl_type, impl_wrap_val) = IMPL_ARGS[impl_i];
+
+                            if $crate::reflect::str_eq(base_name, impl_name) {
+                                if $crate::reflect::str_eq(base_type, impl_type)
+                                    && base_wrap_val == impl_wrap_val
+                                {
+                                    was_found = true;
+                                    break;
+                                } else {
+                                    return Err(Error {
+                                        cause: Cause::TypeMismatch,
+                                        base: (base_name, base_type, base_wrap_val),
+                                        implementation: (impl_name, impl_type, impl_wrap_val),
+                                    });
+                                }
+                            }
+
+                            impl_i += 1;
+                        }
+
+                        if !was_found {
+                            return Err(Error {
+                                cause: Cause::RequiredField,
+                                base: (base_name, base_type, base_wrap_val),
+                                implementation: (base_name, base_type, base_wrap_val),
+                            });
+                        }
+
+                        base_i += 1;
+                    }
+
+                    let mut impl_i = 0;
+                    while impl_i < IMPL_ARGS.len() {
+                        let (impl_name, impl_type, impl_wrapped_val) = IMPL_ARGS[impl_i];
+                        impl_i += 1;
+
+                        if impl_wrapped_val % 10 == 2 {
+                            continue;
+                        }
+
+                        let mut base_i = 0;
+                        let mut was_found = false;
+                        while base_i < BASE_ARGS.len() {
+                            let (base_name, _, _) = BASE_ARGS[base_i];
+                            if $crate::reflect::str_eq(base_name, impl_name) {
+                                was_found = true;
+                                break;
+                            }
+                            base_i += 1;
+                        }
+                        if !was_found {
+                            return Err(Error {
+                                cause: Cause::AdditionalNonNullableField,
+                                base: (impl_name, impl_type, impl_wrapped_val),
+                                implementation: (impl_name, impl_type, impl_wrapped_val),
+                            });
+                        }
+                    }
+
+                    Ok(())
+                }
+
+                const RES: ::std::result::Result<(), Error> = check();
+                if RES.is_err() {
+                    const ERROR: Error = unwrap_error(RES);
+
+                    const BASE_ARG_NAME: $crate::reflect::Name = ERROR.base.0;
+                    const IMPL_ARG_NAME: $crate::reflect::Name = ERROR.implementation.0;
+
+                    const BASE_TYPE_FORMATTED: &str =
+                        $crate::reflect::format_type!(ERROR.base.1, ERROR.base.2,);
+                    const IMPL_TYPE_FORMATTED: &str = $crate::reflect::format_type!(
+                        ERROR.implementation.1,
+                        ERROR.implementation.2,
+                    );
+
+                    const MSG: &str = match ERROR.cause {
+                        Cause::TypeMismatch => {
+                            $crate::reflect::const_concat!(
+                                "Argument `",
+                                BASE_ARG_NAME,
+                                "`: expected type `",
+                                BASE_TYPE_FORMATTED,
+                                "`, found: `",
+                                IMPL_TYPE_FORMATTED,
+                                "`.",
+                            )
+                        }
+                        Cause::RequiredField => {
+                            $crate::reflect::const_concat!(
+                                "Argument `",
+                                BASE_ARG_NAME,
+                                "` of type `",
+                                BASE_TYPE_FORMATTED,
+                                "` was expected, but not found.",
+                            )
+                        }
+                        Cause::AdditionalNonNullableField => {
+                            $crate::reflect::const_concat!(
+                                "Argument `",
+                                IMPL_ARG_NAME,
+                                "` of type `",
+                                IMPL_TYPE_FORMATTED,
+                                "` isn't present on the interface and so has to be nullable.",
+                            )
+                        }
+                    };
+                    const ERROR_MSG: &str = $crate::reflect::const_concat!(
+                        ERR_PREFIX, "Field `", FIELD_NAME, "`: ", MSG,
+                    );
+                    ::std::panic!("{}", ERROR_MSG);
+                }
+            };
+        };
+    }
+
+    /// Ensures that the given `$impl_ty` has the specified [`Field`].
+    ///
+    /// [`Field`]: super::Field
+    /// [`fnv1a128`]: super::fnv1a128
+    macro_rules! assert_has_field {
+        (
+            $field_name: expr,
+            $impl_ty: ty,
+            $behavior: ty
+            $(, $prefix: expr)? $(,)?
+        ) => {{
+            let exists = $crate::reflect::str_exists_in_arr(
+                $field_name,
+                <$impl_ty as $crate::reflect::Fields<$behavior>>::NAMES,
+            );
+            if !exists {
+                const MSG: &str = $crate::reflect::const_concat!(
+                    $($prefix,)?
+                    "Field `",
+                    $field_name,
+                    "` isn't implemented on `",
+                    <$impl_ty as $crate::reflect::BaseType<$behavior>>::NAME,
+                    "`."
+                );
+                ::std::panic!("{}", MSG);
+            }
+        }};
+    }
+
+    /// Concatenates `const` [`str`](prim@str)s in a `const` context.
+    macro_rules! const_concat {
+        ($($s:expr),* $(,)?) => {{
+            const LEN: usize = 0 $(+ $s.as_bytes().len())*;
+            const CNT: usize = [$($s),*].len();
+            const fn concat(input: [&str; CNT]) -> [u8; LEN] {
+                let mut bytes = [0; LEN];
+                let (mut i, mut byte) = (0, 0);
+                while i < CNT {
+                    let mut b = 0;
+                    while b < input[i].len() {
+                        bytes[byte] = input[i].as_bytes()[b];
+                        byte += 1;
+                        b += 1;
+                    }
+                    i += 1;
+                }
+                bytes
+            }
+            const CON: [u8; LEN] = concat([$($s),*]);
+
+            // TODO: Use `str::from_utf8()` once it becomes `const`.
+            // SAFETY: This is safe, as we concatenate multiple UTF-8 strings
+            //         one after another byte-by-byte.
+            #[allow(unsafe_code)]
+            unsafe { ::std::str::from_utf8_unchecked(&CON) }
+        }};
+    }
+
+    /// Formats the given [`Type`] and [`WrappedValue`] into a human-readable
+    /// GraphQL type name string.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use juniper::reflect::format_type;
+    /// #
+    /// assert_eq!(format_type!("String", 123), "[String]!");
+    /// assert_eq!(format_type!("🦀", 123), "[🦀]!");
+    /// ```
+    ///
+    /// [`Type`]: super::Type
+    /// [`WrappedValue`]: super::WrappedValue
+    macro_rules! format_type {
+        ($ty: expr, $wrapped_value: expr $(,)?) => {{
+            const TYPE: ($crate::reflect::Type, $crate::reflect::WrappedValue) =
+                ($ty, $wrapped_value);
+            const RES_LEN: usize = $crate::reflect::type_len_with_wrapped_val(TYPE.0, TYPE.1);
+
+            const OPENING_BRACKET: &str = "[";
+            const CLOSING_BRACKET: &str = "]";
+            const BANG: &str = "!";
+
+            const fn format_type_arr() -> [u8; RES_LEN] {
+                let (ty, wrap_val) = TYPE;
+                let mut type_arr: [u8; RES_LEN] = [0; RES_LEN];
+
+                let mut current_start = 0;
+                let mut current_end = RES_LEN - 1;
+                let mut current_wrap_val = wrap_val;
+                let mut is_null = false;
+                while current_wrap_val % 10 != 0 {
+                    match current_wrap_val % 10 {
+                        2 => is_null = true, // Skips writing `BANG` later.
+                        3 => {
+                            // Write `OPENING_BRACKET` at `current_start`.
+                            let mut i = 0;
+                            while i < OPENING_BRACKET.as_bytes().len() {
+                                type_arr[current_start + i] = OPENING_BRACKET.as_bytes()[i];
+                                i += 1;
+                            }
+                            current_start += i;
+                            if !is_null {
+                                // Write `BANG` at `current_end`.
+                                i = 0;
+                                while i < BANG.as_bytes().len() {
+                                    type_arr[current_end - BANG.as_bytes().len() + i + 1] =
+                                        BANG.as_bytes()[i];
+                                    i += 1;
+                                }
+                                current_end -= i;
+                            }
+                            // Write `CLOSING_BRACKET` at `current_end`.
+                            i = 0;
+                            while i < CLOSING_BRACKET.as_bytes().len() {
+                                type_arr[current_end - CLOSING_BRACKET.as_bytes().len() + i + 1] =
+                                    CLOSING_BRACKET.as_bytes()[i];
+                                i += 1;
+                            }
+                            current_end -= i;
+                            is_null = false;
+                        }
+                        _ => {}
+                    }
+
+                    current_wrap_val /= 10;
+                }
+
+                // Writes `Type` at `current_start`.
+                let mut i = 0;
+                while i < ty.as_bytes().len() {
+                    type_arr[current_start + i] = ty.as_bytes()[i];
+                    i += 1;
+                }
+                i = 0;
+                if !is_null {
+                    // Writes `BANG` at `current_end`.
+                    while i < BANG.as_bytes().len() {
+                        type_arr[current_end - BANG.as_bytes().len() + i + 1] = BANG.as_bytes()[i];
+                        i += 1;
+                    }
+                }
+
+                type_arr
+            }
+
+            const TYPE_ARR: [u8; RES_LEN] = format_type_arr();
+
+            // TODO: Use `str::from_utf8()` once it becomes `const`.
+            // SAFETY: This is safe, as we concatenate multiple UTF-8 strings one
+            //         after another byte-by-byte.
+            #[allow(unsafe_code)]
+            const TYPE_FORMATTED: &str =
+                unsafe { ::std::str::from_utf8_unchecked(TYPE_ARR.as_slice()) };
+            TYPE_FORMATTED
+        }};
+    }
+
+    #[doc(inline)]
+    pub(super) use {
+        assert_field, assert_field_args, assert_field_type, assert_has_field,
+        assert_implemented_for, assert_interfaces_impls, checked_hash, const_concat, format_type,
+    };
+}
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 8e823117e..fa32f9e53 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -2,7 +2,7 @@ use crate::{
     behavior, graphql,
     meta::MetaType,
     parser::{self, ParseError},
-    Arguments, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry, Selection,
+    reflect, Arguments, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry, Selection,
 };
 
 #[doc(inline)]
@@ -100,6 +100,22 @@ pub trait Field<
     ) -> ExecutionResult<ScalarValue>;
 }
 
+pub trait StaticField<
+    const N: reflect::FieldName,
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
+    fn resolve_static_field(
+        &self,
+        arguments: &Arguments<ScalarValue>,
+        type_info: &TypeInfo,
+        executor: &Executor<Context, ScalarValue>,
+    ) -> ExecutionResult<ScalarValue>;
+}
+
 pub trait FieldAsync<
     TypeInfo: ?Sized,
     Context: ?Sized,
@@ -116,6 +132,22 @@ pub trait FieldAsync<
     ) -> BoxFuture<'r, ExecutionResult<ScalarValue>>;
 }
 
+pub trait StaticFieldAsync<
+    const N: reflect::FieldName,
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
+    fn resolve_static_field_async<'r>(
+        &'r self,
+        arguments: &'r Arguments<ScalarValue>,
+        type_info: &'r TypeInfo,
+        executor: &'r Executor<Context, ScalarValue>,
+    ) -> BoxFuture<'r, ExecutionResult<ScalarValue>>;
+}
+
 pub trait ToInputValue<ScalarValue, Behavior: ?Sized = behavior::Standard> {
     fn to_input_value(&self) -> graphql::InputValue<ScalarValue>;
 }

From b716a45215e5a11ed5bff5b6d7599179a3d5284e Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 7 Jun 2022 18:53:01 +0200
Subject: [PATCH 19/58] Refactor `input_value!` macro position [skip ci]

---
 juniper/src/graphql/mod.rs                    | 101 +++---
 juniper/src/lib.rs                            |   5 +-
 ...{graphql_input_value.rs => input_value.rs} | 296 +++++++++---------
 juniper/src/macros/mod.rs                     |   6 +-
 4 files changed, 213 insertions(+), 195 deletions(-)
 rename juniper/src/macros/{graphql_input_value.rs => input_value.rs} (59%)

diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 8c3d3b660..3deea79c7 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -1,67 +1,88 @@
+use crate::{behavior, resolve};
+
 pub use crate::{
-    ast::InputValue, graphql_input_value as input_value, graphql_value as value, value::Value,
+    ast::InputValue, graphql_value as value, macros::input_value,
+    resolve::Type, value::Value,
 };
 
-pub trait Interface<S>:
-    OutputType<S>
-/*
-    + resolve::TypeName
-    + resolve::ConcreteTypeName
-    + resolve::Value<S>
-    + resolve::ValueAsync<S>
-    + resolve::ConcreteValue<S>
-    + resolve::ConcreteValueAsync<S>
-    + resolve::Field<S>
-    + resolve::FieldAsync<S>
+pub trait Interface<S>
+/*: OutputType<S>
+   + resolve::TypeName
+   + resolve::ConcreteTypeName
+   + resolve::Value<S>
+   + resolve::ValueAsync<S>
+   + resolve::ConcreteValue<S>
+   + resolve::ConcreteValueAsync<S>
+   + resolve::Field<S>
+   + resolve::FieldAsync<S>
 
- */
+*/
 {
     fn assert_interface();
 }
 
-pub trait Object<S>:
-    OutputType<S>
-/*
-    + resolve::TypeName
-    + resolve::ConcreteTypeName
-    + resolve::Value<S>
-    + resolve::ValueAsync<S>
-    + resolve::Field<S>
-    + resolve::FieldAsync<S>
+pub trait Object<S>
+/*: OutputType<S>
+   + resolve::TypeName
+   + resolve::ConcreteTypeName
+   + resolve::Value<S>
+   + resolve::ValueAsync<S>
+   + resolve::Field<S>
+   + resolve::FieldAsync<S>
 
- */
+*/
 {
     fn assert_object();
 }
 
-pub trait Scalar<S>:
-    OutputType<S> + /*
-    resolve::TypeName + resolve::Value<S> + resolve::ValueAsync<S> */
+pub trait Scalar<
+    'inp,
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue: 'inp,
+    Behavior: ?Sized = behavior::Standard,
+>:
+    InputType<'inp, TypeInfo, ScalarValue, Behavior>
+    + OutputType<TypeInfo, Context, ScalarValue, Behavior>
+    + resolve::ScalarToken<ScalarValue, Behavior>
 {
     fn assert_scalar();
 }
 
-pub trait Union<S>:
-    OutputType<S>
-/*
-    + resolve::TypeName
-    + resolve::ConcreteTypeName
-    + resolve::Value<S>
-    + resolve::ValueAsync<S>
-    + resolve::ConcreteValue<S>
-    + resolve::ConcreteValueAsync<S> */
+pub trait Union<S>
+/*: OutputType<S>
++ resolve::TypeName
++ resolve::ConcreteTypeName
++ resolve::Value<S>
++ resolve::ValueAsync<S>
++ resolve::ConcreteValue<S>
++ resolve::ConcreteValueAsync<S> */
 {
     fn assert_union();
 }
 
-pub trait InputType<'inp, Info: ?Sized, S: 'inp> /*:
-    crate::resolve::Type<Info, S>
-    + crate::resolve::ToInputValue<S>
-    + crate::resolve::InputValue<'inp, S>*/
+pub trait InputType<
+    'inp,
+    TypeInfo: ?Sized,
+    ScalarValue: 'inp,
+    Behavior: ?Sized = behavior::Standard,
+>:
+    Type<TypeInfo, ScalarValue, Behavior>
+    + resolve::ToInputValue<ScalarValue, Behavior>
+    + resolve::InputValue<'inp, ScalarValue, Behavior>
 {
     fn assert_input_type();
 }
 
-pub trait OutputType<S>: /*Type<S>*/ {
+pub trait OutputType<
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>:
+    Type<TypeInfo, ScalarValue, Behavior>
+    + resolve::Value<TypeInfo, Context, ScalarValue, Behavior>
+    + resolve::ValueAsync<TypeInfo, Context, ScalarValue, Behavior>
+{
     fn assert_output_type();
 }
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 04ac5d69c..ea55733f8 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -74,7 +74,10 @@ pub use crate::{
         LookAheadSelection, LookAheadValue, OwnedExecutor, Registry, ValuesStream, Variables,
     },
     introspection::IntrospectionFormat,
-    macros::helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
+    macros::{
+        input_value as graphql_input_value,
+        helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
+    },
     parser::{ParseError, ScalarToken, Spanning},
     schema::{
         meta,
diff --git a/juniper/src/macros/graphql_input_value.rs b/juniper/src/macros/input_value.rs
similarity index 59%
rename from juniper/src/macros/graphql_input_value.rs
rename to juniper/src/macros/input_value.rs
index 69641e376..0edc06002 100644
--- a/juniper/src/macros/graphql_input_value.rs
+++ b/juniper/src/macros/input_value.rs
@@ -1,45 +1,43 @@
-//! [`graphql_input_value!`] macro implementation.
-//!
-//! [`graphql_input_value!`]: graphql_input_value
+//! [`input_value!`] macro implementation.
 
-/// Constructs [`InputValue`]s via JSON-like syntax.
+/// Constructs [`graphql::InputValue`]s via JSON-like syntax.
 ///
 /// # Differences from [`graphql_value!`]
 ///
 /// - [`InputValue::Enum`] is constructed with `ident`, so to capture outer
 ///   variable as [`InputValue::Scalar`] surround it with parens: `(var)`.
 /// ```rust
-/// # use juniper::{graphql_input_value, graphql_value};
+/// # use juniper::{graphql, graphql_value};
 /// #
-/// # type InputValue = juniper::InputValue;
-/// # type Value = juniper::Value;
+/// # type InputValue = graphql::InputValue;
+/// # type Value = graphql::Value;
 /// #
 /// const OUTER_VAR: i32 = 42;
-/// assert_eq!(graphql_value!(OUTER_VAR), Value::scalar(42));
-/// assert_eq!(graphql_input_value!(OUTER_VAR), InputValue::enum_value("OUTER_VAR"));
-/// assert_eq!(graphql_input_value!((OUTER_VAR)), InputValue::scalar(42));
+/// assert_eq!(graphql::value!(OUTER_VAR), Value::scalar(42));
+/// assert_eq!(graphql::input_value!(OUTER_VAR), InputValue::enum_value("OUTER_VAR"));
+/// assert_eq!(graphql::input_value!((OUTER_VAR)), InputValue::scalar(42));
 /// ```
 ///
 /// - [`InputValue::Variable`] is constructed by prefixing `ident` with `@`.
 /// ```rust
-/// # use juniper::graphql_input_value;
+/// # use juniper::graphql;
 /// #
-/// # type InputValue = juniper::InputValue;
+/// # type InputValue = graphql::InputValue;
 /// #
-/// assert_eq!(graphql_input_value!(@var), InputValue::variable("var"));
+/// assert_eq!(graphql::input_value!(@var), InputValue::variable("var"));
 /// ```
 ///
 /// - [`InputValue::Object`] key should implement [`Into`]`<`[`String`]`>`.
 /// ```rust
 /// # use std::borrow::Cow;
 /// #
-/// # use juniper::{graphql_input_value, InputValue};
+/// # use juniper::graphql;
 /// #
 /// let code = 200;
 /// let features = vec!["key", "value"];
 /// let key: Cow<'static, str> = "key".into();
 ///
-/// let value: InputValue = graphql_input_value!({
+/// let value: graphql::InputValue = graphql::input_value!({
 ///     "code": code,
 ///     "success": code == 200,
 ///     "payload": {
@@ -55,128 +53,127 @@
 /// # Example
 ///
 /// ```rust
-/// # use juniper::{graphql_input_value, InputValue};
+/// # use juniper::graphql;
 /// #
-/// # type V = InputValue;
+/// # type V = graphql::InputValue;
 /// #
 /// # let _: V =
-/// graphql_input_value!(null);
+/// graphql::input_value!(null);
 /// # let _: V =
-/// graphql_input_value!(1234);
+/// graphql::input_value!(1234);
 /// # let _: V =
-/// graphql_input_value!("test");
+/// graphql::input_value!("test");
 /// # let _: V =
-/// graphql_input_value!([1234, "test", true]);
+/// graphql::input_value!([1234, "test", true]);
 /// # let _: V =
-/// graphql_input_value!({"key": "value", "foo": 1234});
+/// graphql::input_value!({"key": "value", "foo": 1234});
 /// # let _: V =
-/// graphql_input_value!({"key": ENUM});
+/// graphql::input_value!({"key": ENUM});
 /// let captured_var = 42;
 /// # let _: V =
-/// graphql_input_value!({"key": (captured_var)});
+/// graphql::input_value!({"key": (captured_var)});
 /// # let _: V =
-/// graphql_input_value!({"key": @variable});
+/// graphql::input_value!({"key": @variable});
 /// ```
 ///
-/// [`InputValue`]: crate::InputValue
-/// [`InputValue::Enum`]: crate::InputValue::Enum
-/// [`InputValue::List`]: crate::InputValue::List
-/// [`InputValue::Object`]: crate::InputValue::Object
-/// [`InputValue::Scalar`]: crate::InputValue::Scalar
-/// [`InputValue::Variable`]: crate::InputValue::Variable
+/// [`graphql::InputValue`]: crate::graphql::InputValue
+/// [`InputValue::Enum`]: crate::graphql::InputValue::Enum
+/// [`InputValue::List`]: crate::graphql::InputValue::List
+/// [`InputValue::Object`]: crate::graphql::InputValue::Object
+/// [`InputValue::Scalar`]: crate::graphql::InputValue::Scalar
+/// [`InputValue::Variable`]: crate::graphql::InputValue::Variable
 /// [`Spanning::unlocated`]: crate::Spanning::unlocated
-#[macro_export]
-macro_rules! graphql_input_value {
+macro_rules! input_value {
     ///////////
     // Array //
     ///////////
 
     // Done with trailing comma.
     (@@array [$($elems:expr,)*]) => {
-        $crate::InputValue::list(vec![
+        $crate::graphql::InputValue::list(::std::vec![
             $( $elems, )*
         ])
     };
 
     // Done without trailing comma.
     (@@array [$($elems:expr),*]) => {
-        $crate::InputValue::list(vec![
+        $crate::graphql::InputValue::list(::std::vec![
             $( $elems, )*
         ])
     };
 
     // Next element is `null`.
     (@@array [$($elems:expr,)*] null $($rest:tt)*) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!(null)] $($rest)*
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!(null)] $($rest)*
         )
     };
 
     // Next element is `None`.
     (@@array [$($elems:expr,)*] None $($rest:tt)*) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!(None)] $($rest)*
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!(None)] $($rest)*
         )
     };
 
     // Next element is a variable.
     (@@array [$($elems:expr,)*] @$var:ident $($rest:tt)*) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!(@$var)] $($rest)*
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!(@$var)] $($rest)*
         )
     };
 
 
     // Next element is an array.
     (@@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!([$($array)*])] $($rest)*
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!([$($array)*])] $($rest)*
         )
     };
 
     // Next element is a map.
     (@@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!({$($map)*})] $($rest)*
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!({$($map)*})] $($rest)*
         )
     };
 
     // Next element is `true`, `false` or enum ident followed by comma.
     (@@array [$($elems:expr,)*] $ident:ident, $($rest:tt)*) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!($ident),] $($rest)*
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!($ident),] $($rest)*
         )
     };
 
     // Next element is `true`, `false` or enum ident without trailing comma.
     (@@array [$($elems:expr,)*] $last:ident ) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!($last)]
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!($last)]
         )
     };
 
     // Next element is an expression followed by comma.
     (@@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!($next),] $($rest)*
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!($next),] $($rest)*
         )
     };
 
     // Last element is an expression with no trailing comma.
     (@@array [$($elems:expr,)*] $last:expr) => {
-        $crate::graphql_input_value!(
-            @@array [$($elems,)* $crate::graphql_input_value!($last)]
+        $crate::graphql::input_value!(
+            @@array [$($elems,)* $crate::graphql::input_value!($last)]
         )
     };
 
     // Comma after the most recent element.
     (@@array [$($elems:expr),*] , $($rest:tt)*) => {
-        $crate::graphql_input_value!(@@array [$($elems,)*] $($rest)*)
+        $crate::graphql::input_value!(@@array [$($elems,)*] $($rest)*)
     };
 
     // Unexpected token after most recent element.
     (@@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
-        $crate::graphql_input_value!(@unexpected $unexpected)
+        $crate::graphql::input_value!(@unexpected $unexpected)
     };
 
     ////////////
@@ -192,12 +189,12 @@ macro_rules! graphql_input_value {
             $crate::Spanning::unlocated(($($key)+).into()),
             $crate::Spanning::unlocated($value),
         ));
-        $crate::graphql_input_value!(@@object $object () ($($rest)*) ($($rest)*));
+        $crate::graphql::input_value!(@@object $object () ($($rest)*) ($($rest)*));
     };
 
     // Current entry followed by unexpected token.
     (@@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
-        $crate::graphql_input_value!(@unexpected $unexpected);
+        $crate::graphql::input_value!(@unexpected $unexpected);
     };
 
     // Insert the last entry without trailing comma.
@@ -210,114 +207,114 @@ macro_rules! graphql_input_value {
 
     // Next value is `null`.
     (@@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!(null)) $($rest)*
+            ($crate::graphql::input_value!(null)) $($rest)*
         );
     };
 
     // Next value is `None`.
     (@@object $object:ident ($($key:tt)+) (: None $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!(None)) $($rest)*
+            ($crate::graphql::input_value!(None)) $($rest)*
         );
     };
 
     // Next value is a variable.
     (@@object $object:ident ($($key:tt)+) (: @$var:ident $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!(@$var)) $($rest)*
+            ($crate::graphql::input_value!(@$var)) $($rest)*
         );
     };
 
     // Next value is an array.
     (@@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!([$($array)*])) $($rest)*
+            ($crate::graphql::input_value!([$($array)*])) $($rest)*
         );
     };
 
     // Next value is a map.
     (@@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!({$($map)*})) $($rest)*
+            ($crate::graphql::input_value!({$($map)*})) $($rest)*
         );
     };
 
     // Next value is `true`, `false` or enum ident followed by comma.
     (@@object $object:ident ($($key:tt)+) (: $ident:ident , $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!($ident)) , $($rest)*
+            ($crate::graphql::input_value!($ident)) , $($rest)*
         );
     };
 
     // Next value is `true`, `false` or enum ident without trailing comma.
     (@@object $object:ident ($($key:tt)+) (: $last:ident ) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!($last))
+            ($crate::graphql::input_value!($last))
         );
     };
 
     // Next value is an expression followed by comma.
     (@@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!($value)) , $($rest)*
+            ($crate::graphql::input_value!($value)) , $($rest)*
         );
     };
 
     // Last value is an expression with no trailing comma.
     (@@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             [$($key)+]
-            ($crate::graphql_input_value!($value))
+            ($crate::graphql::input_value!($value))
         );
     };
 
     // Missing value for last entry. Trigger a reasonable error message.
     (@@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
         // "unexpected end of macro invocation"
-        $crate::graphql_input_value!();
+        $crate::graphql::input_value!();
     };
 
     // Missing colon and value for last entry. Trigger a reasonable error
     // message.
     (@@object $object:ident ($($key:tt)+) () $copy:tt) => {
         // "unexpected end of macro invocation"
-        $crate::graphql_input_value!();
+        $crate::graphql::input_value!();
     };
 
     // Misplaced colon. Trigger a reasonable error message.
     (@@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
         // Takes no arguments so "no rules expected the token `:`".
-        $crate::graphql_input_value!(@unexpected $colon);
+        $crate::graphql::input_value!(@unexpected $colon);
     };
 
     // Found a comma inside a key. Trigger a reasonable error message.
     (@@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
         // Takes no arguments so "no rules expected the token `,`".
-        $crate::graphql_input_value!(@unexpected $comma);
+        $crate::graphql::input_value!(@unexpected $comma);
     };
 
     // Key is fully parenthesized. This avoids `clippy::double_parens` false
     // positives because the parenthesization may be necessary here.
     (@@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             ($key)
             (: $($rest)*) (: $($rest)*)
@@ -326,12 +323,12 @@ macro_rules! graphql_input_value {
 
     // Refuse to absorb colon token into key expression.
     (@@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => {
-        $crate::graphql_input_value!(@@unexpected $($unexpected)+);
+        $crate::graphql::input_value!(@@unexpected $($unexpected)+);
     };
 
     // Munch a token into the current key.
     (@@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_input_value!(
+        $crate::graphql::input_value!(
             @@object $object
             ($($key)* $tt)
             ($($rest)*) ($($rest)*)
@@ -349,109 +346,107 @@ macro_rules! graphql_input_value {
     //////////////
 
     ([ $($arr:tt)* ]$(,)?) => {
-        $crate::graphql_input_value!(@@array [] $($arr)*)
+        $crate::graphql::input_value!(@@array [] $($arr)*)
     };
 
     ({}$(,)?) => {
-        $crate::InputValue::parsed_object(vec![])
+        $crate::graphql::InputValue::parsed_object(vec![])
     };
 
     ({ $($map:tt)+ }$(,)?) => {
-        $crate::InputValue::parsed_object({
+        $crate::graphql::InputValue::parsed_object({
             let mut object = vec![];
-            $crate::graphql_input_value!(@@object object () ($($map)*) ($($map)*));
+            $crate::graphql::input_value!(@@object object () ($($map)*) ($($map)*));
             object
         })
     };
 
-    (null$(,)?) => ($crate::InputValue::null());
+    (null$(,)?) => ($crate::graphql::InputValue::null());
 
-    (None$(,)?) => ($crate::InputValue::null());
+    (None$(,)?) => ($crate::graphql::InputValue::null());
 
-    (true$(,)?) => ($crate::InputValue::from(true));
+    (true$(,)?) => ($crate::graphql::InputValue::from(true));
 
-    (false$(,)?) => ($crate::InputValue::from(false));
+    (false$(,)?) => ($crate::graphql::InputValue::from(false));
 
-    (@$var:ident$(,)?) => ($crate::InputValue::variable(stringify!($var)));
+    (@$var:ident$(,)?) => ($crate::graphql::InputValue::variable(stringify!($var)));
 
-    ($enum:ident$(,)?) => ($crate::InputValue::enum_value(stringify!($enum)));
+    ($enum:ident$(,)?) => ($crate::graphql::InputValue::enum_value(stringify!($enum)));
 
-    (($e:expr)$(,)?) => ($crate::InputValue::from($e));
+    (($e:expr)$(,)?) => ($crate::graphql::InputValue::from($e));
 
-    ($e:expr$(,)?) => ($crate::InputValue::from($e));
+    ($e:expr$(,)?) => ($crate::graphql::InputValue::from($e));
 }
 
+#[doc(inline)]
+pub(super) use input_value;
+
 #[cfg(test)]
 mod tests {
     use indexmap::{indexmap, IndexMap};
 
-    type V = crate::InputValue;
+    use crate::graphql;
+
+    use super::input_value;
+
+    type V = graphql::InputValue;
 
     #[test]
     fn null() {
-        assert_eq!(graphql_input_value!(null), V::Null);
+        assert_eq!(input_value!(null), V::Null);
     }
 
     #[test]
     fn scalar() {
         let val = 42;
-        assert_eq!(graphql_input_value!(1), V::scalar(1));
-        assert_eq!(graphql_input_value!("val"), V::scalar("val"));
-        assert_eq!(graphql_input_value!(1.34), V::scalar(1.34));
-        assert_eq!(graphql_input_value!(false), V::scalar(false));
-        assert_eq!(graphql_input_value!(1 + 2), V::scalar(3));
-        assert_eq!(graphql_input_value!((val)), V::scalar(42));
+        assert_eq!(input_value!(1), V::scalar(1));
+        assert_eq!(input_value!("val"), V::scalar("val"));
+        assert_eq!(input_value!(1.34), V::scalar(1.34));
+        assert_eq!(input_value!(false), V::scalar(false));
+        assert_eq!(input_value!(1 + 2), V::scalar(3));
+        assert_eq!(input_value!((val)), V::scalar(42));
     }
 
     #[test]
     fn r#enum() {
-        assert_eq!(graphql_input_value!(ENUM), V::enum_value("ENUM"));
-        assert_eq!(graphql_input_value!(lowercase), V::enum_value("lowercase"));
+        assert_eq!(input_value!(ENUM), V::enum_value("ENUM"));
+        assert_eq!(input_value!(lowercase), V::enum_value("lowercase"));
     }
 
     #[test]
     fn variable() {
-        assert_eq!(graphql_input_value!(@var), V::variable("var"));
-        assert_eq!(graphql_input_value!(@array), V::variable("array"));
-        assert_eq!(graphql_input_value!(@object), V::variable("object"));
+        assert_eq!(input_value!(@var), V::variable("var"));
+        assert_eq!(input_value!(@array), V::variable("array"));
+        assert_eq!(input_value!(@object), V::variable("object"));
     }
 
     #[test]
     fn list() {
         let val = 42;
 
-        assert_eq!(graphql_input_value!([]), V::list(vec![]));
+        assert_eq!(input_value!([]), V::list(vec![]));
 
-        assert_eq!(graphql_input_value!([null]), V::list(vec![V::Null]));
+        assert_eq!(input_value!([null]), V::list(vec![V::Null]));
 
-        assert_eq!(graphql_input_value!([1]), V::list(vec![V::scalar(1)]));
-        assert_eq!(graphql_input_value!([1 + 2]), V::list(vec![V::scalar(3)]));
-        assert_eq!(graphql_input_value!([(val)]), V::list(vec![V::scalar(42)]));
+        assert_eq!(input_value!([1]), V::list(vec![V::scalar(1)]));
+        assert_eq!(input_value!([1 + 2]), V::list(vec![V::scalar(3)]));
+        assert_eq!(input_value!([(val)]), V::list(vec![V::scalar(42)]));
 
+        assert_eq!(input_value!([ENUM]), V::list(vec![V::enum_value("ENUM")]));
         assert_eq!(
-            graphql_input_value!([ENUM]),
-            V::list(vec![V::enum_value("ENUM")]),
-        );
-        assert_eq!(
-            graphql_input_value!([lowercase]),
+            input_value!([lowercase]),
             V::list(vec![V::enum_value("lowercase")]),
         );
 
+        assert_eq!(input_value!([@var]), V::list(vec![V::variable("var")]),);
+        assert_eq!(input_value!([@array]), V::list(vec![V::variable("array")]));
         assert_eq!(
-            graphql_input_value!([@var]),
-            V::list(vec![V::variable("var")]),
-        );
-        assert_eq!(
-            graphql_input_value!([@array]),
-            V::list(vec![V::variable("array")]),
-        );
-        assert_eq!(
-            graphql_input_value!([@object]),
+            input_value!([@object]),
             V::list(vec![V::variable("object")]),
         );
 
         assert_eq!(
-            graphql_input_value!([1, [2], 3]),
+            input_value!([1, [2], 3]),
             V::list(vec![
                 V::scalar(1),
                 V::list(vec![V::scalar(2)]),
@@ -459,7 +454,7 @@ mod tests {
             ]),
         );
         assert_eq!(
-            graphql_input_value!([1, [2 + 3], 3]),
+            input_value!([1, [2 + 3], 3]),
             V::list(vec![
                 V::scalar(1),
                 V::list(vec![V::scalar(5)]),
@@ -467,7 +462,7 @@ mod tests {
             ]),
         );
         assert_eq!(
-            graphql_input_value!([1, [ENUM], (val)]),
+            input_value!([1, [ENUM], (val)]),
             V::list(vec![
                 V::scalar(1),
                 V::list(vec![V::enum_value("ENUM")]),
@@ -475,7 +470,7 @@ mod tests {
             ]),
         );
         assert_eq!(
-            graphql_input_value!([1 + 2, [(val)], @val]),
+            input_value!([1 + 2, [(val)], @val]),
             V::list(vec![
                 V::scalar(3),
                 V::list(vec![V::scalar(42)]),
@@ -483,7 +478,7 @@ mod tests {
             ]),
         );
         assert_eq!(
-            graphql_input_value!([1, [@val], ENUM]),
+            input_value!([1, [@val], ENUM]),
             V::list(vec![
                 V::scalar(1),
                 V::list(vec![V::variable("val")]),
@@ -495,68 +490,65 @@ mod tests {
     #[test]
     fn object() {
         let val = 42;
-        assert_eq!(
-            graphql_input_value!({}),
-            V::object(IndexMap::<String, _>::new()),
-        );
+        assert_eq!(input_value!({}), V::object(IndexMap::<String, _>::new()));
 
         assert_eq!(
-            graphql_input_value!({ "key": null }),
+            input_value!({ "key": null }),
             V::object(indexmap! {"key" => V::Null}),
         );
 
         assert_eq!(
-            graphql_input_value!({"key": 123}),
+            input_value!({"key": 123}),
             V::object(indexmap! {"key" => V::scalar(123)}),
         );
         assert_eq!(
-            graphql_input_value!({"key": 1 + 2}),
+            input_value!({"key": 1 + 2}),
             V::object(indexmap! {"key" => V::scalar(3)}),
         );
         assert_eq!(
-            graphql_input_value!({ "key": (val) }),
+            input_value!({ "key": (val) }),
             V::object(indexmap! {"key" => V::scalar(42)}),
         );
 
         assert_eq!(
-            graphql_input_value!({"key": []}),
+            input_value!({"key": []}),
             V::object(indexmap! {"key" => V::list(vec![])}),
         );
         assert_eq!(
-            graphql_input_value!({ "key": [null] }),
+            input_value!({ "key": [null] }),
             V::object(indexmap! {"key" => V::list(vec![V::Null])}),
         );
         assert_eq!(
-            graphql_input_value!({"key": [1] }),
+            input_value!({"key": [1] }),
             V::object(indexmap! {"key" => V::list(vec![V::scalar(1)])}),
         );
         assert_eq!(
-            graphql_input_value!({"key": [1 + 2] }),
+            input_value!({"key": [1 + 2] }),
             V::object(indexmap! {"key" => V::list(vec![V::scalar(3)])}),
         );
         assert_eq!(
-            graphql_input_value!({ "key": [(val)] }),
+            input_value!({ "key": [(val)] }),
             V::object(indexmap! {"key" => V::list(vec![V::scalar(42)])}),
         );
         assert_eq!(
-            graphql_input_value!({ "key": ENUM }),
+            input_value!({ "key": ENUM }),
             V::object(indexmap! {"key" => V::enum_value("ENUM")}),
         );
         assert_eq!(
-            graphql_input_value!({ "key": lowercase }),
+            input_value!({ "key": lowercase }),
             V::object(indexmap! {"key" => V::enum_value("lowercase")}),
         );
         assert_eq!(
-            graphql_input_value!({"key": @val}),
+            input_value!({"key": @val}),
             V::object(indexmap! {"key" => V::variable("val")}),
         );
         assert_eq!(
-            graphql_input_value!({"key": @array }),
+            input_value!({"key": @array }),
             V::object(indexmap! {"key" => V::variable("array")}),
         );
 
         assert_eq!(
-            graphql_input_value!({
+            input_value!({
                 "inner": {
                     "key1": (val),
                     "key2": "val",
@@ -606,8 +598,8 @@ mod tests {
     fn option() {
         let val = Some(42);
 
-        assert_eq!(graphql_input_value!(None), V::Null);
-        assert_eq!(graphql_input_value!(Some(42)), V::scalar(42));
-        assert_eq!(graphql_input_value!((val)), V::scalar(42));
+        assert_eq!(input_value!(None), V::Null);
+        assert_eq!(input_value!(Some(42)), V::scalar(42));
+        assert_eq!(input_value!((val)), V::scalar(42));
     }
 }
diff --git a/juniper/src/macros/mod.rs b/juniper/src/macros/mod.rs
index 4bbcfb5f6..ebde9761e 100644
--- a/juniper/src/macros/mod.rs
+++ b/juniper/src/macros/mod.rs
@@ -6,9 +6,11 @@ pub mod helper;
 #[macro_use]
 pub mod reflect;
 
-#[macro_use]
-mod graphql_input_value;
+mod input_value;
 #[macro_use]
 mod graphql_value;
 #[macro_use]
 mod graphql_vars;
+
+#[doc(inline)]
+pub use self::input_value::input_value;

From b28acbd96dbbfc665bcd87c47773da3cb99a9a91 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 7 Jun 2022 19:03:39 +0200
Subject: [PATCH 20/58] Refactor `value!` macro position [skip ci]

---
 juniper/src/graphql/mod.rs                    |   6 +-
 juniper/src/lib.rs                            |   2 +-
 juniper/src/macros/input_value.rs             |   2 +-
 juniper/src/macros/mod.rs                     |   5 +-
 .../src/macros/{graphql_value.rs => value.rs} | 185 +++++++++---------
 5 files changed, 103 insertions(+), 97 deletions(-)
 rename juniper/src/macros/{graphql_value.rs => value.rs} (62%)

diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 3deea79c7..5b02afb96 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -1,8 +1,10 @@
 use crate::{behavior, resolve};
 
 pub use crate::{
-    ast::InputValue, graphql_value as value, macros::input_value,
-    resolve::Type, value::Value,
+    ast::InputValue,
+    macros::{input_value, value},
+    resolve::Type,
+    value::Value,
 };
 
 pub trait Interface<S>
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index ea55733f8..70c514187 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -75,8 +75,8 @@ pub use crate::{
     },
     introspection::IntrospectionFormat,
     macros::{
-        input_value as graphql_input_value,
         helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
+        input_value as graphql_input_value, value as graphql_value,
     },
     parser::{ParseError, ScalarToken, Spanning},
     schema::{
diff --git a/juniper/src/macros/input_value.rs b/juniper/src/macros/input_value.rs
index 0edc06002..627b4f634 100644
--- a/juniper/src/macros/input_value.rs
+++ b/juniper/src/macros/input_value.rs
@@ -7,7 +7,7 @@
 /// - [`InputValue::Enum`] is constructed with `ident`, so to capture outer
 ///   variable as [`InputValue::Scalar`] surround it with parens: `(var)`.
 /// ```rust
-/// # use juniper::{graphql, graphql_value};
+/// # use juniper::graphql;
 /// #
 /// # type InputValue = graphql::InputValue;
 /// # type Value = graphql::Value;
diff --git a/juniper/src/macros/mod.rs b/juniper/src/macros/mod.rs
index ebde9761e..37bd0218d 100644
--- a/juniper/src/macros/mod.rs
+++ b/juniper/src/macros/mod.rs
@@ -7,10 +7,9 @@ pub mod helper;
 pub mod reflect;
 
 mod input_value;
-#[macro_use]
-mod graphql_value;
+mod value;
 #[macro_use]
 mod graphql_vars;
 
 #[doc(inline)]
-pub use self::input_value::input_value;
+pub use self::{input_value::input_value, value::value};
diff --git a/juniper/src/macros/graphql_value.rs b/juniper/src/macros/value.rs
similarity index 62%
rename from juniper/src/macros/graphql_value.rs
rename to juniper/src/macros/value.rs
index cc4e34d38..c689afa68 100644
--- a/juniper/src/macros/graphql_value.rs
+++ b/juniper/src/macros/value.rs
@@ -1,19 +1,18 @@
-//! [`graphql_value!`] macro implementation.
-//!
-//! [`graphql_value!`]: graphql_value
+//! [`value!`] macro implementation.
 
-/// Constructs [`Value`]s via JSON-like syntax.
+/// Constructs [`graphql::Value`]s via JSON-like syntax.
 ///
-/// [`Value`] objects are used mostly when creating custom errors from fields.
+/// [`graphql::Value`] objects are used mostly when creating custom errors from
+/// fields.
 ///
 /// [`Value::Object`] key should implement [`AsRef`]`<`[`str`]`>`.
 /// ```rust
-/// # use juniper::{graphql_value, Value};
+/// # use juniper::graphql;
 /// #
 /// let code = 200;
 /// let features = ["key", "value"];
 ///
-/// let value: Value = graphql_value!({
+/// let value: graphql::Value = graphql::value!({
 ///     "code": code,
 ///     "success": code == 200,
 ///     "payload": {
@@ -26,94 +25,93 @@
 ///
 /// Resulting JSON will look just like what you passed in.
 /// ```rust
-/// # use juniper::{graphql_value, DefaultScalarValue, Value};
+/// # use juniper::graphql;
 /// #
-/// # type V = Value<DefaultScalarValue>;
+/// # type V = graphql::Value;
 /// #
 /// # let _: V =
-/// graphql_value!(null);
+/// graphql::value!(null);
 /// # let _: V =
-/// graphql_value!(1234);
+/// graphql::value!(1234);
 /// # let _: V =
-/// graphql_value!("test");
+/// graphql::value!("test");
 /// # let _: V =
-/// graphql_value!([1234, "test", true]);
+/// graphql::value!([1234, "test", true]);
 /// # let _: V =
-/// graphql_value!({"key": "value", "foo": 1234});
+/// graphql::value!({"key": "value", "foo": 1234});
 /// ```
 ///
-/// [`Value`]: crate::Value
-/// [`Value::Object`]: crate::Value::Object
-#[macro_export]
-macro_rules! graphql_value {
+/// [`graphql::Value`]: crate::graphql::Value
+/// [`Value::Object`]: crate::graphql::Value::Object
+macro_rules! value {
     ///////////
     // Array //
     ///////////
 
     // Done with trailing comma.
     (@array [$($elems:expr,)*]) => {
-        $crate::Value::list(vec![
+        $crate::graphql::Value::list(::std::vec![
             $( $elems, )*
         ])
     };
 
     // Done without trailing comma.
     (@array [$($elems:expr),*]) => {
-        $crate::Value::list(vec![
-            $( $crate::graphql_value!($elems), )*
+        $crate::graphql::Value::list(::std::vec![
+            $( $crate::graphql::value!($elems), )*
         ])
     };
 
     // Next element is `null`.
     (@array [$($elems:expr,)*] null $($rest:tt)*) => {
-        $crate::graphql_value!(
-            @array [$($elems,)* $crate::graphql_value!(null)] $($rest)*
+        $crate::graphql::value!(
+            @array [$($elems,)* $crate::graphql::value!(null)] $($rest)*
         )
     };
 
     // Next element is `None`.
     (@array [$($elems:expr,)*] None $($rest:tt)*) => {
-        $crate::graphql_value!(
-            @array [$($elems,)* $crate::graphql_value!(None)] $($rest)*
+        $crate::graphql::value!(
+            @array [$($elems,)* $crate::graphql::value!(None)] $($rest)*
         )
     };
 
     // Next element is an array.
     (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
-        $crate::graphql_value!(
-            @array [$($elems,)* $crate::graphql_value!([$($array)*])] $($rest)*
+        $crate::graphql::value!(
+            @array [$($elems,)* $crate::graphql::value!([$($array)*])] $($rest)*
         )
     };
 
     // Next element is a map.
     (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
-        $crate::graphql_value!(
-            @array [$($elems,)* $crate::graphql_value!({$($map)*})] $($rest)*
+        $crate::graphql::value!(
+            @array [$($elems,)* $crate::graphql::value!({$($map)*})] $($rest)*
         )
     };
 
     // Next element is an expression followed by comma.
     (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
-        $crate::graphql_value!(
-            @array [$($elems,)* $crate::graphql_value!($next),] $($rest)*
+        $crate::graphql::value!(
+            @array [$($elems,)* $crate::graphql::value!($next),] $($rest)*
         )
     };
 
     // Last element is an expression with no trailing comma.
     (@array [$($elems:expr,)*] $last:expr) => {
-        $crate::graphql_value!(
-            @array [$($elems,)* $crate::graphql_value!($last)]
+        $crate::graphql::value!(
+            @array [$($elems,)* $crate::graphql::value!($last)]
         )
     };
 
     // Comma after the most recent element.
     (@array [$($elems:expr),*] , $($rest:tt)*) => {
-        $crate::graphql_value!(@array [$($elems,)*] $($rest)*)
+        $crate::graphql::value!(@array [$($elems,)*] $($rest)*)
     };
 
     // Unexpected token after most recent element.
     (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
-        $crate::graphql_value!(@unexpected $unexpected)
+        $crate::graphql::value!(@unexpected $unexpected)
     };
 
     ////////////
@@ -126,12 +124,12 @@ macro_rules! graphql_value {
     // Insert the current entry followed by trailing comma.
     (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
         let _ = $object.add_field(($($key)+), $value);
-        $crate::graphql_value!(@object $object () ($($rest)*) ($($rest)*));
+        $crate::graphql::value!(@object $object () ($($rest)*) ($($rest)*));
     };
 
     // Current entry followed by unexpected token.
     (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
-        $crate::graphql_value!(@unexpected $unexpected);
+        $crate::graphql::value!(@unexpected $unexpected);
     };
 
     // Insert the last entry without trailing comma.
@@ -141,97 +139,97 @@ macro_rules! graphql_value {
 
     // Next value is `null`.
     (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_value!(
+        $crate::graphql::value!(
             @object $object
             [$($key)+]
-            ($crate::graphql_value!(null)) $($rest)*
+            ($crate::graphql::value!(null)) $($rest)*
         );
     };
 
     // Next value is `None`.
     (@object $object:ident ($($key:tt)+) (: None $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_value!(
+        $crate::graphql::value!(
             @object $object
             [$($key)+]
-            ($crate::graphql_value!(None)) $($rest)*
+            ($crate::graphql::value!(None)) $($rest)*
         );
     };
 
     // Next value is an array.
     (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_value!(
+        $crate::graphql::value!(
             @object $object
             [$($key)+]
-            ($crate::graphql_value!([$($array)*])) $($rest)*
+            ($crate::graphql::value!([$($array)*])) $($rest)*
         );
     };
 
     // Next value is a map.
     (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_value!(
+        $crate::graphql::value!(
             @object $object
             [$($key)+]
-            ($crate::graphql_value!({$($map)*})) $($rest)*
+            ($crate::graphql::value!({$($map)*})) $($rest)*
         );
     };
 
     // Next value is an expression followed by comma.
     (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_value!(
+        $crate::graphql::value!(
             @object $object
             [$($key)+]
-            ($crate::graphql_value!($value)) , $($rest)*
+            ($crate::graphql::value!($value)) , $($rest)*
         );
     };
 
     // Last value is an expression with no trailing comma.
     (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
-        $crate::graphql_value!(
+        $crate::graphql::value!(
             @object $object
             [$($key)+]
-            ($crate::graphql_value!($value))
+            ($crate::graphql::value!($value))
         );
     };
 
     // Missing value for last entry. Trigger a reasonable error message.
     (@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
         // "unexpected end of macro invocation"
-        $crate::graphql_value!();
+        $crate::graphql::value!();
     };
 
     // Missing colon and value for last entry. Trigger a reasonable error
     // message.
     (@object $object:ident ($($key:tt)+) () $copy:tt) => {
         // "unexpected end of macro invocation"
-        $crate::graphql_value!();
+        $crate::graphql::value!();
     };
 
     // Misplaced colon. Trigger a reasonable error message.
     (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
         // Takes no arguments so "no rules expected the token `:`".
-        $crate::graphql_value!(@unexpected $colon);
+        $crate::graphql::value!(@unexpected $colon);
     };
 
     // Found a comma inside a key. Trigger a reasonable error message.
     (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
         // Takes no arguments so "no rules expected the token `,`".
-        $crate::graphql_value!(@unexpected $comma);
+        $crate::graphql::value!(@unexpected $comma);
     };
 
     // Key is fully parenthesized. This avoids `clippy::double_parens` false
     // positives because the parenthesization may be necessary here.
     (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_value!(@object $object ($key) (: $($rest)*) (: $($rest)*));
+        $crate::graphql::value!(@object $object ($key) (: $($rest)*) (: $($rest)*));
     };
 
     // Refuse to absorb colon token into key expression.
     (@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => {
-        $crate::graphql_value!(@unexpected $($unexpected)+);
+        $crate::graphql::value!(@unexpected $($unexpected)+);
     };
 
     // Munch a token into the current key.
     (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_value!(
+        $crate::graphql::value!(
             @object $object
             ($($key)* $tt)
             ($($rest)*) ($($rest)*)
@@ -249,63 +247,70 @@ macro_rules! graphql_value {
     //////////////
 
     ([ $($arr:tt)* ]$(,)?) => {
-        $crate::graphql_value!(@array [] $($arr)*)
+        $crate::graphql::value!(@array [] $($arr)*)
     };
 
     ({}$(,)?) => {
-        $crate::Value::object($crate::Object::with_capacity(0))
+        $crate::graphql::Value::object($crate::Object::with_capacity(0))
     };
 
     ({ $($map:tt)+ }$(,)?) => {
-        $crate::Value::object({
+        $crate::graphql::Value::object({
             let mut object = $crate::Object::with_capacity(0);
-            $crate::graphql_value!(@object object () ($($map)*) ($($map)*));
+            $crate::graphql::value!(@object object () ($($map)*) ($($map)*));
             object
         })
     };
 
-    (null$(,)?) => ($crate::Value::null());
+    (null$(,)?) => ($crate::graphql::Value::null());
 
-    (None$(,)?) => ($crate::Value::null());
+    (None$(,)?) => ($crate::graphql::Value::null());
 
-    ($e:expr$(,)?) => ($crate::Value::from($e));
+    ($e:expr$(,)?) => ($crate::graphql::Value::from($e));
 }
 
+#[doc(inline)]
+pub(super) use value;
+
 #[cfg(test)]
 mod tests {
-    type V = crate::Value;
+    use crate::graphql;
+
+    use super::value;
+
+    type V = graphql::Value;
 
     #[test]
     fn null() {
-        assert_eq!(graphql_value!(null), V::Null);
+        assert_eq!(value!(null), V::Null);
     }
 
     #[test]
     fn scalar() {
         let val = 42;
 
-        assert_eq!(graphql_value!(1), V::scalar(1));
-        assert_eq!(graphql_value!("val"), V::scalar("val"));
-        assert_eq!(graphql_value!(1.34), V::scalar(1.34));
-        assert_eq!(graphql_value!(false), V::scalar(false));
-        assert_eq!(graphql_value!(1 + 2), V::scalar(3));
-        assert_eq!(graphql_value!(val), V::scalar(42));
+        assert_eq!(value!(1), V::scalar(1));
+        assert_eq!(value!("val"), V::scalar("val"));
+        assert_eq!(value!(1.34), V::scalar(1.34));
+        assert_eq!(value!(false), V::scalar(false));
+        assert_eq!(value!(1 + 2), V::scalar(3));
+        assert_eq!(value!(val), V::scalar(42));
     }
 
     #[test]
     fn list() {
         let val = 42;
 
-        assert_eq!(graphql_value!([]), V::list(vec![]));
+        assert_eq!(value!([]), V::list(vec![]));
 
-        assert_eq!(graphql_value!([null]), V::list(vec![V::Null]));
+        assert_eq!(value!([null]), V::list(vec![V::Null]));
 
-        assert_eq!(graphql_value!([1]), V::list(vec![V::scalar(1)]));
-        assert_eq!(graphql_value!([1 + 2]), V::list(vec![V::scalar(3)]));
-        assert_eq!(graphql_value!([val]), V::list(vec![V::scalar(42)]));
+        assert_eq!(value!([1]), V::list(vec![V::scalar(1)]));
+        assert_eq!(value!([1 + 2]), V::list(vec![V::scalar(3)]));
+        assert_eq!(value!([val]), V::list(vec![V::scalar(42)]));
 
         assert_eq!(
-            graphql_value!([1, [2], 3]),
+            value!([1, [2], 3]),
             V::list(vec![
                 V::scalar(1),
                 V::list(vec![V::scalar(2)]),
@@ -313,7 +318,7 @@ mod tests {
             ]),
         );
         assert_eq!(
-            graphql_value!(["string", [2 + 3], true]),
+            value!(["string", [2 + 3], true]),
             V::list(vec![
                 V::scalar("string"),
                 V::list(vec![V::scalar(5)]),
@@ -327,31 +332,31 @@ mod tests {
         let val = 42;
 
         assert_eq!(
-            graphql_value!({}),
+            value!({}),
             V::object(Vec::<(String, _)>::new().into_iter().collect()),
         );
         assert_eq!(
-            graphql_value!({ "key": null }),
+            value!({ "key": null }),
             V::object(vec![("key", V::Null)].into_iter().collect()),
         );
         assert_eq!(
-            graphql_value!({ "key": 123 }),
+            value!({ "key": 123 }),
             V::object(vec![("key", V::scalar(123))].into_iter().collect()),
         );
         assert_eq!(
-            graphql_value!({ "key": 1 + 2 }),
+            value!({ "key": 1 + 2 }),
             V::object(vec![("key", V::scalar(3))].into_iter().collect()),
         );
         assert_eq!(
-            graphql_value!({ "key": [] }),
+            value!({ "key": [] }),
             V::object(vec![("key", V::list(vec![]))].into_iter().collect()),
         );
         assert_eq!(
-            graphql_value!({ "key": [null] }),
+            value!({ "key": [null] }),
             V::object(vec![("key", V::list(vec![V::Null]))].into_iter().collect()),
         );
         assert_eq!(
-            graphql_value!({ "key": [1] }),
+            value!({ "key": [1] }),
             V::object(
                 vec![("key", V::list(vec![V::scalar(1)]))]
                     .into_iter()
@@ -359,7 +364,7 @@ mod tests {
             ),
         );
         assert_eq!(
-            graphql_value!({ "key": [1 + 2] }),
+            value!({ "key": [1 + 2] }),
             V::object(
                 vec![("key", V::list(vec![V::scalar(3)]))]
                     .into_iter()
@@ -367,7 +372,7 @@ mod tests {
             ),
         );
         assert_eq!(
-            graphql_value!({ "key": [val] }),
+            value!({ "key": [val] }),
             V::object(
                 vec![("key", V::list(vec![V::scalar(42)]))]
                     .into_iter()
@@ -380,8 +385,8 @@ mod tests {
     fn option() {
         let val = Some(42);
 
-        assert_eq!(graphql_value!(None), V::Null);
-        assert_eq!(graphql_value!(Some(42)), V::scalar(42));
-        assert_eq!(graphql_value!(val), V::scalar(42));
+        assert_eq!(value!(None), V::Null);
+        assert_eq!(value!(Some(42)), V::scalar(42));
+        assert_eq!(value!(val), V::scalar(42));
     }
 }

From e347f25718aefeb2e4a10416664f45c769930081 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Wed, 8 Jun 2022 10:50:47 +0200
Subject: [PATCH 21/58] Refactor `vars!` macro position [skip ci]

---
 juniper/src/graphql/mod.rs                    |   3 +-
 juniper/src/lib.rs                            |   2 +-
 juniper/src/macros/mod.rs                     |   5 +-
 .../src/macros/{graphql_vars.rs => vars.rs}   | 158 +++++++++---------
 4 files changed, 86 insertions(+), 82 deletions(-)
 rename juniper/src/macros/{graphql_vars.rs => vars.rs} (81%)

diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 5b02afb96..1dfe22348 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -2,9 +2,10 @@ use crate::{behavior, resolve};
 
 pub use crate::{
     ast::InputValue,
-    macros::{input_value, value},
+    macros::{input_value, value, vars},
     resolve::Type,
     value::Value,
+    executor::Variables,
 };
 
 pub trait Interface<S>
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 70c514187..c612b27ae 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -76,7 +76,7 @@ pub use crate::{
     introspection::IntrospectionFormat,
     macros::{
         helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
-        input_value as graphql_input_value, value as graphql_value,
+        input_value as graphql_input_value, value as graphql_value, vars as graphql_vars,
     },
     parser::{ParseError, ScalarToken, Spanning},
     schema::{
diff --git a/juniper/src/macros/mod.rs b/juniper/src/macros/mod.rs
index 37bd0218d..9e60986e6 100644
--- a/juniper/src/macros/mod.rs
+++ b/juniper/src/macros/mod.rs
@@ -8,8 +8,7 @@ pub mod reflect;
 
 mod input_value;
 mod value;
-#[macro_use]
-mod graphql_vars;
+mod vars;
 
 #[doc(inline)]
-pub use self::{input_value::input_value, value::value};
+pub use self::{input_value::input_value, value::value, vars::vars};
diff --git a/juniper/src/macros/graphql_vars.rs b/juniper/src/macros/vars.rs
similarity index 81%
rename from juniper/src/macros/graphql_vars.rs
rename to juniper/src/macros/vars.rs
index 56bff3b3c..d4b75e82b 100644
--- a/juniper/src/macros/graphql_vars.rs
+++ b/juniper/src/macros/vars.rs
@@ -1,20 +1,18 @@
-//! [`graphql_vars!`] macro implementation.
-//!
-//! [`graphql_vars!`]: graphql_vars
+//! [`vars!`] macro implementation.
 
-/// Constructs [`Variables`] via JSON-like syntax.
+/// Constructs [`graphql::Variables`] via JSON-like syntax.
 ///
-/// [`Variables`] key should implement [`Into`]`<`[`String`]`>`.
+/// [`graphql::Variables`] key should implement [`Into`]`<`[`String`]`>`.
 /// ```rust
 /// # use std::borrow::Cow;
 /// #
-/// # use juniper::{graphql_vars, Variables};
+/// # use juniper::graphql;
 /// #
 /// let code = 200;
 /// let features = vec!["key", "value"];
 /// let key: Cow<'static, str> = "key".into();
 ///
-/// let value: Variables = graphql_vars! {
+/// let value: graphql::Variables = graphql::vars! {
 ///     "code": code,
 ///     "success": code == 200,
 ///     features[0]: features[1],
@@ -22,12 +20,11 @@
 /// };
 /// ```
 ///
-/// See [`graphql_input_value!`] for more info on syntax of value after `:`.
+/// See [`graphql::input_value!`] for more info on syntax of value after `:`.
 ///
-/// [`graphql_input_value!`]: crate::graphql_input_value
-/// [`Variables`]: crate::Variables
-#[macro_export]
-macro_rules! graphql_vars {
+/// [`graphql::input_value!`]: crate::graphql::input_value
+/// [`graphql::Variables`]: crate::graphql::Variables
+macro_rules! vars {
     ////////////
     // Object //
     ////////////
@@ -38,12 +35,12 @@ macro_rules! graphql_vars {
     // Insert the current entry followed by trailing comma.
     (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
         let _ = $object.insert(($($key)+).into(), $value);
-        $crate::graphql_vars! {@object $object () ($($rest)*) ($($rest)*)};
+        $crate::graphql::vars! {@object $object () ($($rest)*) ($($rest)*)};
     };
 
     // Current entry followed by unexpected token.
     (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
-        $crate::graphql_vars! {@unexpected $unexpected};
+        $crate::graphql::vars! {@unexpected $unexpected};
     };
 
     // Insert the last entry without trailing comma.
@@ -53,7 +50,7 @@ macro_rules! graphql_vars {
 
     // Next value is `null`.
     (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!(null)) $($rest)*
@@ -62,7 +59,7 @@ macro_rules! graphql_vars {
 
     // Next value is `None`.
     (@object $object:ident ($($key:tt)+) (: None $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!(None)) $($rest)*
@@ -71,7 +68,7 @@ macro_rules! graphql_vars {
 
     // Next value is a variable.
     (@object $object:ident ($($key:tt)+) (: @$var:ident $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!(@$var)) $($rest)*
@@ -80,7 +77,7 @@ macro_rules! graphql_vars {
 
     // Next value is an array.
     (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!([$($array)*])) $($rest)*
@@ -89,7 +86,7 @@ macro_rules! graphql_vars {
 
     // Next value is a map.
     (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!({$($map)*})) $($rest)*
@@ -98,7 +95,7 @@ macro_rules! graphql_vars {
 
     // Next value is `true`, `false` or enum ident followed by a comma.
     (@object $object:ident ($($key:tt)+) (: $ident:ident , $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!($ident)) , $($rest)*
@@ -107,7 +104,7 @@ macro_rules! graphql_vars {
 
     // Next value is `true`, `false` or enum ident without trailing comma.
     (@object $object:ident ($($key:tt)+) (: $last:ident ) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!($last))
@@ -116,7 +113,7 @@ macro_rules! graphql_vars {
 
     // Next value is an expression followed by comma.
     (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!($value)) , $($rest)*
@@ -125,7 +122,7 @@ macro_rules! graphql_vars {
 
     // Last value is an expression with no trailing comma.
     (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             [$($key)+]
             ($crate::graphql_input_value!($value))
@@ -135,44 +132,44 @@ macro_rules! graphql_vars {
     // Missing value for last entry. Trigger a reasonable error message.
     (@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
         // "unexpected end of macro invocation"
-        $crate::graphql_vars! {};
+        $crate::graphql::vars! {};
     };
 
     // Missing colon and value for last entry. Trigger a reasonable error
     // message.
     (@object $object:ident ($($key:tt)+) () $copy:tt) => {
         // "unexpected end of macro invocation"
-        $crate::graphql_vars! {};
+        $crate::graphql::vars! {};
     };
 
     // Misplaced colon. Trigger a reasonable error message.
     (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
         // Takes no arguments so "no rules expected the token `:`".
-        $crate::graphql_vars! {@unexpected $colon};
+        $crate::graphql::vars! {@unexpected $colon};
     };
 
     // Found a comma inside a key. Trigger a reasonable error message.
     (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
         // Takes no arguments so "no rules expected the token `,`".
-        $crate::graphql_vars! {@unexpected $comma};
+        $crate::graphql::vars! {@unexpected $comma};
     };
 
     // Key is fully parenthesized. This avoids clippy double_parens false
     // positives because the parenthesization may be necessary here.
     (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object ($key) (: $($rest)*) (: $($rest)*)
         };
     };
 
     // Refuse to absorb colon token into key expression.
     (@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => {
-        $crate::graphql_vars! {@unexpected $($unexpected)+};
+        $crate::graphql::vars! {@unexpected $($unexpected)+};
     };
 
     // Munch a token into the current key.
     (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
-        $crate::graphql_vars! {
+        $crate::graphql::vars! {
             @object $object
             ($($key)* $tt)
             ($($rest)*) ($($rest)*)
@@ -189,26 +186,33 @@ macro_rules! graphql_vars {
     // Defaults //
     //////////////
 
-    () => {{ $crate::Variables::<_>::new() }};
+    () => {{ $crate::graphql::Variables::<_>::new() }};
 
     ( $($map:tt)+ ) => {{
-        let mut object = $crate::Variables::<_>::new();
-        $crate::graphql_vars! {@object object () ($($map)*) ($($map)*)};
+        let mut object = $crate::graphql::Variables::<_>::new();
+        $crate::graphql::vars! {@object object () ($($map)*) ($($map)*)};
         object
     }};
 }
 
+#[doc(inline)]
+pub(super) use vars;
+
 #[cfg(test)]
 mod tests {
     use indexmap::{indexmap, IndexMap};
 
-    type V = crate::Variables;
+    use crate::graphql;
+
+    use super::vars;
+
+    type V = graphql::Variables;
 
-    type IV = crate::InputValue;
+    type IV = graphql::InputValue;
 
     #[test]
     fn empty() {
-        assert_eq!(graphql_vars! {}, V::new());
+        assert_eq!(vars! {}, V::new());
     }
 
     #[test]
@@ -216,37 +220,37 @@ mod tests {
         let val = 42;
 
         assert_eq!(
-            graphql_vars! {"key": 123},
+            vars! {"key": 123},
             vec![("key".to_owned(), IV::scalar(123))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": "val"},
+            vars! {"key": "val"},
             vec![("key".to_owned(), IV::scalar("val"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": 1.23},
+            vars! {"key": 1.23},
             vec![("key".to_owned(), IV::scalar(1.23))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": 1 + 2},
+            vars! {"key": 1 + 2},
             vec![("key".to_owned(), IV::scalar(3))]
                 .into_iter()
                 .collect(),
         );
         assert_eq!(
-            graphql_vars! {"key": false},
+            vars! {"key": false},
             vec![("key".to_owned(), IV::scalar(false))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": (val)},
+            vars! {"key": (val)},
             vec![("key".to_owned(), IV::scalar(42))]
                 .into_iter()
                 .collect::<V>(),
@@ -256,13 +260,13 @@ mod tests {
     #[test]
     fn r#enum() {
         assert_eq!(
-            graphql_vars! {"key": ENUM},
+            vars! {"key": ENUM},
             vec![("key".to_owned(), IV::enum_value("ENUM"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": lowercase},
+            vars! {"key": lowercase},
             vec![("key".to_owned(), IV::enum_value("lowercase"))]
                 .into_iter()
                 .collect::<V>(),
@@ -272,19 +276,19 @@ mod tests {
     #[test]
     fn variable() {
         assert_eq!(
-            graphql_vars! {"key": @var},
+            vars! {"key": @var},
             vec![("key".to_owned(), IV::variable("var"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": @array},
+            vars! {"key": @array},
             vec![("key".to_owned(), IV::variable("array"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": @object},
+            vars! {"key": @object},
             vec![("key".to_owned(), IV::variable("object"))]
                 .into_iter()
                 .collect::<V>(),
@@ -296,46 +300,46 @@ mod tests {
         let val = 42;
 
         assert_eq!(
-            graphql_vars! {"key": []},
+            vars! {"key": []},
             vec![("key".to_owned(), IV::list(vec![]))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
-            graphql_vars! {"key": [null]},
+            vars! {"key": [null]},
             vec![("key".to_owned(), IV::list(vec![IV::Null]))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
-            graphql_vars! {"key": [1]},
+            vars! {"key": [1]},
             vec![("key".to_owned(), IV::list(vec![IV::scalar(1)]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [1 + 2]},
+            vars! {"key": [1 + 2]},
             vec![("key".to_owned(), IV::list(vec![IV::scalar(3)]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [(val)]},
+            vars! {"key": [(val)]},
             vec![("key".to_owned(), IV::list(vec![IV::scalar(42)]))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
-            graphql_vars! {"key": [ENUM]},
+            vars! {"key": [ENUM]},
             vec![("key".to_owned(), IV::list(vec![IV::enum_value("ENUM")]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [lowercase]},
+            vars! {"key": [lowercase]},
             vec![(
                 "key".to_owned(),
                 IV::list(vec![IV::enum_value("lowercase")])
@@ -345,26 +349,26 @@ mod tests {
         );
 
         assert_eq!(
-            graphql_vars! {"key": [@var]},
+            vars! {"key": [@var]},
             vec![("key".to_owned(), IV::list(vec![IV::variable("var")]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [@array]},
+            vars! {"key": [@array]},
             vec![("key".to_owned(), IV::list(vec![IV::variable("array")]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [@object]},
+            vars! {"key": [@object]},
             vec![("key".to_owned(), IV::list(vec![IV::variable("object")]))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
-            graphql_vars! {"key": [1, [2], 3]},
+            vars! {"key": [1, [2], 3]},
             vec![(
                 "key".to_owned(),
                 IV::list(vec![
@@ -377,7 +381,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [1, [2 + 3], 3]},
+            vars! {"key": [1, [2 + 3], 3]},
             vec![(
                 "key".to_owned(),
                 IV::list(vec![
@@ -390,7 +394,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [1, [ENUM], (val)]},
+            vars! {"key": [1, [ENUM], (val)]},
             vec![(
                 "key".to_owned(),
                 IV::list(vec![
@@ -403,7 +407,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [1 + 2, [(val)], @val]},
+            vars! {"key": [1 + 2, [(val)], @val]},
             vec![(
                 "key".to_owned(),
                 IV::list(vec![
@@ -416,7 +420,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": [1, [@val], ENUM]},
+            vars! {"key": [1, [@val], ENUM]},
             vec![(
                 "key".to_owned(),
                 IV::list(vec![
@@ -435,21 +439,21 @@ mod tests {
         let val = 42;
 
         assert_eq!(
-            graphql_vars! {"key": {}},
+            vars! {"key": {}},
             vec![("key".to_owned(), IV::object(IndexMap::<String, _>::new()))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
-            graphql_vars! {"key": {"key": null}},
+            vars! {"key": {"key": null}},
             vec![("key".to_owned(), IV::object(indexmap! {"key" => IV::Null}))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
-            graphql_vars! {"key": {"key": 123}},
+            vars! {"key": {"key": 123}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::scalar(123)}),
@@ -458,7 +462,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": 1 + 2}},
+            vars! {"key": {"key": 1 + 2}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::scalar(3)}),
@@ -467,7 +471,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": (val)}},
+            vars! {"key": {"key": (val)}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::scalar(42)}),
@@ -477,7 +481,7 @@ mod tests {
         );
 
         assert_eq!(
-            graphql_vars! {"key": {"key": []}},
+            vars! {"key": {"key": []}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::list(vec![])}),
@@ -486,7 +490,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": [null]}},
+            vars! {"key": {"key": [null]}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::Null])}),
@@ -495,7 +499,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": [1]}},
+            vars! {"key": {"key": [1]}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::scalar(1)])}),
@@ -504,7 +508,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": [1 + 2]}},
+            vars! {"key": {"key": [1 + 2]}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::scalar(3)])}),
@@ -513,7 +517,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": [(val)]}},
+            vars! {"key": {"key": [(val)]}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::scalar(42)])}),
@@ -522,7 +526,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": ENUM}},
+            vars! {"key": {"key": ENUM}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::enum_value("ENUM")}),
@@ -531,7 +535,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": lowercase}},
+            vars! {"key": {"key": lowercase}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::enum_value("lowercase")}),
@@ -540,7 +544,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": @val}},
+            vars! {"key": {"key": @val}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::variable("val")}),
@@ -549,7 +553,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {"key": {"key": @array}},
+            vars! {"key": {"key": @array}},
             vec![(
                 "key".to_owned(),
                 IV::object(indexmap! {"key" => IV::variable("array")}),
@@ -558,7 +562,7 @@ mod tests {
             .collect::<V>(),
         );
         assert_eq!(
-            graphql_vars! {
+            vars! {
                 "inner": {
                     "key1": (val),
                     "key2": "val",

From 5a62ddfbf224b6a0ee3711e2b42a15b887e7f5e7 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Wed, 8 Jun 2022 11:06:28 +0200
Subject: [PATCH 22/58] Restore old reflection impls

---
 juniper/src/macros/reflect.rs             | 122 +++++++++++++++++++++-
 juniper/src/types/nullable.rs             |   6 +-
 juniper/src/types/scalars.rs              |  13 +++
 juniper_codegen/src/graphql_scalar/mod.rs |  59 +++++++++--
 4 files changed, 187 insertions(+), 13 deletions(-)

diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs
index b24ba4f58..e67762df0 100644
--- a/juniper/src/macros/reflect.rs
+++ b/juniper/src/macros/reflect.rs
@@ -7,7 +7,7 @@ use crate::{
         can_be_subtype, fnv1a128, str_eq, str_exists_in_arr, type_len_with_wrapped_val, wrap,
         Argument, Arguments, FieldName, Name, Names, Type, Types, WrappedValue,
     },
-    Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue,
+    Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue, Nullable,
 };
 
 /// Naming of a [GraphQL object][1], [scalar][2] or [interface][3] [`Type`].
@@ -31,6 +31,10 @@ pub trait BaseType<S> {
     const NAME: Type;
 }
 
+impl<'a, S, T: BaseType<S> + ?Sized> BaseType<S> for &'a T {
+    const NAME: Type = T::NAME;
+}
+
 impl<'ctx, S, T> BaseType<S> for (&'ctx T::Context, T)
 where
     S: ScalarValue,
@@ -39,6 +43,42 @@ where
     const NAME: Type = T::NAME;
 }
 
+impl<S, T: BaseType<S>> BaseType<S> for Option<T> {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S>> BaseType<S> for Nullable<T> {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S>, E> BaseType<S> for Result<T, E> {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S>> BaseType<S> for Vec<T> {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S>> BaseType<S> for [T] {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S>, const N: usize> BaseType<S> for [T; N] {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S> + ?Sized> BaseType<S> for Box<T> {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S> + ?Sized> BaseType<S> for Arc<T> {
+    const NAME: Type = T::NAME;
+}
+
+impl<S, T: BaseType<S> + ?Sized> BaseType<S> for Rc<T> {
+    const NAME: Type = T::NAME;
+}
+
 /// [Sub-types][2] of a [GraphQL object][1].
 ///
 /// This trait is transparent to [`Option`], [`Vec`] and other containers.
@@ -52,6 +92,10 @@ pub trait BaseSubTypes<S> {
     const NAMES: Types;
 }
 
+impl<'a, S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for &'a T {
+    const NAMES: Types = T::NAMES;
+}
+
 impl<'ctx, S, T> BaseSubTypes<S> for (&'ctx T::Context, T)
 where
     S: ScalarValue,
@@ -60,6 +104,42 @@ where
     const NAMES: Types = T::NAMES;
 }
 
+impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for Option<T> {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for Nullable<T> {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S>, E> BaseSubTypes<S> for Result<T, E> {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for Vec<T> {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S>> BaseSubTypes<S> for [T] {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S>, const N: usize> BaseSubTypes<S> for [T; N] {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for Box<T> {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for Arc<T> {
+    const NAMES: Types = T::NAMES;
+}
+
+impl<S, T: BaseSubTypes<S> + ?Sized> BaseSubTypes<S> for Rc<T> {
+    const NAMES: Types = T::NAMES;
+}
+
 // TODO: Just use `&str`s once they're allowed in `const` generics.
 /// Encoding of a composed GraphQL type in numbers.
 ///
@@ -117,6 +197,46 @@ where
     const VALUE: u128 = T::VALUE;
 }
 
+impl<S, T: WrappedType<S>> WrappedType<S> for Option<T> {
+    const VALUE: u128 = T::VALUE * 10 + 2;
+}
+
+impl<S, T: WrappedType<S>> WrappedType<S> for Nullable<T> {
+    const VALUE: u128 = T::VALUE * 10 + 2;
+}
+
+impl<S, T: WrappedType<S>, E> WrappedType<S> for Result<T, E> {
+    const VALUE: u128 = T::VALUE;
+}
+
+impl<S, T: WrappedType<S>> WrappedType<S> for Vec<T> {
+    const VALUE: u128 = T::VALUE * 10 + 3;
+}
+
+impl<S, T: WrappedType<S>> WrappedType<S> for [T] {
+    const VALUE: u128 = T::VALUE * 10 + 3;
+}
+
+impl<S, T: WrappedType<S>, const N: usize> WrappedType<S> for [T; N] {
+    const VALUE: u128 = T::VALUE * 10 + 3;
+}
+
+impl<'a, S, T: WrappedType<S> + ?Sized> WrappedType<S> for &'a T {
+    const VALUE: u128 = T::VALUE;
+}
+
+impl<S, T: WrappedType<S> + ?Sized> WrappedType<S> for Box<T> {
+    const VALUE: u128 = T::VALUE;
+}
+
+impl<S, T: WrappedType<S> + ?Sized> WrappedType<S> for Arc<T> {
+    const VALUE: u128 = T::VALUE;
+}
+
+impl<S, T: WrappedType<S> + ?Sized> WrappedType<S> for Rc<T> {
+    const VALUE: u128 = T::VALUE;
+}
+
 /// [GraphQL object][1] or [interface][2] [field arguments][3] [`Names`].
 ///
 /// [1]: https://spec.graphql.org/October2021#sec-Objects
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index 04165f3bf..daec60440 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -244,7 +244,7 @@ impl<T: Copy> Nullable<&T> {
     /// Maps this `Nullable<&T>` to a `Nullable<T>` by [`Copy`]ing the contents
     /// of this [`Nullable`].
     pub fn copied(self) -> Nullable<T> {
-        self.map(|&t| t)
+        self.map(|t| *t)
     }
 }
 
@@ -252,7 +252,7 @@ impl<T: Copy> Nullable<&mut T> {
     /// Maps this `Nullable<&mut T>` to a `Nullable<T>` by [`Copy`]ing the
     /// contents of this [`Nullable`].
     pub fn copied(self) -> Nullable<T> {
-        self.map(|&mut t| t)
+        self.map(|t| *t)
     }
 }
 
@@ -260,7 +260,7 @@ impl<T: Clone> Nullable<&T> {
     /// Maps this `Nullable<&T>` to a `Nullable<T>` by [`Clone`]ing the contents
     /// of this [`Nullable`].
     pub fn cloned(self) -> Nullable<T> {
-        self.map(|t| t.clone())
+        self.map(T::clone)
     }
 }
 
diff --git a/juniper/src/types/scalars.rs b/juniper/src/types/scalars.rs
index 0f8bb4089..66e26e74f 100644
--- a/juniper/src/types/scalars.rs
+++ b/juniper/src/types/scalars.rs
@@ -8,6 +8,7 @@ use crate::{
     ast::{InputValue, Selection, ToInputValue},
     executor::{ExecutionResult, Executor, Registry},
     graphql_scalar,
+    macros::reflect,
     parser::{LexerError, ParseError, ScalarToken, Token},
     schema::meta::MetaType,
     types::{
@@ -195,6 +196,18 @@ where
     })
 }
 
+impl<S> reflect::WrappedType<S> for str {
+    const VALUE: reflect::WrappedValue = 1;
+}
+
+impl<S> reflect::BaseType<S> for str {
+    const NAME: reflect::Type = "String";
+}
+
+impl<S> reflect::BaseSubTypes<S> for str {
+    const NAMES: reflect::Types = &[<Self as reflect::BaseType<S>>::NAME];
+}
+
 impl<S> GraphQLType<S> for str
 where
     S: ScalarValue,
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 9e6e49cff..5a706851a 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -329,17 +329,19 @@ impl ToTokens for Definition {
         self.impl_to_input_value_tokens().to_tokens(into);
         self.impl_from_input_value_tokens().to_tokens(into);
         self.impl_parse_scalar_value_tokens().to_tokens(into);
+        self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        self.impl_resolve_type().to_tokens(into);
-        self.impl_resolve_type_name().to_tokens(into);
-        self.impl_resolve_value().to_tokens(into);
-        self.impl_resolve_value_async().to_tokens(into);
-        self.impl_resolve_to_input_value().to_tokens(into);
-        self.impl_resolve_input_value().to_tokens(into);
-        self.impl_resolve_scalar_token().to_tokens(into);
-        //self.impl_graphql_input_and_output_type().to_tokens(into);
+        //self.impl_resolve_type().to_tokens(into);
+        //self.impl_resolve_type_name().to_tokens(into);
+        //self.impl_resolve_value().to_tokens(into);
+        //self.impl_resolve_value_async().to_tokens(into);
+        //self.impl_resolve_to_input_value().to_tokens(into);
+        //self.impl_resolve_input_value().to_tokens(into);
+        //self.impl_resolve_scalar_token().to_tokens(into);
+        //self.impl_graphql_output_type().to_tokens(into);
+        //self.impl_graphql_output_type().to_tokens(into);
         //self.impl_graphql_scalar().to_tokens(into);
-        self.impl_reflect().to_tokens(into);
+        //self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -850,6 +852,45 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`BaseType`], [`BaseSubTypes`] and
+    /// [`WrappedType`] traits for this [GraphQL scalar][1].
+    ///
+    /// [`BaseSubTypes`]: juniper::macros::reflection::BaseSubTypes
+    /// [`BaseType`]: juniper::macros::reflection::BaseType
+    /// [`WrappedType`]: juniper::macros::reflection::WrappedType
+    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_reflection_traits_tokens(&self) -> TokenStream {
+        let scalar = &self.scalar;
+        let name = &self.name;
+
+        let (ty, generics) = self.impl_self_and_generics(false);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::macros::reflect::BaseType<#scalar> for #ty
+                #where_clause
+            {
+                const NAME: ::juniper::macros::reflect::Type = #name;
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::macros::reflect::BaseSubTypes<#scalar> for #ty
+                #where_clause
+            {
+                const NAMES: ::juniper::macros::reflect::Types =
+                    &[<Self as ::juniper::macros::reflect::BaseType<#scalar>>::NAME];
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::macros::reflect::WrappedType<#scalar> for #ty
+                #where_clause
+            {
+                const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
+            }
+        }
+    }
+
     /// Returns generated code implementing [`reflect::BaseType`],
     /// [`reflect::BaseSubTypes`] and [`reflect::WrappedType`] traits for this
     /// [GraphQL scalar][0].

From 017e87c79110cb18c97f633f372b8533e1436981 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Wed, 8 Jun 2022 19:17:46 +0200
Subject: [PATCH 23/58] Reimpl renewed traits machinery for `Box` [skip ci]

---
 juniper/src/executor/mod.rs                   |   3 +-
 juniper/src/graphql/mod.rs                    |  20 +-
 juniper/src/lib.rs                            |   5 +-
 ...{input_value.rs => graphql_input_value.rs} |   5 +-
 .../src/macros/{value.rs => graphql_value.rs} |   5 +-
 .../src/macros/{vars.rs => graphql_vars.rs}   |   5 +-
 juniper/src/macros/mod.rs                     |   8 +-
 juniper/src/macros/reflect.rs                 |  13 +-
 juniper/src/reflect/mod.rs                    |  34 ++-
 juniper/src/resolve/mod.rs                    |  16 +-
 juniper/src/schema/meta.rs                    |   5 +-
 juniper/src/types/arc.rs                      |   2 +
 juniper/src/types/array.rs                    |   2 +
 juniper/src/types/box.rs                      | 268 +++++++++---------
 juniper/src/types/iter.rs                     |   2 +
 juniper/src/types/nullable.rs                 |   2 +
 juniper/src/types/option.rs                   |   3 +-
 juniper/src/types/rc.rs                       |   2 +
 juniper/src/types/ref.rs                      |   2 +
 juniper/src/types/ref_mut.rs                  |   2 +
 juniper/src/types/result.rs                   |   2 +
 juniper/src/types/slice.rs                    |   5 +-
 juniper/src/types/str.rs                      |   2 +
 juniper/src/types/vec.rs                      |   6 +-
 24 files changed, 230 insertions(+), 189 deletions(-)
 rename juniper/src/macros/{input_value.rs => graphql_input_value.rs} (99%)
 rename juniper/src/macros/{value.rs => graphql_value.rs} (99%)
 rename juniper/src/macros/{vars.rs => graphql_vars.rs} (99%)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 0dc3118b1..7603acb18 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -1294,6 +1294,7 @@ impl<'r, S: 'r> Registry<'r, S> {
         ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
     }
 
+    /*
     /// Builds a [`ScalarMeta`] information for the specified [`graphql::Type`].
     ///
     /// [`graphql::Type`]: resolve::Type
@@ -1317,7 +1318,7 @@ impl<'r, S: 'r> Registry<'r, S> {
     {
         // TODO: Allow using references.
         ScalarMeta::new_unsized::<T, _>(T::type_name(info).to_owned())
-    }
+    }*/
 
     /// Creates a [`ListMeta`] type.
     ///
diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 1dfe22348..8fa9391a0 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -8,8 +8,8 @@ pub use crate::{
     executor::Variables,
 };
 
-pub trait Interface<S>
-/*: OutputType<S>
+/*
+pub trait Interface<S>: OutputType<S>
    + resolve::TypeName
    + resolve::ConcreteTypeName
    + resolve::Value<S>
@@ -18,25 +18,20 @@ pub trait Interface<S>
    + resolve::ConcreteValueAsync<S>
    + resolve::Field<S>
    + resolve::FieldAsync<S>
-
-*/
 {
     fn assert_interface();
 }
 
-pub trait Object<S>
-/*: OutputType<S>
+pub trait Object<S>: OutputType<S>
    + resolve::TypeName
    + resolve::ConcreteTypeName
    + resolve::Value<S>
    + resolve::ValueAsync<S>
    + resolve::Field<S>
    + resolve::FieldAsync<S>
-
-*/
 {
     fn assert_object();
-}
+}*/
 
 pub trait Scalar<
     'inp,
@@ -52,17 +47,18 @@ pub trait Scalar<
     fn assert_scalar();
 }
 
+/*
 pub trait Union<S>
-/*: OutputType<S>
+ OutputType<S>
 + resolve::TypeName
 + resolve::ConcreteTypeName
 + resolve::Value<S>
 + resolve::ValueAsync<S>
 + resolve::ConcreteValue<S>
-+ resolve::ConcreteValueAsync<S> */
++ resolve::ConcreteValueAsync<S>
 {
     fn assert_union();
-}
+}*/
 
 pub trait InputType<
     'inp,
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index c612b27ae..04ac5d69c 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -74,10 +74,7 @@ pub use crate::{
         LookAheadSelection, LookAheadValue, OwnedExecutor, Registry, ValuesStream, Variables,
     },
     introspection::IntrospectionFormat,
-    macros::{
-        helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
-        input_value as graphql_input_value, value as graphql_value, vars as graphql_vars,
-    },
+    macros::helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
     parser::{ParseError, ScalarToken, Spanning},
     schema::{
         meta,
diff --git a/juniper/src/macros/input_value.rs b/juniper/src/macros/graphql_input_value.rs
similarity index 99%
rename from juniper/src/macros/input_value.rs
rename to juniper/src/macros/graphql_input_value.rs
index 627b4f634..73233a799 100644
--- a/juniper/src/macros/input_value.rs
+++ b/juniper/src/macros/graphql_input_value.rs
@@ -83,7 +83,8 @@
 /// [`InputValue::Scalar`]: crate::graphql::InputValue::Scalar
 /// [`InputValue::Variable`]: crate::graphql::InputValue::Variable
 /// [`Spanning::unlocated`]: crate::Spanning::unlocated
-macro_rules! input_value {
+#[macro_export]
+macro_rules! graphql_input_value {
     ///////////
     // Array //
     ///////////
@@ -379,7 +380,7 @@ macro_rules! input_value {
 }
 
 #[doc(inline)]
-pub(super) use input_value;
+pub use graphql_input_value as input_value;
 
 #[cfg(test)]
 mod tests {
diff --git a/juniper/src/macros/value.rs b/juniper/src/macros/graphql_value.rs
similarity index 99%
rename from juniper/src/macros/value.rs
rename to juniper/src/macros/graphql_value.rs
index c689afa68..aa72a7fbd 100644
--- a/juniper/src/macros/value.rs
+++ b/juniper/src/macros/graphql_value.rs
@@ -43,7 +43,8 @@
 ///
 /// [`graphql::Value`]: crate::graphql::Value
 /// [`Value::Object`]: crate::graphql::Value::Object
-macro_rules! value {
+#[macro_export]
+macro_rules! graphql_value {
     ///////////
     // Array //
     ///////////
@@ -270,7 +271,7 @@ macro_rules! value {
 }
 
 #[doc(inline)]
-pub(super) use value;
+pub use graphql_value as value;
 
 #[cfg(test)]
 mod tests {
diff --git a/juniper/src/macros/vars.rs b/juniper/src/macros/graphql_vars.rs
similarity index 99%
rename from juniper/src/macros/vars.rs
rename to juniper/src/macros/graphql_vars.rs
index d4b75e82b..2034e4933 100644
--- a/juniper/src/macros/vars.rs
+++ b/juniper/src/macros/graphql_vars.rs
@@ -24,7 +24,8 @@
 ///
 /// [`graphql::input_value!`]: crate::graphql::input_value
 /// [`graphql::Variables`]: crate::graphql::Variables
-macro_rules! vars {
+#[macro_export]
+macro_rules! graphql_vars {
     ////////////
     // Object //
     ////////////
@@ -196,7 +197,7 @@ macro_rules! vars {
 }
 
 #[doc(inline)]
-pub(super) use vars;
+pub use graphql_vars as vars;
 
 #[cfg(test)]
 mod tests {
diff --git a/juniper/src/macros/mod.rs b/juniper/src/macros/mod.rs
index 9e60986e6..57f1a4c74 100644
--- a/juniper/src/macros/mod.rs
+++ b/juniper/src/macros/mod.rs
@@ -6,9 +6,9 @@ pub mod helper;
 #[macro_use]
 pub mod reflect;
 
-mod input_value;
-mod value;
-mod vars;
+mod graphql_input_value;
+mod graphql_value;
+mod graphql_vars;
 
 #[doc(inline)]
-pub use self::{input_value::input_value, value::value, vars::vars};
+pub use self::{graphql_input_value::input_value, graphql_value::value, graphql_vars::vars};
diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs
index e67762df0..e7cb1f305 100644
--- a/juniper/src/macros/reflect.rs
+++ b/juniper/src/macros/reflect.rs
@@ -1,13 +1,16 @@
 //! Compile-time reflection of Rust types into GraphQL types.
 
+use std::{rc::Rc, sync::Arc};
+
 use futures::future::BoxFuture;
 
 use crate::{
-    reflect::{
-        can_be_subtype, fnv1a128, str_eq, str_exists_in_arr, type_len_with_wrapped_val, wrap,
-        Argument, Arguments, FieldName, Name, Names, Type, Types, WrappedValue,
-    },
-    Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue, Nullable,
+    Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, Nullable, ScalarValue,
+};
+
+pub use crate::reflect::{
+    can_be_subtype, fnv1a128, str_eq, str_exists_in_arr, type_len_with_wrapped_val, Argument,
+    Arguments, FieldName, Name, Names, Type, Types, WrappedValue,
 };
 
 /// Naming of a [GraphQL object][1], [scalar][2] or [interface][3] [`Type`].
diff --git a/juniper/src/reflect/mod.rs b/juniper/src/reflect/mod.rs
index 2304e6a2b..43d738278 100644
--- a/juniper/src/reflect/mod.rs
+++ b/juniper/src/reflect/mod.rs
@@ -5,7 +5,7 @@ use crate::behavior;
 #[doc(inline)]
 pub use self::macros::{
     assert_field, assert_field_args, assert_field_type, assert_has_field, assert_implemented_for,
-    assert_interfaces_impls, checked_hash, const_concat, format_type,
+    assert_interfaces_impls, const_concat, format_type,
 };
 
 /// Name of a [GraphQL type][0] in a GraphQL schema.
@@ -329,7 +329,8 @@ mod macros {
     /// types referencing this interface in the `impl = ...` attribute argument.
     ///
     /// Symmetrical to [`assert_interfaces_impls!`].
-    macro_rules! assert_implemented_for {
+    #[macro_export]
+    macro_rules! reflect_assert_implemented_for {
         ($behavior: ty, $implementor: ty $(, $interfaces: ty)* $(,)?) => {
             const _: () = {
                 $({
@@ -356,7 +357,8 @@ mod macros {
     /// referencing this type in `#[graphql::interface(for = ...)]` attribute.
     ///
     /// Symmetrical to [`assert_implemented_for!`].
-    macro_rules! assert_interfaces_impls {
+    #[macro_export]
+    macro_rules! reflect_assert_interfaces_impls {
         ($behavior: ty, $interface: ty $(, $implementers: ty)* $(,)?) => {
             const _: () = {
                 $({
@@ -390,7 +392,8 @@ mod macros {
     /// [`Field`]: super::Field
     /// [`Type`]: super::Type
     /// [0]: https://spec.graphql.org/October2021#IsValidImplementation()
-    macro_rules! assert_field {
+    #[macro_export]
+    macro_rules! reflect_assert_field {
         (
             $base_ty: ty,
             $impl_ty: ty,
@@ -409,7 +412,7 @@ mod macros {
     /// [`Field`]: super::Field
     /// [0]: https://spec.graphql.org/October2021#IsValidImplementationFieldType()
     #[macro_export]
-    macro_rules! assert_field_type {
+    macro_rules! reflect_assert_field_type {
         (
             $base_ty: ty,
             $impl_ty: ty,
@@ -492,7 +495,7 @@ mod macros {
     /// [`Field`]: super::Field
     /// [0]: https://spec.graphql.org/October2021#sel-IAHZhCHCDEEFAAADHD8Cxob
     #[macro_export]
-    macro_rules! assert_field_args {
+    macro_rules! reflect_assert_field_args {
         (
             $base_ty: ty,
             $impl_ty: ty,
@@ -677,7 +680,8 @@ mod macros {
     ///
     /// [`Field`]: super::Field
     /// [`fnv1a128`]: super::fnv1a128
-    macro_rules! assert_has_field {
+    #[macro_export]
+    macro_rules! reflect_assert_has_field {
         (
             $field_name: expr,
             $impl_ty: ty,
@@ -703,7 +707,8 @@ mod macros {
     }
 
     /// Concatenates `const` [`str`](prim@str)s in a `const` context.
-    macro_rules! const_concat {
+    #[macro_export]
+    macro_rules! reflect_const_concat {
         ($($s:expr),* $(,)?) => {{
             const LEN: usize = 0 $(+ $s.as_bytes().len())*;
             const CNT: usize = [$($s),*].len();
@@ -745,7 +750,8 @@ mod macros {
     ///
     /// [`Type`]: super::Type
     /// [`WrappedValue`]: super::WrappedValue
-    macro_rules! format_type {
+    #[macro_export]
+    macro_rules! reflect_format_type {
         ($ty: expr, $wrapped_value: expr $(,)?) => {{
             const TYPE: ($crate::reflect::Type, $crate::reflect::WrappedValue) =
                 ($ty, $wrapped_value);
@@ -831,8 +837,12 @@ mod macros {
     }
 
     #[doc(inline)]
-    pub(super) use {
-        assert_field, assert_field_args, assert_field_type, assert_has_field,
-        assert_implemented_for, assert_interfaces_impls, checked_hash, const_concat, format_type,
+    pub use {
+        reflect_assert_field as assert_field, reflect_assert_field_args as assert_field_args,
+        reflect_assert_field_type as assert_field_type,
+        reflect_assert_has_field as assert_has_field,
+        reflect_assert_implemented_for as assert_implemented_for,
+        reflect_assert_interfaces_impls as assert_interfaces_impls,
+        reflect_const_concat as const_concat, reflect_format_type as format_type,
     };
 }
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index fa32f9e53..21517fc78 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -7,8 +7,8 @@ use crate::{
 
 #[doc(inline)]
 pub use crate::types::{
-    arc::TryFromInputValue as InputValueAsArc, r#box::TryFromInputValue as InputValueAsBox,
-    r#ref::TryFromInputValue as InputValueAsRef, rc::TryFromInputValue as InputValueAsRc,
+    /*arc::TryFromInputValue as InputValueAsArc,*/ r#box::TryFromInputValue as InputValueAsBox,
+    /*r#ref::TryFromInputValue as InputValueAsRef, rc::TryFromInputValue as InputValueAsRc,*/
 };
 
 pub trait Type<TypeInfo: ?Sized, ScalarValue, Behavior: ?Sized = behavior::Standard> {
@@ -24,7 +24,7 @@ pub trait TypeName<TypeInfo: ?Sized, Behavior: ?Sized = behavior::Standard> {
     fn type_name(type_info: &TypeInfo) -> &str;
 }
 
-pub trait ConcreteTypeName<TypeInfo: ?Sized> {
+pub trait ConcreteTypeName<TypeInfo: ?Sized, Behavior: ?Sized = behavior::Standard> {
     fn concrete_type_name<'i>(&self, type_info: &'i TypeInfo) -> &'i str;
 }
 
@@ -74,7 +74,13 @@ pub trait ConcreteValue<
     ) -> ExecutionResult<ScalarValue>;
 }
 
-pub trait ConcreteValueAsync<TypeInfo: ?Sized, Context: ?Sized, ScalarValue> {
+pub trait ConcreteValueAsync<
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue,
+    Behavior: ?Sized = behavior::Standard,
+>
+{
     fn resolve_concrete_value_async<'r>(
         &'r self,
         type_name: &str,
@@ -171,7 +177,7 @@ pub trait InputValueOwned<ScalarValue, Behavior: ?Sized = behavior::Standard>:
 {
 }
 
-impl<T, S, B: ?Sized> InputValueOwned<S, B> for T where T: for<'i> InputValue<'i, S, B> {}
+impl<T, SV, BH: ?Sized> InputValueOwned<SV, BH> for T where T: for<'i> InputValue<'i, SV, BH> {}
 
 pub trait ScalarToken<ScalarValue, Behavior: ?Sized = behavior::Standard> {
     fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<ScalarValue, ParseError<'_>>;
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index dfcc838d2..f9f50af6d 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -448,6 +448,7 @@ impl<'a, S> ScalarMeta<'a, S> {
         }
     }
 
+    /*
     /// Builds a new [`ScalarMeta`] information with the specified `name`.
     // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
     //       `explicit_generic_args_with_impl_trait` hits stable:
@@ -483,7 +484,7 @@ impl<'a, S> ScalarMeta<'a, S> {
             try_parse_fn: try_parse_unsized_fn::<S, T>,
             parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
         }
-    }
+    }*/
 
     /// Sets the `description` of this [`ScalarMeta`] type.
     ///
@@ -837,6 +838,7 @@ where
         .map_err(T::Error::into_field_error)
 }
 
+/*
 fn try_parse_fn_new<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
 where
     T: resolve::InputValueOwned<S>,
@@ -854,3 +856,4 @@ where
         .map(drop)
         .map_err(T::Error::into_field_error)
 }
+*/
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 38f0f2187..3c6d12d05 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -10,6 +10,7 @@ use crate::{
     IntoFieldError, Registry, Selection,
 };
 
+/*
 impl<T, Info, S> resolve::Type<Info, S> for Arc<T>
 where
     T: resolve::Type<Info, S> + ?Sized,
@@ -278,3 +279,4 @@ where
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
+*/
diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
index 77ef5f9be..f730c39da 100644
--- a/juniper/src/types/array.rs
+++ b/juniper/src/types/array.rs
@@ -11,6 +11,7 @@ use crate::{
 
 use super::iter;
 
+/*
 impl<T, Info, S, const N: usize> resolve::Type<Info, S> for [T; N]
 where
     T: resolve::Type<Info, S>,
@@ -114,3 +115,4 @@ where
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
 }
+*/
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index b30936972..68edcc005 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -1,278 +1,278 @@
 //! GraphQL implementation for [`Box`].
 
 use crate::{
-    graphql,
+    behavior, graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
-    IntoFieldError, Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry,
+    Selection,
 };
 
-impl<T, Info, S> resolve::Type<Info, S> for Box<T>
+impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Box<T>
 where
-    T: resolve::Type<Info, S> + ?Sized,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
         T::meta(registry, info)
     }
 }
 
-impl<T, Info> resolve::TypeName<Info> for Box<T>
+impl<T, TI, BH> resolve::TypeName<TI, BH> for Box<T>
 where
-    T: resolve::TypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::TypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn type_name(info: &Info) -> &str {
+    fn type_name(info: &TI) -> &str {
         T::type_name(info)
     }
 }
 
-impl<T, Info> resolve::ConcreteTypeName<Info> for Box<T>
+impl<T, TI, BH> resolve::ConcreteTypeName<TI, BH> for Box<T>
 where
-    T: resolve::ConcreteTypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::ConcreteTypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
         (**self).concrete_type_name(info)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Box<T>
+impl<T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for Box<T>
 where
-    T: resolve::Value<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_value(selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_value(selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Box<T>
+impl<T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for Box<T>
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_value_async(selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_value_async(selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for Box<T>
+impl<T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Box<T>
 where
-    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value(
         &self,
         type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_concrete_value(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for Box<T>
+impl<T, TI, CX, SV, BH> resolve::ConcreteValueAsync<TI, CX, SV, BH> for Box<T>
 where
-    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value_async<'r>(
         &'r self,
         type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for Box<T>
+impl<T, TI, CX, SV, BH> resolve::Field<TI, CX, SV, BH> for Box<T>
 where
-    T: resolve::Field<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Field<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field(
         &self,
         field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_field(field_name, arguments, info, executor)
+        arguments: &Arguments<SV>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_field(field_name, arguments, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for Box<T>
+impl<T, TI, CX, SV, BH> resolve::FieldAsync<TI, CX, SV, BH> for Box<T>
 where
-    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::FieldAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field_async<'r>(
         &'r self,
         field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_field_async(field_name, arguments, info, executor)
+        arguments: &'r Arguments<SV>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_field_async(field_name, arguments, type_info, executor)
     }
 }
 
-impl<T, S> resolve::ToInputValue<S> for Box<T>
+impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Box<T>
 where
-    T: resolve::ToInputValue<S> + ?Sized,
+    T: resolve::ToInputValue<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         (**self).to_input_value()
     }
 }
 
-impl<'inp, T, S> resolve::InputValue<'inp, S> for Box<T>
+impl<'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Box<T>
 where
-    T: resolve::InputValueAsBox<'inp, S> + ?Sized,
-    S: 'inp,
+    T: resolve::InputValueAsBox<'i, SV, BH> + ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValueAsBox<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsBox<'inp, S>>::try_from_input_value(v)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        T::try_from_input_value(v)
     }
 
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsBox<'inp, S>>::try_from_implicit_null()
+        T::try_from_implicit_null()
     }
 }
 
-pub trait TryFromInputValue<'input, S: 'input = DefaultScalarValue> {
-    type Error: IntoFieldError<S>;
+pub trait TryFromInputValue<'input, ScalarValue: 'input, Behavior: ?Sized = behavior::Standard> {
+    type Error: IntoFieldError<ScalarValue>;
 
-    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Box<Self>, Self::Error>;
+    fn try_from_input_value(
+        v: &'input graphql::InputValue<ScalarValue>,
+    ) -> Result<Box<Self>, Self::Error>;
 
     fn try_from_implicit_null() -> Result<Box<Self>, Self::Error> {
-        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
+        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
     }
 }
 
-impl<'inp, T, S> TryFromInputValue<'inp, S> for T
+impl<'i, T, SV, BH> TryFromInputValue<'i, SV, BH> for T
 where
-    T: resolve::InputValue<'inp, S>,
-    S: 'inp,
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Box<Self>, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Box::new)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Box<Self>, Self::Error> {
+        T::try_from_input_value(v).map(Box::new)
     }
 
     fn try_from_implicit_null() -> Result<Box<Self>, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Box::new)
+        T::try_from_implicit_null().map(Box::new)
     }
 }
 
-impl<T, S> resolve::ScalarToken<S> for Box<T>
+impl<T, SV, BH> resolve::ScalarToken<SV, BH> for Box<T>
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ScalarToken<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
         T::parse_scalar_token(token)
     }
 }
 
-impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Box<T>
+impl<'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Box<T>
 where
-    T: graphql::InputType<'i, Info, S> + resolve::InputValueAsBox<'i, S> + ?Sized,
-    Info: ?Sized,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
 
-impl<T, S> graphql::OutputType<S> for Box<T>
+impl<T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for Box<T>
 where
-    T: graphql::OutputType<S> + ?Sized,
+    T: graphql::OutputType<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<T, S> graphql::Interface<S> for Box<T>
+impl<'i, T, TI, CX, SV, BH> graphql::Scalar<'i, TI, CX, SV, BH> for Box<T>
 where
-    T: graphql::Interface<S> + ?Sized,
-{
-    fn assert_interface() {
-        T::assert_interface()
-    }
-}
-
-impl<T, S> graphql::Object<S> for Box<T>
-where
-    T: graphql::Object<S> + ?Sized,
-{
-    fn assert_object() {
-        T::assert_object()
-    }
-}
-
-impl<T, S> graphql::Scalar<S> for Box<T>
-where
-    T: graphql::Scalar<S> + ?Sized,
+    T: graphql::Scalar<'i, TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_scalar() {
         T::assert_scalar()
     }
 }
 
-impl<T, S> graphql::Union<S> for Box<T>
-where
-    T: graphql::Union<S> + ?Sized,
-{
-    fn assert_union() {
-        T::assert_union()
-    }
-}
-
-impl<T, S> reflect::BaseType<S> for Box<T>
+impl<T, BH> reflect::BaseType<BH> for Box<T>
 where
-    T: reflect::BaseType<S> + ?Sized,
+    T: reflect::BaseType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S> reflect::BaseSubTypes<S> for Box<T>
+impl<T, BH> reflect::BaseSubTypes<BH> for Box<T>
 where
-    T: reflect::BaseSubTypes<S> + ?Sized,
+    T: reflect::BaseSubTypes<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S> reflect::WrappedType<S> for Box<T>
+impl<T, BH> reflect::WrappedType<BH> for Box<T>
 where
-    T: reflect::WrappedType<S> + ?Sized,
+    T: reflect::WrappedType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
diff --git a/juniper/src/types/iter.rs b/juniper/src/types/iter.rs
index c3979b088..8d6aad9df 100644
--- a/juniper/src/types/iter.rs
+++ b/juniper/src/types/iter.rs
@@ -2,6 +2,7 @@
 
 use crate::{graphql, resolve, ExecutionResult, Executor, Selection};
 
+/*
 pub fn resolve_list<'t, T, S, Info, Ctx, I>(
     iter: I,
     selection_set: Option<&[Selection<'_, S>]>,
@@ -65,3 +66,4 @@ where
     }
     Ok(graphql::Value::list(values))
 }
+*/
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index daec60440..b48064df5 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -272,6 +272,7 @@ impl<T: Clone> Nullable<&mut T> {
     }
 }
 
+/*
 impl<T, Info, S> resolve::Type<Info, S> for Nullable<T>
 where
     T: resolve::Type<Info, S>,
@@ -395,6 +396,7 @@ where
     const VALUE: reflect::WrappedValue = reflect::wrap::nullable(T::VALUE);
 }
 
+ */
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<S, T> GraphQLType<S> for Nullable<T>
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index 0d8ebb6aa..7f3ef70d9 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -8,7 +8,7 @@ use crate::{
     schema::meta::MetaType,
     BoxFuture, Selection,
 };
-
+/*
 impl<T, Info, S> resolve::Type<Info, S> for Option<T>
 where
     T: resolve::Type<Info, S>,
@@ -127,3 +127,4 @@ where
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::nullable(T::VALUE);
 }
+*/
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index ebecc3f27..88f7089de 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -10,6 +10,7 @@ use crate::{
     IntoFieldError, Registry, Selection,
 };
 
+/*
 impl<T, Info, S> resolve::Type<Info, S> for Rc<T>
 where
     T: resolve::Type<Info, S> + ?Sized,
@@ -278,3 +279,4 @@ where
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
+*/
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 5b84d54f6..e087482a4 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -10,6 +10,7 @@ use crate::{
     IntoFieldError, Registry, Selection,
 };
 
+/*
 impl<'me, T, Info, S> resolve::Type<Info, S> for &'me T
 where
     T: resolve::Type<Info, S> + ?Sized,
@@ -265,3 +266,4 @@ where
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
+*/
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index 77f8b602e..31a572119 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -9,6 +9,7 @@ use crate::{
     reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
+/*
 impl<'me, T, Info, S> resolve::Type<Info, S> for &'me mut T
 where
     T: resolve::Type<Info, S> + ?Sized,
@@ -225,3 +226,4 @@ where
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
+*/
diff --git a/juniper/src/types/result.rs b/juniper/src/types/result.rs
index 1077f979c..51ec79ad1 100644
--- a/juniper/src/types/result.rs
+++ b/juniper/src/types/result.rs
@@ -2,6 +2,7 @@
 
 use crate::reflect;
 
+/*
 impl<T, E, S> reflect::BaseType<S> for Result<T, E>
 where
     T: reflect::BaseType<S>,
@@ -22,3 +23,4 @@ where
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
+*/
diff --git a/juniper/src/types/slice.rs b/juniper/src/types/slice.rs
index 022a335bb..0b31c7a99 100644
--- a/juniper/src/types/slice.rs
+++ b/juniper/src/types/slice.rs
@@ -11,6 +11,7 @@ use crate::{
 
 use super::iter;
 
+/*
 impl<T, Info, S> resolve::Type<Info, S> for [T]
 where
     T: resolve::Type<Info, S>,
@@ -71,7 +72,6 @@ where
     }
 }
 
-/*
 impl<T, S> graphql::InputType<S> for [T]
 where
     T: graphql::InputType<S>,
@@ -80,7 +80,7 @@ where
         T::assert_input_type()
     }
 }
-*/
+
 
 impl<T, S> graphql::OutputType<S> for [T]
 where
@@ -111,3 +111,4 @@ where
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
 }
+*/
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index c1a559a0c..a5ff4436c 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -13,6 +13,7 @@ use crate::{
     reflect, resolve, BoxFuture, ExecutionResult, Executor, Registry, ScalarValue, Selection,
 };
 
+/*
 impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
     fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
     where
@@ -146,3 +147,4 @@ impl<S> reflect::BaseSubTypes<S> for str {
 impl<S> reflect::WrappedType<S> for str {
     const VALUE: reflect::WrappedValue = reflect::wrap::SINGULAR;
 }
+*/
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
index a3022e412..ad4cd8edb 100644
--- a/juniper/src/types/vec.rs
+++ b/juniper/src/types/vec.rs
@@ -9,6 +9,7 @@ use crate::{
 
 use super::iter;
 
+/*
 impl<T, Info, S> resolve::Type<Info, S> for Vec<T>
 where
     T: resolve::Type<Info, S>,
@@ -69,7 +70,7 @@ where
     }
 }
 
-/*
+
 impl<'i, T, Info, S> graphql::InputType<'i, Info, S> for Vec<T>
 where
     T: graphql::InputType<'i, Info, S>,
@@ -79,7 +80,7 @@ where
         T::assert_input_type()
     }
 }
- */
+
 
 impl<T, S> graphql::OutputType<S> for Vec<T>
 where
@@ -110,3 +111,4 @@ where
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
 }
+*/

From 5ab398e22bb47404e90e7758c65040f7eda8f7b7 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 9 Jun 2022 15:39:14 +0200
Subject: [PATCH 24/58] Re-impl renewed traits machinery for other pointer
 types

---
 juniper/src/graphql/mod.rs   |  31 +++-
 juniper/src/resolve/mod.rs   |  32 +++-
 juniper/src/types/arc.rs     | 276 ++++++++++++++++++-----------------
 juniper/src/types/box.rs     |  46 +++---
 juniper/src/types/mod.rs     |   8 +-
 juniper/src/types/rc.rs      | 276 ++++++++++++++++++-----------------
 juniper/src/types/ref.rs     | 268 +++++++++++++++++-----------------
 juniper/src/types/ref_mut.rs | 217 +++++++++++++--------------
 8 files changed, 608 insertions(+), 546 deletions(-)

diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 8fa9391a0..9e0e1af92 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -2,10 +2,10 @@ use crate::{behavior, resolve};
 
 pub use crate::{
     ast::InputValue,
+    executor::Variables,
     macros::{input_value, value, vars},
     resolve::Type,
     value::Value,
-    executor::Variables,
 };
 
 /*
@@ -47,6 +47,21 @@ pub trait Scalar<
     fn assert_scalar();
 }
 
+pub trait ScalarAs<
+    'inp,
+    Wrapper,
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue: 'inp,
+    Behavior: ?Sized = behavior::Standard,
+>:
+    InputTypeAs<'inp, Wrapper, TypeInfo, ScalarValue, Behavior>
+    + OutputType<TypeInfo, Context, ScalarValue, Behavior>
+    + resolve::ScalarToken<ScalarValue, Behavior>
+{
+    fn assert_scalar();
+}
+
 /*
 pub trait Union<S>
  OutputType<S>
@@ -73,6 +88,20 @@ pub trait InputType<
     fn assert_input_type();
 }
 
+pub trait InputTypeAs<
+    'inp,
+    Wrapper,
+    TypeInfo: ?Sized,
+    ScalarValue: 'inp,
+    Behavior: ?Sized = behavior::Standard,
+>:
+    Type<TypeInfo, ScalarValue, Behavior>
+    + resolve::ToInputValue<ScalarValue, Behavior>
+    + resolve::InputValueAs<'inp, Wrapper, ScalarValue, Behavior>
+{
+    fn assert_input_type();
+}
+
 pub trait OutputType<
     TypeInfo: ?Sized,
     Context: ?Sized,
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 21517fc78..206cf950c 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -5,12 +5,6 @@ use crate::{
     reflect, Arguments, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry, Selection,
 };
 
-#[doc(inline)]
-pub use crate::types::{
-    /*arc::TryFromInputValue as InputValueAsArc,*/ r#box::TryFromInputValue as InputValueAsBox,
-    /*r#ref::TryFromInputValue as InputValueAsRef, rc::TryFromInputValue as InputValueAsRc,*/
-};
-
 pub trait Type<TypeInfo: ?Sized, ScalarValue, Behavior: ?Sized = behavior::Standard> {
     fn meta<'r>(
         registry: &mut Registry<'r, ScalarValue>,
@@ -179,6 +173,32 @@ pub trait InputValueOwned<ScalarValue, Behavior: ?Sized = behavior::Standard>:
 
 impl<T, SV, BH: ?Sized> InputValueOwned<SV, BH> for T where T: for<'i> InputValue<'i, SV, BH> {}
 
+pub trait InputValueAs<'input, Wrapper, ScalarValue: 'input, Behavior: ?Sized = behavior::Standard>
+{
+    type Error: IntoFieldError<ScalarValue>;
+
+    fn try_from_input_value(
+        v: &'input graphql::InputValue<ScalarValue>,
+    ) -> Result<Wrapper, Self::Error>;
+
+    fn try_from_implicit_null() -> Result<Wrapper, Self::Error> {
+        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
+    }
+}
+
+pub trait InputValueAsRef<ScalarValue, Behavior: ?Sized = behavior::Standard> {
+    type Error: IntoFieldError<ScalarValue>;
+
+    fn try_from_input_value(v: &graphql::InputValue<ScalarValue>) -> Result<&Self, Self::Error>;
+
+    fn try_from_implicit_null<'a>() -> Result<&'a Self, Self::Error>
+    where
+        ScalarValue: 'a,
+    {
+        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
+    }
+}
+
 pub trait ScalarToken<ScalarValue, Behavior: ?Sized = behavior::Standard> {
     fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<ScalarValue, ParseError<'_>>;
 }
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 3c6d12d05..7000e4457 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -6,277 +6,287 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
-    IntoFieldError, Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
-/*
-impl<T, Info, S> resolve::Type<Info, S> for Arc<T>
+impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Arc<T>
 where
-    T: resolve::Type<Info, S> + ?Sized,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
         T::meta(registry, info)
     }
 }
 
-impl<T, Info> resolve::TypeName<Info> for Arc<T>
+impl<T, TI, BH> resolve::TypeName<TI, BH> for Arc<T>
 where
-    T: resolve::TypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::TypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn type_name(info: &Info) -> &str {
+    fn type_name(info: &TI) -> &str {
         T::type_name(info)
     }
 }
 
-impl<T, Info> resolve::ConcreteTypeName<Info> for Arc<T>
+impl<T, TI, BH> resolve::ConcreteTypeName<TI, BH> for Arc<T>
 where
-    T: resolve::ConcreteTypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::ConcreteTypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
         (**self).concrete_type_name(info)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Arc<T>
+impl<T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for Arc<T>
 where
-    T: resolve::Value<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_value(selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_value(selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Arc<T>
+impl<T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for Arc<T>
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_value_async(selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_value_async(selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for Arc<T>
+impl<T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Arc<T>
 where
-    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value(
         &self,
         type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_concrete_value(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for Arc<T>
+impl<T, TI, CX, SV, BH> resolve::ConcreteValueAsync<TI, CX, SV, BH> for Arc<T>
 where
-    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value_async<'r>(
         &'r self,
         type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for Arc<T>
+impl<T, TI, CX, SV, BH> resolve::Field<TI, CX, SV, BH> for Arc<T>
 where
-    T: resolve::Field<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Field<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field(
         &self,
         field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_field(field_name, arguments, info, executor)
+        arguments: &Arguments<SV>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_field(field_name, arguments, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for Arc<T>
+impl<T, TI, CX, SV, BH> resolve::FieldAsync<TI, CX, SV, BH> for Arc<T>
 where
-    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::FieldAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field_async<'r>(
         &'r self,
         field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_field_async(field_name, arguments, info, executor)
+        arguments: &'r Arguments<SV>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_field_async(field_name, arguments, type_info, executor)
     }
 }
 
-impl<T, S> resolve::ToInputValue<S> for Arc<T>
+impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Arc<T>
 where
-    T: resolve::ToInputValue<S> + ?Sized,
+    T: resolve::ToInputValue<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         (**self).to_input_value()
     }
 }
 
-impl<'inp, T, S> resolve::InputValue<'inp, S> for Arc<T>
+impl<'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Arc<T>
 where
-    T: resolve::InputValueAsArc<'inp, S> + ?Sized,
-    S: 'inp,
+    T: resolve::InputValueAs<'i, Self, SV, BH> + ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValueAsArc<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsArc<'inp, S>>::try_from_input_value(v)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        T::try_from_input_value(v)
     }
 
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsArc<'inp, S>>::try_from_implicit_null()
+        T::try_from_implicit_null()
     }
 }
 
-pub trait TryFromInputValue<'input, S: 'input = DefaultScalarValue> {
-    type Error: IntoFieldError<S>;
-
-    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Arc<Self>, Self::Error>;
-
-    fn try_from_implicit_null() -> Result<Arc<Self>, Self::Error> {
-        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
-    }
-}
-
-impl<'inp, T, S> TryFromInputValue<'inp, S> for T
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Arc<T>, SV, BH> for T
 where
-    T: resolve::InputValue<'inp, S>,
-    S: 'inp,
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Arc<Self>, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Arc::new)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Arc<Self>, Self::Error> {
+        T::try_from_input_value(v).map(Arc::new)
     }
 
     fn try_from_implicit_null() -> Result<Arc<Self>, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Arc::new)
+        T::try_from_implicit_null().map(Arc::new)
     }
 }
 
-impl<T, S> resolve::ScalarToken<S> for Arc<T>
+impl<T, SV, BH> resolve::ScalarToken<SV, BH> for Arc<T>
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ScalarToken<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
         T::parse_scalar_token(token)
     }
 }
 
-impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Arc<T>
+impl<'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Arc<T>
 where
-    T: graphql::InputType<'i, Info, S> + ?Sized,
-    Info: ?Sized,
+    T: graphql::InputTypeAs<'i, Self, TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
 
-impl<T, S> graphql::OutputType<S> for Arc<T>
+impl<'i, T, TI, SV, BH> graphql::InputTypeAs<'i, Arc<T>, TI, SV, BH> for T
 where
-    T: graphql::OutputType<S> + ?Sized,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    fn assert_output_type() {
-        T::assert_output_type()
-    }
-}
-
-impl<T, S> graphql::Interface<S> for Arc<T>
-where
-    T: graphql::Interface<S> + ?Sized,
-{
-    fn assert_interface() {
-        T::assert_interface()
+    fn assert_input_type() {
+        T::assert_input_type()
     }
 }
 
-impl<T, S> graphql::Object<S> for Arc<T>
+impl<T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for Arc<T>
 where
-    T: graphql::Object<S> + ?Sized,
+    T: graphql::OutputType<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
-    fn assert_object() {
-        T::assert_object()
+    fn assert_output_type() {
+        T::assert_output_type()
     }
 }
 
-impl<T, S> graphql::Scalar<S> for Arc<T>
+impl<'i, T, TI, CX, SV, BH> graphql::Scalar<'i, TI, CX, SV, BH> for Arc<T>
 where
-    T: graphql::Scalar<S> + ?Sized,
+    T: graphql::ScalarAs<'i, Self, TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_scalar() {
         T::assert_scalar()
     }
 }
 
-impl<T, S> graphql::Union<S> for Arc<T>
+impl<'i, T, TI, CX, SV, BH> graphql::ScalarAs<'i, Arc<T>, TI, CX, SV, BH> for T
 where
-    T: graphql::Union<S> + ?Sized,
+    T: graphql::Scalar<'i, TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    fn assert_union() {
-        T::assert_union()
+    fn assert_scalar() {
+        T::assert_scalar()
     }
 }
 
-impl<T, S> reflect::BaseType<S> for Arc<T>
+impl<T, BH> reflect::BaseType<BH> for Arc<T>
 where
-    T: reflect::BaseType<S> + ?Sized,
+    T: reflect::BaseType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S> reflect::BaseSubTypes<S> for Arc<T>
+impl<T, BH> reflect::BaseSubTypes<BH> for Arc<T>
 where
-    T: reflect::BaseSubTypes<S> + ?Sized,
+    T: reflect::BaseSubTypes<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S> reflect::WrappedType<S> for Arc<T>
+impl<T, BH> reflect::WrappedType<BH> for Arc<T>
 where
-    T: reflect::WrappedType<S> + ?Sized,
+    T: reflect::WrappedType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
-*/
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 68edcc005..c5257b5b0 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -1,11 +1,10 @@
 //! GraphQL implementation for [`Box`].
 
 use crate::{
-    behavior, graphql,
+    graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry,
-    Selection,
+    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
 impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Box<T>
@@ -162,7 +161,7 @@ where
 
 impl<'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Box<T>
 where
-    T: resolve::InputValueAsBox<'i, SV, BH> + ?Sized,
+    T: resolve::InputValueAs<'i, Self, SV, BH> + ?Sized,
     SV: 'i,
     BH: ?Sized,
 {
@@ -177,19 +176,7 @@ where
     }
 }
 
-pub trait TryFromInputValue<'input, ScalarValue: 'input, Behavior: ?Sized = behavior::Standard> {
-    type Error: IntoFieldError<ScalarValue>;
-
-    fn try_from_input_value(
-        v: &'input graphql::InputValue<ScalarValue>,
-    ) -> Result<Box<Self>, Self::Error>;
-
-    fn try_from_implicit_null() -> Result<Box<Self>, Self::Error> {
-        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
-    }
-}
-
-impl<'i, T, SV, BH> TryFromInputValue<'i, SV, BH> for T
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Box<T>, SV, BH> for T
 where
     T: resolve::InputValue<'i, SV, BH>,
     SV: 'i,
@@ -217,6 +204,18 @@ where
 }
 
 impl<'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Box<T>
+where
+    T: graphql::InputTypeAs<'i, Self, TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<'i, T, TI, SV, BH> graphql::InputTypeAs<'i, Box<T>, TI, SV, BH> for T
 where
     T: graphql::InputType<'i, TI, SV, BH>,
     TI: ?Sized,
@@ -241,6 +240,19 @@ where
 }
 
 impl<'i, T, TI, CX, SV, BH> graphql::Scalar<'i, TI, CX, SV, BH> for Box<T>
+where
+    T: graphql::ScalarAs<'i, Self, TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
+{
+    fn assert_scalar() {
+        T::assert_scalar()
+    }
+}
+
+impl<'i, T, TI, CX, SV, BH> graphql::ScalarAs<'i, Box<T>, TI, CX, SV, BH> for T
 where
     T: graphql::Scalar<'i, TI, CX, SV, BH>,
     TI: ?Sized,
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 5e529d61a..d331959a3 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -1,11 +1,11 @@
-pub mod arc;
+mod arc;
 mod array;
-pub mod r#box;
+mod r#box;
 pub mod iter;
 mod nullable;
 mod option;
-pub mod rc;
-pub mod r#ref;
+mod rc;
+mod r#ref;
 mod ref_mut;
 mod result;
 mod slice;
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 88f7089de..53a3248f0 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -6,277 +6,287 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
-    IntoFieldError, Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
-/*
-impl<T, Info, S> resolve::Type<Info, S> for Rc<T>
+impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Rc<T>
 where
-    T: resolve::Type<Info, S> + ?Sized,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
         T::meta(registry, info)
     }
 }
 
-impl<T, Info> resolve::TypeName<Info> for Rc<T>
+impl<T, TI, BH> resolve::TypeName<TI, BH> for Rc<T>
 where
-    T: resolve::TypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::TypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn type_name(info: &Info) -> &str {
+    fn type_name(info: &TI) -> &str {
         T::type_name(info)
     }
 }
 
-impl<T, Info> resolve::ConcreteTypeName<Info> for Rc<T>
+impl<T, TI, BH> resolve::ConcreteTypeName<TI, BH> for Rc<T>
 where
-    T: resolve::ConcreteTypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::ConcreteTypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
         (**self).concrete_type_name(info)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Rc<T>
+impl<T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for Rc<T>
 where
-    T: resolve::Value<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_value(selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_value(selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Rc<T>
+impl<T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for Rc<T>
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_value_async(selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_value_async(selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for Rc<T>
+impl<T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Rc<T>
 where
-    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value(
         &self,
         type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_concrete_value(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for Rc<T>
+impl<T, TI, CX, SV, BH> resolve::ConcreteValueAsync<TI, CX, SV, BH> for Rc<T>
 where
-    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value_async<'r>(
         &'r self,
         type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for Rc<T>
+impl<T, TI, CX, SV, BH> resolve::Field<TI, CX, SV, BH> for Rc<T>
 where
-    T: resolve::Field<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Field<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field(
         &self,
         field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_field(field_name, arguments, info, executor)
+        arguments: &Arguments<SV>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_field(field_name, arguments, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for Rc<T>
+impl<T, TI, CX, SV, BH> resolve::FieldAsync<TI, CX, SV, BH> for Rc<T>
 where
-    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::FieldAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field_async<'r>(
         &'r self,
         field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_field_async(field_name, arguments, info, executor)
+        arguments: &'r Arguments<SV>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_field_async(field_name, arguments, type_info, executor)
     }
 }
 
-impl<T, S> resolve::ToInputValue<S> for Rc<T>
+impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Rc<T>
 where
-    T: resolve::ToInputValue<S> + ?Sized,
+    T: resolve::ToInputValue<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         (**self).to_input_value()
     }
 }
 
-impl<'inp, T, S> resolve::InputValue<'inp, S> for Rc<T>
+impl<'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Rc<T>
 where
-    T: resolve::InputValueAsRc<'inp, S> + ?Sized,
-    S: 'inp,
+    T: resolve::InputValueAs<'i, Self, SV, BH> + ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValueAsRc<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsRc<'inp, S>>::try_from_input_value(v)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        T::try_from_input_value(v)
     }
 
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsRc<'inp, S>>::try_from_implicit_null()
+        T::try_from_implicit_null()
     }
 }
 
-pub trait TryFromInputValue<'input, S: 'input = DefaultScalarValue> {
-    type Error: IntoFieldError<S>;
-
-    fn try_from_input_value(v: &'input graphql::InputValue<S>) -> Result<Rc<Self>, Self::Error>;
-
-    fn try_from_implicit_null() -> Result<Rc<Self>, Self::Error> {
-        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
-    }
-}
-
-impl<'inp, T, S> TryFromInputValue<'inp, S> for T
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Rc<T>, SV, BH> for T
 where
-    T: resolve::InputValue<'inp, S>,
-    S: 'inp,
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Rc<Self>, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Rc::new)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Rc<Self>, Self::Error> {
+        T::try_from_input_value(v).map(Rc::new)
     }
 
     fn try_from_implicit_null() -> Result<Rc<Self>, Self::Error> {
-        <T as resolve::InputValue<'inp, S>>::try_from_implicit_null().map(Rc::new)
+        T::try_from_implicit_null().map(Rc::new)
     }
 }
 
-impl<T, S> resolve::ScalarToken<S> for Rc<T>
+impl<T, SV, BH> resolve::ScalarToken<SV, BH> for Rc<T>
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ScalarToken<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
         T::parse_scalar_token(token)
     }
 }
 
-impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Rc<T>
+impl<'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Rc<T>
 where
-    T: graphql::InputType<'i, Info, S> + ?Sized,
-    Info: ?Sized,
+    T: graphql::InputTypeAs<'i, Self, TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
 
-impl<T, S> graphql::OutputType<S> for Rc<T>
+impl<'i, T, TI, SV, BH> graphql::InputTypeAs<'i, Rc<T>, TI, SV, BH> for T
 where
-    T: graphql::OutputType<S> + ?Sized,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    fn assert_output_type() {
-        T::assert_output_type()
-    }
-}
-
-impl<T, S> graphql::Interface<S> for Rc<T>
-where
-    T: graphql::Interface<S> + ?Sized,
-{
-    fn assert_interface() {
-        T::assert_interface()
+    fn assert_input_type() {
+        T::assert_input_type()
     }
 }
 
-impl<T, S> graphql::Object<S> for Rc<T>
+impl<T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for Rc<T>
 where
-    T: graphql::Object<S> + ?Sized,
+    T: graphql::OutputType<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
-    fn assert_object() {
-        T::assert_object()
+    fn assert_output_type() {
+        T::assert_output_type()
     }
 }
 
-impl<T, S> graphql::Scalar<S> for Rc<T>
+impl<'i, T, TI, CX, SV, BH> graphql::Scalar<'i, TI, CX, SV, BH> for Rc<T>
 where
-    T: graphql::Scalar<S> + ?Sized,
+    T: graphql::ScalarAs<'i, Self, TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_scalar() {
         T::assert_scalar()
     }
 }
 
-impl<T, S> graphql::Union<S> for Rc<T>
+impl<'i, T, TI, CX, SV, BH> graphql::ScalarAs<'i, Rc<T>, TI, CX, SV, BH> for T
 where
-    T: graphql::Union<S> + ?Sized,
+    T: graphql::Scalar<'i, TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    fn assert_union() {
-        T::assert_union()
+    fn assert_scalar() {
+        T::assert_scalar()
     }
 }
 
-impl<T, S> reflect::BaseType<S> for Rc<T>
+impl<T, BH> reflect::BaseType<BH> for Rc<T>
 where
-    T: reflect::BaseType<S> + ?Sized,
+    T: reflect::BaseType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S> reflect::BaseSubTypes<S> for Rc<T>
+impl<T, BH> reflect::BaseSubTypes<BH> for Rc<T>
 where
-    T: reflect::BaseSubTypes<S> + ?Sized,
+    T: reflect::BaseSubTypes<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S> reflect::WrappedType<S> for Rc<T>
+impl<T, BH> reflect::WrappedType<BH> for Rc<T>
 where
-    T: reflect::WrappedType<S> + ?Sized,
+    T: reflect::WrappedType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
-*/
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index e087482a4..7112c99bc 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -6,264 +6,266 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    reflect, resolve, Arguments, BoxFuture, DefaultScalarValue, ExecutionResult, Executor,
-    IntoFieldError, Registry, Selection,
+    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
-/*
-impl<'me, T, Info, S> resolve::Type<Info, S> for &'me T
+impl<'me, T, TI, SV, BH> resolve::Type<TI, SV, BH> for &'me T
 where
-    T: resolve::Type<Info, S> + ?Sized,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
         T::meta(registry, info)
     }
 }
 
-impl<'me, T, Info> resolve::TypeName<Info> for &'me T
+impl<'me, T, TI, BH> resolve::TypeName<TI, BH> for &'me T
 where
-    T: resolve::TypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::TypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn type_name(info: &Info) -> &str {
+    fn type_name(info: &TI) -> &str {
         T::type_name(info)
     }
 }
 
-impl<'me, T, Info> resolve::ConcreteTypeName<Info> for &'me T
+impl<'me, T, TI, BH> resolve::ConcreteTypeName<TI, BH> for &'me T
 where
-    T: resolve::ConcreteTypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::ConcreteTypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
         (**self).concrete_type_name(info)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for &'me T
+impl<'me, T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for &'me T
 where
-    T: resolve::Value<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_value(selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_value(selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for &'me T
+impl<'me, T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for &'me T
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_value_async(selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_value_async(selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for &'me T
+impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for &'me T
 where
-    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value(
         &self,
         type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_concrete_value(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for &'me T
+impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValueAsync<TI, CX, SV, BH> for &'me T
 where
-    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value_async<'r>(
         &'r self,
         type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for &'me T
+impl<'me, T, TI, CX, SV, BH> resolve::Field<TI, CX, SV, BH> for &'me T
 where
-    T: resolve::Field<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Field<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field(
         &self,
         field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_field(field_name, arguments, info, executor)
+        arguments: &Arguments<SV>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_field(field_name, arguments, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for &'me T
+impl<'me, T, TI, CX, SV, BH> resolve::FieldAsync<TI, CX, SV, BH> for &'me T
 where
-    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::FieldAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field_async<'r>(
         &'r self,
         field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_field_async(field_name, arguments, info, executor)
+        arguments: &'r Arguments<SV>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_field_async(field_name, arguments, type_info, executor)
     }
 }
 
-impl<'me, T, S> resolve::ToInputValue<S> for &'me T
+impl<'me, T, SV, BH> resolve::ToInputValue<SV, BH> for &'me T
 where
-    T: resolve::ToInputValue<S> + ?Sized,
+    T: resolve::ToInputValue<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         (**self).to_input_value()
     }
 }
 
-impl<'inp: 'me, 'me, T, S: 'inp> resolve::InputValue<'inp, S> for &'me T
+impl<'me, 'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for &'me T
 where
-    T: resolve::InputValueAsRef<S> + ?Sized,
+    'i: 'me,
+    T: resolve::InputValueAs<'i, &'me T, SV, BH> + ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValueAsRef<S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsRef<S>>::try_from_input_value(v)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        T::try_from_input_value(v)
     }
 
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        <T as resolve::InputValueAsRef<S>>::try_from_implicit_null()
+        T::try_from_implicit_null()
     }
 }
 
-pub trait TryFromInputValue<S = DefaultScalarValue> {
-    type Error: IntoFieldError<S>;
+impl<'me, 'i, T, SV, BH> resolve::InputValueAs<'i, &'me T, SV, BH> for T
+where
+    'i: 'me,
+    T: resolve::InputValueAsRef<SV, BH> + ?Sized,
+    SV: 'i,
+    BH: ?Sized,
+{
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error>;
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<&'me T, Self::Error> {
+        T::try_from_input_value(v)
+    }
 
-    fn try_from_implicit_null<'a>() -> Result<&'a Self, Self::Error>
-    where
-        S: 'a,
-    {
-        Self::try_from_input_value(&graphql::InputValue::<S>::Null)
+    fn try_from_implicit_null() -> Result<&'me T, Self::Error> {
+        T::try_from_implicit_null()
     }
 }
 
-impl<'me, T, S> resolve::ScalarToken<S> for &'me T
+impl<'me, T, SV, BH> resolve::ScalarToken<SV, BH> for &'me T
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ScalarToken<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
         T::parse_scalar_token(token)
     }
 }
 
-/*
-impl<'me, 'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for &'me T
+impl<'me, 'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for &'me T
 where
-    Self: resolve::Type<Info, S> + resolve::ToInputValue<S> + resolve::InputValue<'i, S>,
-    Info: ?Sized,
+    'i: 'me,
+    T: graphql::InputTypeAs<'i, Self, TI, SV, BH> + ?Sized + 'me,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
-}*/
+}
 
-impl<'me, T, S> graphql::OutputType<S> for &'me T
+impl<'me, T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for &'me T
 where
-    T: graphql::OutputType<S> + ?Sized,
+    T: graphql::OutputType<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<'me, T, S> graphql::Interface<S> for &'me T
-where
-    T: graphql::Interface<S> + ?Sized,
-{
-    fn assert_interface() {
-        T::assert_interface()
-    }
-}
-
-impl<'me, T, S> graphql::Object<S> for &'me T
+impl<'me, 'i, T, TI, CX, SV, BH> graphql::Scalar<'i, TI, CX, SV, BH> for &'me T
 where
-    T: graphql::Object<S> + ?Sized,
-{
-    fn assert_object() {
-        T::assert_object()
-    }
-}
-
-impl<'me, T, S> graphql::Scalar<S> for &'me T
-where
-    T: graphql::Scalar<S> + ?Sized,
+    'i: 'me,
+    T: graphql::ScalarAs<'i, Self, TI, CX, SV, BH> + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_scalar() {
         T::assert_scalar()
     }
 }
 
-impl<'me, T, S> graphql::Union<S> for &'me T
-where
-    T: graphql::Union<S> + ?Sized,
-{
-    fn assert_union() {
-        T::assert_union()
-    }
-}
-
-impl<'me, T, S> reflect::BaseType<S> for &'me T
+impl<'me, T, BH> reflect::BaseType<BH> for &'me T
 where
-    T: reflect::BaseType<S> + ?Sized,
+    T: reflect::BaseType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<'me, T, S> reflect::BaseSubTypes<S> for &'me T
+impl<'me, T, BH> reflect::BaseSubTypes<BH> for &'me T
 where
-    T: reflect::BaseSubTypes<S> + ?Sized,
+    T: reflect::BaseSubTypes<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<'me, T, S> reflect::WrappedType<S> for &'me T
+impl<'me, T, BH> reflect::WrappedType<BH> for &'me T
 where
-    T: reflect::WrappedType<S> + ?Sized,
+    T: reflect::WrappedType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
-*/
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index 31a572119..e3911abdb 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -9,221 +9,200 @@ use crate::{
     reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
 };
 
-/*
-impl<'me, T, Info, S> resolve::Type<Info, S> for &'me mut T
+impl<'me, T, TI, SV, BH> resolve::Type<TI, SV, BH> for &'me mut T
 where
-    T: resolve::Type<Info, S> + ?Sized,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
         T::meta(registry, info)
     }
 }
 
-impl<'me, T, Info> resolve::TypeName<Info> for &'me mut T
+impl<'me, T, TI, BH> resolve::TypeName<TI, BH> for &'me mut T
 where
-    T: resolve::TypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::TypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn type_name(info: &Info) -> &str {
+    fn type_name(info: &TI) -> &str {
         T::type_name(info)
     }
 }
 
-impl<'me, T, Info> resolve::ConcreteTypeName<Info> for &'me mut T
+impl<'me, T, TI, BH> resolve::ConcreteTypeName<TI, BH> for &'me mut T
 where
-    T: resolve::ConcreteTypeName<Info> + ?Sized,
-    Info: ?Sized,
+    T: resolve::ConcreteTypeName<TI, BH> + ?Sized,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i Info) -> &'i str {
+    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
         (**self).concrete_type_name(info)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for &'me mut T
+impl<'me, T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for &'me mut T
 where
-    T: resolve::Value<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_value(selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_value(selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for &'me mut T
+impl<'me, T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for &'me mut T
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_value_async(selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_value_async(selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::ConcreteValue<Info, Ctx, S> for &'me mut T
+impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for &'me mut T
 where
-    T: resolve::ConcreteValue<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value(
         &self,
         type_name: &str,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_concrete_value(type_name, selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_concrete_value(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::ConcreteValueAsync<Info, Ctx, S> for &'me mut T
+impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValueAsync<TI, CX, SV, BH> for &'me mut T
 where
-    T: resolve::ConcreteValueAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ConcreteValueAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_concrete_value_async<'r>(
         &'r self,
         type_name: &str,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_concrete_value_async(type_name, selection_set, info, executor)
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::Field<Info, Ctx, S> for &'me mut T
+impl<'me, T, TI, CX, SV, BH> resolve::Field<TI, CX, SV, BH> for &'me mut T
 where
-    T: resolve::Field<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Field<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field(
         &self,
         field_name: &str,
-        arguments: &Arguments<S>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        (**self).resolve_field(field_name, arguments, info, executor)
+        arguments: &Arguments<SV>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_field(field_name, arguments, type_info, executor)
     }
 }
 
-impl<'me, T, Info, Ctx, S> resolve::FieldAsync<Info, Ctx, S> for &'me mut T
+impl<'me, T, TI, CX, SV, BH> resolve::FieldAsync<TI, CX, SV, BH> for &'me mut T
 where
-    T: resolve::FieldAsync<Info, Ctx, S> + ?Sized,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::FieldAsync<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_field_async<'r>(
         &'r self,
         field_name: &'r str,
-        arguments: &'r Arguments<S>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
-        (**self).resolve_field_async(field_name, arguments, info, executor)
+        arguments: &'r Arguments<SV>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_field_async(field_name, arguments, type_info, executor)
     }
 }
 
-impl<'me, T, S> resolve::ToInputValue<S> for &'me mut T
+impl<'me, T, SV, BH> resolve::ToInputValue<SV, BH> for &'me mut T
 where
-    T: resolve::ToInputValue<S> + ?Sized,
+    T: resolve::ToInputValue<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         (**self).to_input_value()
     }
 }
 
-impl<'me, T, S> resolve::ScalarToken<S> for &'me mut T
+impl<'me, T, SV, BH> resolve::ScalarToken<SV, BH> for &'me mut T
 where
-    T: resolve::ScalarToken<S> + ?Sized,
+    T: resolve::ScalarToken<SV, BH> + ?Sized,
+    BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
         T::parse_scalar_token(token)
     }
 }
 
-impl<'me, T, S> graphql::OutputType<S> for &'me mut T
+impl<'me, T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for &'me mut T
 where
-    T: graphql::OutputType<S> + ?Sized,
+    T: graphql::OutputType<TI, CX, SV, BH> + ?Sized,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<'me, T, S> graphql::Interface<S> for &'me mut T
+impl<'me, T, BH> reflect::BaseType<BH> for &'me mut T
 where
-    T: graphql::Interface<S> + ?Sized,
-{
-    fn assert_interface() {
-        T::assert_interface()
-    }
-}
-
-impl<'me, T, S> graphql::Object<S> for &'me mut T
-where
-    T: graphql::Object<S> + ?Sized,
-{
-    fn assert_object() {
-        T::assert_object()
-    }
-}
-
-impl<'me, T, S> graphql::Scalar<S> for &'me mut T
-where
-    T: graphql::Scalar<S> + ?Sized,
-{
-    fn assert_scalar() {
-        T::assert_scalar()
-    }
-}
-
-impl<'me, T, S> graphql::Union<S> for &'me mut T
-where
-    T: graphql::Union<S> + ?Sized,
-{
-    fn assert_union() {
-        T::assert_union()
-    }
-}
-
-impl<'me, T, S> reflect::BaseType<S> for &'me mut T
-where
-    T: reflect::BaseType<S> + ?Sized,
+    T: reflect::BaseType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<'me, T, S> reflect::BaseSubTypes<S> for &'me mut T
+impl<'me, T, BH> reflect::BaseSubTypes<BH> for &'me mut T
 where
-    T: reflect::BaseSubTypes<S> + ?Sized,
+    T: reflect::BaseSubTypes<BH> + ?Sized,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<'me, T, S> reflect::WrappedType<S> for &'me mut T
+impl<'me, T, BH> reflect::WrappedType<BH> for &'me mut T
 where
-    T: reflect::WrappedType<S> + ?Sized,
+    T: reflect::WrappedType<BH> + ?Sized,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
-*/

From be010e812365ae35de545dbc77f9ef3907d907b1 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 9 Jun 2022 16:16:30 +0200
Subject: [PATCH 25/58] Re-impl renewed traits machinery for container types

---
 juniper/src/executor/mod.rs   |   9 +--
 juniper/src/resolve/mod.rs    |   6 +-
 juniper/src/types/arc.rs      |  12 ++--
 juniper/src/types/box.rs      |  12 ++--
 juniper/src/types/nullable.rs | 113 +++++++++++++++++++---------------
 juniper/src/types/option.rs   | 108 ++++++++++++++++++--------------
 juniper/src/types/rc.rs       |  12 ++--
 juniper/src/types/ref.rs      |  12 ++--
 juniper/src/types/ref_mut.rs  |  12 ++--
 9 files changed, 164 insertions(+), 132 deletions(-)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 7603acb18..3c6fd9072 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -1369,12 +1369,13 @@ impl<'r, S: 'r> Registry<'r, S> {
     /// [`graphql::Type`].
     ///
     /// [`graphql::Type`]: resolve::Type
-    pub fn build_nullable_type_new<T, Info>(&mut self, info: &Info) -> NullableMeta<'r>
+    pub fn build_nullable_type_reworked<T, BH, TI>(&mut self, type_info: &TI) -> NullableMeta<'r>
     where
-        T: resolve::Type<Info, S> + ?Sized,
-        Info: ?Sized,
+        T: resolve::Type<TI, S, BH> + ?Sized,
+        BH: ?Sized,
+        TI: ?Sized,
     {
-        NullableMeta::new(T::meta(self, info).as_type())
+        NullableMeta::new(T::meta(self, type_info).as_type())
     }
 
     /// Creates an [`ObjectMeta`] type with the given `fields`.
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 206cf950c..868ce5003 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -162,7 +162,7 @@ pub trait InputValue<'input, ScalarValue: 'input, Behavior: ?Sized = behavior::S
     ) -> Result<Self, Self::Error>;
 
     fn try_from_implicit_null() -> Result<Self, Self::Error> {
-        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
+        Self::try_from_input_value(&graphql::InputValue::Null)
     }
 }
 
@@ -182,7 +182,7 @@ pub trait InputValueAs<'input, Wrapper, ScalarValue: 'input, Behavior: ?Sized =
     ) -> Result<Wrapper, Self::Error>;
 
     fn try_from_implicit_null() -> Result<Wrapper, Self::Error> {
-        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
+        Self::try_from_input_value(&graphql::InputValue::Null)
     }
 }
 
@@ -195,7 +195,7 @@ pub trait InputValueAsRef<ScalarValue, Behavior: ?Sized = behavior::Standard> {
     where
         ScalarValue: 'a,
     {
-        Self::try_from_input_value(&graphql::InputValue::<ScalarValue>::Null)
+        Self::try_from_input_value(&graphql::InputValue::Null)
     }
 }
 
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index 7000e4457..ef7337991 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -15,11 +15,11 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV>
     where
         SV: 'r,
     {
-        T::meta(registry, info)
+        T::meta(registry, type_info)
     }
 }
 
@@ -29,8 +29,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn type_name(info: &TI) -> &str {
-        T::type_name(info)
+    fn type_name(type_info: &TI) -> &str {
+        T::type_name(type_info)
     }
 }
 
@@ -40,8 +40,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
-        (**self).concrete_type_name(info)
+    fn concrete_type_name<'i>(&self, type_info: &'i TI) -> &'i str {
+        (**self).concrete_type_name(type_info)
     }
 }
 
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index c5257b5b0..ec0194612 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -13,11 +13,11 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV>
     where
         SV: 'r,
     {
-        T::meta(registry, info)
+        T::meta(registry, type_info)
     }
 }
 
@@ -27,8 +27,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn type_name(info: &TI) -> &str {
-        T::type_name(info)
+    fn type_name(type_info: &TI) -> &str {
+        T::type_name(type_info)
     }
 }
 
@@ -38,8 +38,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
-        (**self).concrete_type_name(info)
+    fn concrete_type_name<'i>(&self, type_info: &'i TI) -> &'i str {
+        (**self).concrete_type_name(type_info)
     }
 }
 
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index b48064df5..7728959c7 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -272,82 +272,89 @@ impl<T: Clone> Nullable<&mut T> {
     }
 }
 
-/*
-impl<T, Info, S> resolve::Type<Info, S> for Nullable<T>
+impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Nullable<T>
 where
-    T: resolve::Type<Info, S>,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH>,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
-        registry.build_nullable_type_new::<T, _>(info).into_meta()
+        registry
+            .build_nullable_type_reworked::<T, BH, _>(type_info)
+            .into_meta()
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Nullable<T>
+impl<T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for Nullable<T>
 where
-    T: resolve::Value<Info, Ctx, S>,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
         match self {
-            Self::Some(v) => v.resolve_value(selection_set, info, executor),
-            Self::ExplicitNull | Self::ImplicitNull => Ok(graphql::Value::Null),
+            Self::Some(v) => v.resolve_value(selection_set, type_info, executor),
+            Self::ImplicitNull | Self::ExplicitNull => Ok(graphql::Value::Null),
         }
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Nullable<T>
+impl<T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for Nullable<T>
 where
-    T: resolve::ValueAsync<Info, Ctx, S>,
-    Info: ?Sized,
-    Ctx: ?Sized,
-    S: Send,
+    T: resolve::ValueAsync<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: Send,
+    BH: ?Sized,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
         match self {
-            Self::Some(v) => v.resolve_value_async(selection_set, info, executor),
-            Self::ExplicitNull | Self::ImplicitNull => Box::pin(future::ok(graphql::Value::Null)),
+            Self::Some(v) => v.resolve_value_async(selection_set, type_info, executor),
+            Self::ImplicitNull | Self::ExplicitNull => Box::pin(future::ok(graphql::Value::Null)),
         }
     }
 }
 
-impl<T, S> resolve::ToInputValue<S> for Nullable<T>
+impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Nullable<T>
 where
-    T: resolve::ToInputValue<S>,
+    T: resolve::ToInputValue<SV, BH>,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         match self {
             Self::Some(v) => v.to_input_value(),
-            Self::ExplicitNull | Self::ImplicitNull => graphql::InputValue::Null,
+            Self::ImplicitNull | Self::ExplicitNull => graphql::InputValue::Null,
         }
     }
 }
 
-impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Nullable<T>
+impl<'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Nullable<T>
 where
-    T: resolve::InputValue<'inp, S>,
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp InputValue<S>) -> Result<Self, Self::Error> {
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
         if v.is_null() {
             Ok(Self::ExplicitNull)
         } else {
-            <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Self::Some)
+            T::try_from_input_value(v).map(Self::Some)
         }
     }
 
@@ -356,47 +363,55 @@ where
     }
 }
 
-impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Nullable<T>
+impl<'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Nullable<T>
 where
-    T: graphql::InputType<'i, Info, S>,
-    Info: ?Sized,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
 
-impl<T, S> graphql::OutputType<S> for Nullable<T>
+impl<T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for Nullable<T>
 where
-    T: graphql::OutputType<S>,
+    T: graphql::OutputType<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: resolve::ValueAsync<TI, CX, SV, BH>,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<T, S> reflect::BaseType<S> for Nullable<T>
+impl<T, BH> reflect::BaseType<BH> for Nullable<T>
 where
-    T: reflect::BaseType<S>,
+    T: reflect::BaseType<BH>,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S> reflect::BaseSubTypes<S> for Nullable<T>
+impl<T, BH> reflect::BaseSubTypes<BH> for Nullable<T>
 where
-    T: reflect::BaseSubTypes<S>,
+    T: reflect::BaseSubTypes<BH>,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S> reflect::WrappedType<S> for Nullable<T>
+impl<T, BH> reflect::WrappedType<BH> for Nullable<T>
 where
-    T: reflect::WrappedType<S>,
+    T: reflect::WrappedType<BH>,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::nullable(T::VALUE);
 }
 
- */
 ////////////////////////////////////////////////////////////////////////////////
 
 impl<S, T> GraphQLType<S> for Nullable<T>
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index 7f3ef70d9..0a83cc628 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -8,64 +8,70 @@ use crate::{
     schema::meta::MetaType,
     BoxFuture, Selection,
 };
-/*
-impl<T, Info, S> resolve::Type<Info, S> for Option<T>
+
+impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Option<T>
 where
-    T: resolve::Type<Info, S>,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH>,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
-        registry.build_nullable_type_new::<T, _>(info).into_meta()
+        registry
+            .build_nullable_type_reworked::<T, BH, _>(type_info)
+            .into_meta()
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Option<T>
+impl<T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for Option<T>
 where
-    T: resolve::Value<Info, Ctx, S>,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
         match self {
-            Some(v) => v.resolve_value(selection_set, info, executor),
+            Some(v) => v.resolve_value(selection_set, type_info, executor),
             None => Ok(graphql::Value::Null),
         }
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Option<T>
+impl<T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for Option<T>
 where
-    T: resolve::ValueAsync<Info, Ctx, S>,
-    Info: ?Sized,
-    Ctx: ?Sized,
-    S: Send,
+    T: resolve::ValueAsync<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: Send,
+    BH: ?Sized,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
         match self {
-            Some(v) => v.resolve_value_async(selection_set, info, executor),
+            Some(v) => v.resolve_value_async(selection_set, type_info, executor),
             None => Box::pin(future::ok(graphql::Value::Null)),
         }
     }
 }
 
-impl<T, S> resolve::ToInputValue<S> for Option<T>
+impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Option<T>
 where
-    T: resolve::ToInputValue<S>,
+    T: resolve::ToInputValue<SV, BH>,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         match self {
             Some(v) => v.to_input_value(),
             None => graphql::InputValue::Null,
@@ -73,58 +79,68 @@ where
     }
 }
 
-impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Option<T>
+impl<'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Option<T>
 where
-    T: resolve::InputValue<'inp, S>,
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
 {
-    type Error = <T as resolve::InputValue<'inp, S>>::Error;
+    type Error = T::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Self, Self::Error> {
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
         if v.is_null() {
             Ok(None)
         } else {
-            <T as resolve::InputValue<'inp, S>>::try_from_input_value(v).map(Some)
+            T::try_from_input_value(v).map(Some)
         }
     }
 }
 
-impl<'i, T, Info, S: 'i> graphql::InputType<'i, Info, S> for Option<T>
+impl<'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Option<T>
 where
-    T: graphql::InputType<'i, Info, S>,
-    Info: ?Sized,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
 
-impl<T, S> graphql::OutputType<S> for Option<T>
+impl<T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for Option<T>
 where
-    T: graphql::OutputType<S>,
+    T: graphql::OutputType<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: resolve::ValueAsync<TI, CX, SV, BH>,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<T, S> reflect::BaseType<S> for Option<T>
+impl<T, BH> reflect::BaseType<BH> for Option<T>
 where
-    T: reflect::BaseType<S>,
+    T: reflect::BaseType<BH>,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S> reflect::BaseSubTypes<S> for Option<T>
+impl<T, BH> reflect::BaseSubTypes<BH> for Option<T>
 where
-    T: reflect::BaseSubTypes<S>,
+    T: reflect::BaseSubTypes<BH>,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S> reflect::WrappedType<S> for Option<T>
+impl<T, BH> reflect::WrappedType<BH> for Option<T>
 where
-    T: reflect::WrappedType<S>,
+    T: reflect::WrappedType<BH>,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::nullable(T::VALUE);
 }
-*/
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 53a3248f0..950ec0425 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -15,11 +15,11 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV>
     where
         SV: 'r,
     {
-        T::meta(registry, info)
+        T::meta(registry, type_info)
     }
 }
 
@@ -29,8 +29,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn type_name(info: &TI) -> &str {
-        T::type_name(info)
+    fn type_name(type_info: &TI) -> &str {
+        T::type_name(type_info)
     }
 }
 
@@ -40,8 +40,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
-        (**self).concrete_type_name(info)
+    fn concrete_type_name<'i>(&self, type_info: &'i TI) -> &'i str {
+        (**self).concrete_type_name(type_info)
     }
 }
 
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 7112c99bc..9b9668fe3 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -15,11 +15,11 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV>
     where
         SV: 'r,
     {
-        T::meta(registry, info)
+        T::meta(registry, type_info)
     }
 }
 
@@ -29,8 +29,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn type_name(info: &TI) -> &str {
-        T::type_name(info)
+    fn type_name(type_info: &TI) -> &str {
+        T::type_name(type_info)
     }
 }
 
@@ -40,8 +40,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
-        (**self).concrete_type_name(info)
+    fn concrete_type_name<'i>(&self, type_info: &'i TI) -> &'i str {
+        (**self).concrete_type_name(type_info)
     }
 }
 
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index e3911abdb..f24b96a5d 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -15,11 +15,11 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, SV>, info: &TI) -> MetaType<'r, SV>
+    fn meta<'r>(registry: &mut Registry<'r, SV>, type_info: &TI) -> MetaType<'r, SV>
     where
         SV: 'r,
     {
-        T::meta(registry, info)
+        T::meta(registry, type_info)
     }
 }
 
@@ -29,8 +29,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn type_name(info: &TI) -> &str {
-        T::type_name(info)
+    fn type_name(type_info: &TI) -> &str {
+        T::type_name(type_info)
     }
 }
 
@@ -40,8 +40,8 @@ where
     TI: ?Sized,
     BH: ?Sized,
 {
-    fn concrete_type_name<'i>(&self, info: &'i TI) -> &'i str {
-        (**self).concrete_type_name(info)
+    fn concrete_type_name<'i>(&self, type_info: &'i TI) -> &'i str {
+        (**self).concrete_type_name(type_info)
     }
 }
 

From 88046e3ce443803630ec27506e80b2bd613e9b99 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 9 Jun 2022 18:10:33 +0200
Subject: [PATCH 26/58] Re-implement `str`, vol.1 [skip ci]

---
 juniper/src/behavior.rs     | 16 +++++++
 juniper/src/executor/mod.rs | 44 +++++++-----------
 juniper/src/schema/meta.rs  | 58 +++++++++++++++++------
 juniper/src/types/str.rs    | 91 ++++++++++++++++++++++---------------
 4 files changed, 131 insertions(+), 78 deletions(-)

diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
index 3c6c84a41..d7a53f27e 100644
--- a/juniper/src/behavior.rs
+++ b/juniper/src/behavior.rs
@@ -1,5 +1,21 @@
 //! Default GraphQL behaviors.
 
+use std::{marker::PhantomData, sync::atomic::AtomicPtr};
+
 /// Default standard behavior of GraphQL types implementation.
 #[derive(Debug)]
 pub enum Standard {}
+
+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)
+    }
+}
+
+#[must_use]
+pub const fn coerce<T, From: ?Sized>(val: T) -> Coerce<T, From> {
+    Coerce::wrap(val)
+}
diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 3c6fd9072..295af1736 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -3,7 +3,7 @@
 use std::{
     borrow::Cow,
     cmp::Ordering,
-    collections::HashMap,
+    collections::{hash_map, HashMap},
     fmt::{Debug, Display},
     sync::{Arc, RwLock},
 };
@@ -1190,30 +1190,19 @@ impl<'r, S: 'r> Registry<'r, S> {
         }
     }
 
-    /// Returns a [`Type`] meta information for the specified [`graphql::Type`],
-    /// registered in this [`Registry`].
-    ///
-    /// If this [`Registry`] doesn't contain a [`Type`] meta information with
-    /// such [`TypeName`] before, it will construct the one and store it.
+    /// Returns an entry with a [`Type`] meta information for the specified
+    /// named [`graphql::Type`], registered in this [`Registry`].
     ///
     /// [`graphql::Type`]: resolve::Type
-    /// [`TypeName`]: resolve::TypeName
-    pub fn get_type_new<T, Info>(&mut self, info: &Info) -> Type<'r>
+    pub fn entry_type<T, TI>(
+        &mut self,
+        type_info: &TI,
+    ) -> hash_map::Entry<'_, Name, MetaType<'r, S>>
     where
-        T: resolve::Type<Info, S> + resolve::TypeName<Info> + ?Sized,
-        Info: ?Sized,
+        T: resolve::TypeName<TI> + ?Sized,
+        TI: ?Sized,
     {
-        let name = T::type_name(info);
-        let validated_name = name.parse::<Name>().unwrap();
-        if !self.types.contains_key(name) {
-            self.insert_placeholder(
-                validated_name.clone(),
-                Type::NonNullNamed(Cow::Owned(name.to_string())),
-            );
-            let meta = T::meta(self, info);
-            self.types.insert(validated_name, meta);
-        }
-        self.types[name].as_type()
+        self.types.entry(T::type_name(type_info).parse().unwrap())
     }
 
     /// Creates a [`Field`] with the provided `name`.
@@ -1306,19 +1295,20 @@ impl<'r, S: 'r> Registry<'r, S> {
         // TODO: Allow using references.
         ScalarMeta::new_new::<T, _>(T::type_name(info).to_owned())
     }
+    */
 
-    /// Builds a [`ScalarMeta`] information for the [`?Sized`] specified
+    /// Builds a [`ScalarMeta`] information for the specified [`?Sized`]
     /// [`graphql::Type`].
     ///
     /// [`graphql::Type`]: resolve::Type
-    pub fn build_scalar_type_unsized<T, Info>(&mut self, info: &Info) -> ScalarMeta<'r, S>
+    pub fn build_scalar_type_unsized<T, TI>(&mut self, type_info: &TI) -> ScalarMeta<'r, S>
     where
-        T: resolve::TypeName<Info> + resolve::ScalarToken<S> + resolve::InputValueAsRef<S> + ?Sized,
-        Info: ?Sized,
+        T: resolve::TypeName<TI> + resolve::InputValueAsRef<S> + resolve::ScalarToken<S> + ?Sized,
+        TI: ?Sized,
     {
         // TODO: Allow using references.
-        ScalarMeta::new_unsized::<T, _>(T::type_name(info).to_owned())
-    }*/
+        ScalarMeta::new_unsized::<T, _>(T::type_name(type_info).to_owned())
+    }
 
     /// Creates a [`ListMeta`] type.
     ///
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index f9f50af6d..17ce8c74e 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -54,6 +54,20 @@ pub struct ScalarMeta<'a, S> {
     pub(crate) parse_fn: ScalarTokenParseFn<S>,
 }
 
+// Manual implementation is required here to omit redundant `S: Clone` trait
+// bound, imposed by `#[derive(Clone)]`.
+impl<'a, S> Clone for ScalarMeta<'a, S> {
+    fn clone(&self) -> Self {
+        Self {
+            name: self.name.clone(),
+            description: self.description.clone(),
+            specified_by_url: self.specified_by_url.clone(),
+            try_parse_fn: self.try_parse_fn,
+            parse_fn: self.parse_fn,
+        }
+    }
+}
+
 /// Shortcut for an [`InputValue`] parsing function.
 pub type InputValueParseFn<S> = for<'b> fn(&'b InputValue<S>) -> Result<(), FieldError<S>>;
 
@@ -61,7 +75,7 @@ pub type InputValueParseFn<S> = for<'b> fn(&'b InputValue<S>) -> Result<(), Fiel
 pub type ScalarTokenParseFn<S> = for<'b> fn(ScalarToken<'b>) -> Result<S, ParseError<'b>>;
 
 /// List type metadata
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct ListMeta<'a> {
     #[doc(hidden)]
     pub of_type: Type<'a>,
@@ -71,14 +85,14 @@ pub struct ListMeta<'a> {
 }
 
 /// Nullable type metadata
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct NullableMeta<'a> {
     #[doc(hidden)]
     pub of_type: Type<'a>,
 }
 
 /// Object type metadata
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct ObjectMeta<'a, S> {
     #[doc(hidden)]
     pub name: Cow<'a, str>,
@@ -101,8 +115,21 @@ pub struct EnumMeta<'a, S> {
     pub(crate) try_parse_fn: InputValueParseFn<S>,
 }
 
+// Manual implementation is required here to omit redundant `S: Clone` trait
+// bound, imposed by `#[derive(Clone)]`.
+impl<'a, S> Clone for EnumMeta<'a, S> {
+    fn clone(&self) -> Self {
+        Self {
+            name: self.name.clone(),
+            description: self.description.clone(),
+            values: self.values.clone(),
+            try_parse_fn: self.try_parse_fn,
+        }
+    }
+}
+
 /// Interface type metadata
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct InterfaceMeta<'a, S> {
     #[doc(hidden)]
     pub name: Cow<'a, str>,
@@ -113,7 +140,7 @@ pub struct InterfaceMeta<'a, S> {
 }
 
 /// Union type metadata
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct UnionMeta<'a> {
     #[doc(hidden)]
     pub name: Cow<'a, str>,
@@ -124,6 +151,7 @@ pub struct UnionMeta<'a> {
 }
 
 /// Input object metadata
+#[derive(Clone)]
 pub struct InputObjectMeta<'a, S> {
     #[doc(hidden)]
     pub name: Cow<'a, str>,
@@ -138,14 +166,14 @@ pub struct InputObjectMeta<'a, S> {
 ///
 /// After a type's `meta` method has been called but before it has returned, a placeholder type
 /// is inserted into a registry to indicate existence.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct PlaceholderMeta<'a> {
     #[doc(hidden)]
     pub of_type: Type<'a>,
 }
 
 /// Generic type metadata
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub enum MetaType<'a, S = DefaultScalarValue> {
     #[doc(hidden)]
     Scalar(ScalarMeta<'a, S>),
@@ -168,7 +196,7 @@ pub enum MetaType<'a, S = DefaultScalarValue> {
 }
 
 /// Metadata for a field
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug)]
 pub struct Field<'a, S> {
     #[doc(hidden)]
     pub name: smartstring::alias::String,
@@ -191,7 +219,7 @@ impl<'a, S> Field<'a, S> {
 }
 
 /// Metadata for an argument to a field
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug)]
 pub struct Argument<'a, S> {
     #[doc(hidden)]
     pub name: String,
@@ -465,7 +493,7 @@ impl<'a, S> ScalarMeta<'a, S> {
             try_parse_fn: try_parse_fn_new::<S, T>,
             parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
         }
-    }
+    }*/
 
     /// Builds a new [`ScalarMeta`] information with the specified `name` for
     /// the [`?Sized`] `T`ype that may only be parsed as a reference.
@@ -481,10 +509,10 @@ impl<'a, S> ScalarMeta<'a, S> {
             name: name.into(),
             description: None,
             specified_by_url: None,
-            try_parse_fn: try_parse_unsized_fn::<S, T>,
+            try_parse_fn: try_parse_unsized_fn::<T, S>,
             parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
         }
-    }*/
+    }
 
     /// Sets the `description` of this [`ScalarMeta`] type.
     ///
@@ -847,13 +875,13 @@ where
         .map(drop)
         .map_err(T::Error::into_field_error)
 }
+*/
 
-fn try_parse_unsized_fn<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
+fn try_parse_unsized_fn<T, SV>(v: &InputValue<SV>) -> Result<(), FieldError<SV>>
 where
-    T: resolve::InputValueAsRef<S> + ?Sized,
+    T: resolve::InputValueAsRef<SV> + ?Sized,
 {
     T::try_from_input_value(v)
         .map(drop)
         .map_err(T::Error::into_field_error)
 }
-*/
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index a5ff4436c..6e0a39e4a 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -13,24 +13,28 @@ use crate::{
     reflect, resolve, BoxFuture, ExecutionResult, Executor, Registry, ScalarValue, Selection,
 };
 
-/*
-impl<Info: ?Sized, S: ScalarValue> resolve::Type<Info, S> for str {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+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>
     where
-        S: 'r,
+        SV: 'r,
     {
+        let meta = registry
+            .build_scalar_type_unsized::<Self, _>(type_info)
+            .into_meta();
         registry
-            .build_scalar_type_unsized::<Self, _>(info)
-            .into_meta()
+            .entry_type::<Self, _>(type_info)
+            .or_insert(meta)
+            .clone()
     }
 }
 
-impl<Info: ?Sized> resolve::TypeName<Info> for str {
-    fn type_name(_: &Info) -> &'static str {
-        <Self as reflect::BaseType<()>>::NAME
+impl<TI: ?Sized> resolve::TypeName<TI> for str {
+    fn type_name(_: &TI) -> &'static str {
+        <Self as reflect::BaseType>::NAME
     }
 }
 
+/*
 impl<Info, Ctx, S> resolve::Value<Info, Ctx, S> for str
 where
     Info: ?Sized,
@@ -76,49 +80,65 @@ where
     }
 }
 
-impl<S: ScalarValue> resolve::InputValueAsRef<S> for str {
+ */
+
+impl<SV: ScalarValue> resolve::InputValueAsRef<SV> for str {
     type Error = String;
 
-    fn try_from_input_value(v: &graphql::InputValue<S>) -> Result<&Self, Self::Error> {
+    fn try_from_input_value(v: &graphql::InputValue<SV>) -> Result<&Self, Self::Error> {
         v.as_string_value()
             .ok_or_else(|| format!("Expected `String`, found: {}", v))
     }
 }
 
-impl<'inp, S: ScalarValue> resolve::InputValueAsBox<'inp, S> for str {
-    type Error = String;
+impl<'i, SV> resolve::InputValueAs<'i, Box<str>, SV> for str
+where
+    SV: 'i,
+    Self: resolve::InputValueAsRef<SV>,
+{
+    type Error = <Self as resolve::InputValueAsRef<SV>>::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Box<Self>, Self::Error> {
-        <str as resolve::InputValueAsRef<S>>::try_from_input_value(v).map(Into::into)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Box<Self>, Self::Error> {
+        <Self as resolve::InputValueAsRef<SV>>::try_from_input_value(v).map(Into::into)
     }
 }
 
-impl<'inp, S: ScalarValue> resolve::InputValueAsArc<'inp, S> for str {
-    type Error = String;
+impl<'i, SV> resolve::InputValueAs<'i, Rc<str>, SV> for str
+where
+    SV: 'i,
+    Self: resolve::InputValueAsRef<SV>,
+{
+    type Error = <Self as resolve::InputValueAsRef<SV>>::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Arc<Self>, Self::Error> {
-        <str as resolve::InputValueAsRef<S>>::try_from_input_value(v).map(Into::into)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Rc<Self>, Self::Error> {
+        <Self as resolve::InputValueAsRef<SV>>::try_from_input_value(v).map(Into::into)
     }
 }
 
-impl<'inp, S: ScalarValue> resolve::InputValueAsRc<'inp, S> for str {
-    type Error = String;
+impl<'i, SV> resolve::InputValueAs<'i, Arc<str>, SV> for str
+where
+    SV: 'i,
+    Self: resolve::InputValueAsRef<SV>,
+{
+    type Error = <Self as resolve::InputValueAsRef<SV>>::Error;
 
-    fn try_from_input_value(v: &'inp graphql::InputValue<S>) -> Result<Rc<Self>, Self::Error> {
-        <str as resolve::InputValueAsRef<S>>::try_from_input_value(v).map(Into::into)
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Arc<Self>, Self::Error> {
+        <Self as resolve::InputValueAsRef<SV>>::try_from_input_value(v).map(Into::into)
     }
 }
 
-impl<S> resolve::ScalarToken<S> for str
+impl<SV> resolve::ScalarToken<SV> for str
+//TODO: where String: resolve::ScalarToken<SV>,
 where
-    String: resolve::ScalarToken<S>,
+    String: crate::ParseScalarValue<SV>,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
-        <String as resolve::ScalarToken<S>>::parse_scalar_token(token)
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+        // TODO: <String as resolve::ScalarToken<SV>>::parse_scalar_token(token)
+        <String as crate::ParseScalarValue<SV>>::from_str(token)
     }
 }
-
 /*
+
 impl<'i, Info, S: 'i> graphql::InputType<'i, Info, S> for str
 where
     Self: resolve::Type<Info, S> + resolve::ToInputValue<S> + resolve::InputValue<'i, S>,
@@ -126,7 +146,7 @@ where
 {
     fn assert_input_type() {}
 }
-*/
+
 
 impl<S> graphql::OutputType<S> for str {
     fn assert_output_type() {}
@@ -134,17 +154,16 @@ impl<S> graphql::OutputType<S> for str {
 
 impl<S> graphql::Scalar<S> for str {
     fn assert_scalar() {}
-}
+}*/
 
-impl<S> reflect::BaseType<S> for str {
-    const NAME: reflect::Type = <String as reflect::BaseType<S>>::NAME;
+impl reflect::BaseType for str {
+    const NAME: reflect::Type = "String"; // TODO: <String as reflect::BaseType<BH>>::NAME;
 }
 
-impl<S> reflect::BaseSubTypes<S> for str {
-    const NAMES: reflect::Types = &[<Self as reflect::BaseType<S>>::NAME];
+impl reflect::BaseSubTypes for str {
+    const NAMES: reflect::Types = &[<Self as reflect::BaseType>::NAME];
 }
 
-impl<S> reflect::WrappedType<S> for str {
+impl reflect::WrappedType for str {
     const VALUE: reflect::WrappedValue = reflect::wrap::SINGULAR;
 }
-*/

From 067b1e532a551b8395eabd67557bbecba3222420 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 13 Jun 2022 18:12:44 +0200
Subject: [PATCH 27/58] Re-implement `str`, vol.2 [skip ci]

---
 juniper/src/types/str.rs | 139 ++++++++++++++++++++++++++++++---------
 1 file changed, 107 insertions(+), 32 deletions(-)

diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 6e0a39e4a..0e3f862b5 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -34,54 +34,51 @@ impl<TI: ?Sized> resolve::TypeName<TI> for str {
     }
 }
 
-/*
-impl<Info, Ctx, S> resolve::Value<Info, Ctx, S> for str
+impl<TI, CX, SV> resolve::Value<TI, CX, SV> for str
 where
-    Info: ?Sized,
-    Ctx: ?Sized,
-    S: From<String>,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: From<String>,
 {
     fn resolve_value(
         &self,
-        _: Option<&[Selection<'_, S>]>,
-        _: &Info,
-        _: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
+        _: Option<&[Selection<'_, SV>]>,
+        _: &TI,
+        _: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
         // TODO: Remove redundant `.to_owned()` allocation by allowing
         //       `ScalarValue` creation from reference?
         Ok(graphql::Value::scalar(self.to_owned()))
     }
 }
 
-impl<Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for str
+impl<TI, CX, SV> resolve::ValueAsync<TI, CX, SV> for str
 where
-    Info: ?Sized,
-    Ctx: ?Sized,
-    S: From<String> + Send,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: From<String> + Send,
 {
     fn resolve_value_async<'r>(
         &'r self,
-        _: Option<&'r [Selection<'_, S>]>,
-        _: &'r Info,
-        _: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        _: Option<&'r [Selection<'_, SV>]>,
+        _: &'r TI,
+        _: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
         // TODO: Remove redundant `.to_owned()` allocation by allowing
         //       `ScalarValue` creation from reference?
         Box::pin(future::ok(graphql::Value::scalar(self.to_owned())))
     }
 }
 
-impl<S> resolve::ToInputValue<S> for str
+impl<SV> resolve::ToInputValue<SV> for str
 where
-    S: From<String>,
+    SV: From<String>,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         graphql::InputValue::scalar(self.to_owned())
     }
 }
 
- */
-
 impl<SV: ScalarValue> resolve::InputValueAsRef<SV> for str {
     type Error = String;
 
@@ -91,7 +88,7 @@ impl<SV: ScalarValue> resolve::InputValueAsRef<SV> for str {
     }
 }
 
-impl<'i, SV> resolve::InputValueAs<'i, Box<str>, SV> for str
+impl<'i, SV> resolve::InputValueAs<'i, Box<Self>, SV> for str
 where
     SV: 'i,
     Self: resolve::InputValueAsRef<SV>,
@@ -103,7 +100,7 @@ where
     }
 }
 
-impl<'i, SV> resolve::InputValueAs<'i, Rc<str>, SV> for str
+impl<'i, SV> resolve::InputValueAs<'i, Rc<Self>, SV> for str
 where
     SV: 'i,
     Self: resolve::InputValueAsRef<SV>,
@@ -115,7 +112,7 @@ where
     }
 }
 
-impl<'i, SV> resolve::InputValueAs<'i, Arc<str>, SV> for str
+impl<'i, SV> resolve::InputValueAs<'i, Arc<Self>, SV> for str
 where
     SV: 'i,
     Self: resolve::InputValueAsRef<SV>,
@@ -137,24 +134,102 @@ where
         <String as crate::ParseScalarValue<SV>>::from_str(token)
     }
 }
-/*
 
-impl<'i, Info, S: 'i> graphql::InputType<'i, Info, S> for str
+impl<'me, 'i, TI, SV> graphql::InputTypeAs<'i, &'me Self, TI, SV> for str
+where
+    Self: graphql::Type<TI, SV>
+        + resolve::ToInputValue<SV>
+        + resolve::InputValueAs<'i, &'me Self, SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_input_type() {}
+}
+
+impl<'i, TI, SV> graphql::InputTypeAs<'i, Box<Self>, TI, SV> for str
+where
+    Self: graphql::Type<TI, SV>
+        + resolve::ToInputValue<SV>
+        + resolve::InputValueAs<'i, Box<Self>, SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_input_type() {}
+}
+
+impl<'i, TI, SV> graphql::InputTypeAs<'i, Rc<Self>, TI, SV> for str
 where
-    Self: resolve::Type<Info, S> + resolve::ToInputValue<S> + resolve::InputValue<'i, S>,
-    Info: ?Sized,
+    Self:
+        graphql::Type<TI, SV> + resolve::ToInputValue<SV> + resolve::InputValueAs<'i, Rc<Self>, SV>,
+    TI: ?Sized,
+    SV: 'i,
 {
     fn assert_input_type() {}
 }
 
+impl<'i, TI, SV> graphql::InputTypeAs<'i, Arc<Self>, TI, SV> for str
+where
+    Self: graphql::Type<TI, SV>
+        + resolve::ToInputValue<SV>
+        + resolve::InputValueAs<'i, Arc<Self>, SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_input_type() {}
+}
 
-impl<S> graphql::OutputType<S> for str {
+impl<TI, CX, SV> graphql::OutputType<TI, CX, SV> for str
+where
+    Self: graphql::Type<TI, SV> + resolve::Value<TI, CX, SV> + resolve::ValueAsync<TI, CX, SV>,
+    TI: ?Sized,
+    CX: ?Sized,
+{
     fn assert_output_type() {}
 }
 
-impl<S> graphql::Scalar<S> for str {
+impl<'me, 'i, TI, CX, SV> graphql::ScalarAs<'i, &'me Self, TI, CX, SV> for str
+where
+    Self: graphql::InputTypeAs<'i, &'me Self, TI, SV>
+        + graphql::OutputType<TI, CX, SV>
+        + resolve::ScalarToken<SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
     fn assert_scalar() {}
-}*/
+}
+
+impl<'i, TI, CX, SV> graphql::ScalarAs<'i, Box<Self>, TI, CX, SV> for str
+where
+    Self: graphql::InputTypeAs<'i, Box<Self>, TI, SV>
+        + graphql::OutputType<TI, CX, SV>
+        + resolve::ScalarToken<SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_scalar() {}
+}
+
+impl<'i, TI, CX, SV> graphql::ScalarAs<'i, Rc<Self>, TI, CX, SV> for str
+where
+    Self: graphql::InputTypeAs<'i, Rc<Self>, TI, SV>
+        + graphql::OutputType<TI, CX, SV>
+        + resolve::ScalarToken<SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_scalar() {}
+}
+
+impl<'i, TI, CX, SV> graphql::ScalarAs<'i, Arc<Self>, TI, CX, SV> for str
+where
+    Self: graphql::InputTypeAs<'i, Arc<Self>, TI, SV>
+        + graphql::OutputType<TI, CX, SV>
+        + resolve::ScalarToken<SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_scalar() {}
+}
 
 impl reflect::BaseType for str {
     const NAME: reflect::Type = "String"; // TODO: <String as reflect::BaseType<BH>>::NAME;

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 28/58] 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 d7a53f27e..c68cae6cd 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 295af1736..7c0bd8d29 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 868ce5003..353095fd1 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 17ce8c74e..73d0620d4 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 ef7337991..db4c6cba7 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 ec0194612..845343d22 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 7728959c7..ee4a861aa 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 0a83cc628..cdc919416 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 950ec0425..f886e910c 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 9b9668fe3..867f4f481 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 f24b96a5d..c0c479c68 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 0e3f862b5..aeeac1edb 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())
     }
 }

From f2718cc01a9e0eed184e1bfa1c5e70a218d0edb6 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Fri, 17 Jun 2022 18:24:02 +0200
Subject: [PATCH 29/58] Impl macro for scalars, vol.1 [skip ci]

---
 juniper/src/behavior.rs                      |  60 ++++-
 juniper/src/executor/mod.rs                  |  34 ++-
 juniper/src/schema/meta.rs                   |  15 +-
 juniper/src/types/str.rs                     |   8 +-
 juniper_codegen/src/common/behavior.rs       |  57 +++++
 juniper_codegen/src/common/mod.rs            |   1 +
 juniper_codegen/src/graphql_scalar/attr.rs   |   2 +
 juniper_codegen/src/graphql_scalar/derive.rs |  13 +-
 juniper_codegen/src/graphql_scalar/mod.rs    | 217 ++++++++++++-------
 9 files changed, 303 insertions(+), 104 deletions(-)
 create mode 100644 juniper_codegen/src/common/behavior.rs

diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
index c68cae6cd..6ad3fee4b 100644
--- a/juniper/src/behavior.rs
+++ b/juniper/src/behavior.rs
@@ -2,24 +2,35 @@
 
 use std::{marker::PhantomData, sync::atomic::AtomicPtr};
 
-use crate::{meta::MetaType, resolve, Registry};
+use crate::{
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    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);
+#[repr(transparent)]
+pub struct Coerce<T: ?Sized, To: ?Sized = Standard>(PhantomData<AtomicPtr<Box<To>>>, T);
 
-impl<T, From: ?Sized> Coerce<T, From> {
+impl<T, To: ?Sized> Coerce<T, To> {
     #[must_use]
     pub const fn wrap(value: T) -> Self {
         Self(PhantomData, value)
     }
+
+    #[must_use]
+    pub fn into_inner(self) -> T {
+        self.1
+    }
 }
 
 #[must_use]
-pub const fn coerce<T, From: ?Sized>(value: T) -> Coerce<T, From> {
+pub const fn coerce<T, To: ?Sized>(value: T) -> Coerce<T, To> {
     Coerce::wrap(value)
 }
 
@@ -37,3 +48,44 @@ where
         T::meta(registry, type_info)
     }
 }
+
+impl<T, TI, B1, B2> resolve::TypeName<TI, B1> for Coerce<T, B2>
+where
+    T: resolve::TypeName<TI, B2> + ?Sized,
+    TI: ?Sized,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    fn type_name(type_info: &TI) -> &str {
+        T::type_name(type_info)
+    }
+}
+
+impl<'i, T, SV, B1, B2> resolve::InputValue<'i, SV, B1> for Coerce<T, B2>
+where
+    T: resolve::InputValue<'i, SV, B2>,
+    SV: 'i,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    type Error = T::Error;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        T::try_from_input_value(v).map(Self::wrap)
+    }
+
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        T::try_from_implicit_null().map(Self::wrap)
+    }
+}
+
+impl<T, SV, B1, B2> resolve::ScalarToken<SV, B1> for Coerce<T, B2>
+where
+    T: resolve::ScalarToken<SV, B2> + ?Sized,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 7c0bd8d29..6cf83769f 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -1277,19 +1277,37 @@ impl<'r, S: 'r> Registry<'r, S> {
         ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
     }
 
-    /*
-    /// Builds a [`ScalarMeta`] information for the specified [`graphql::Type`].
+    /// Builds a [`ScalarMeta`] information for the specified [`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
-    pub fn build_scalar_type_new<T, Info>(&mut self, info: &Info) -> ScalarMeta<'r, S>
+    /// [`TypeName`]: resolve::TypeName
+    pub fn register_scalar_with<'ti, T, TI, F>(
+        &mut self,
+        type_info: &'ti TI,
+        customize: F,
+    ) -> MetaType<'r, S>
     where
-        T: resolve::TypeName<Info> + resolve::ScalarToken<S> + resolve::InputValueOwned<S>,
-        Info: ?Sized,
+        T: resolve::TypeName<TI> + resolve::InputValueOwned<S> + resolve::ScalarToken<S>,
+        TI: ?Sized,
+        'ti: 'r,
+        F: FnOnce(&mut ScalarMeta<'r, S>),
+        S: Clone,
     {
-        // TODO: Allow using references.
-        ScalarMeta::new_new::<T, _>(T::type_name(info).to_owned())
+        self.entry_type::<T, _>(type_info)
+            .or_insert_with(move || {
+                let mut scalar = ScalarMeta::new_reworked::<T, _>(T::type_name(type_info));
+                customize(&mut scalar);
+                scalar.into_meta()
+            })
+            .clone()
     }
-    */
 
     /// Builds a [`ScalarMeta`] information for the specified non-[`Sized`]
     /// [`graphql::Type`], and stores it in this [`Registry`].
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index 73d0620d4..1113cffe6 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -499,12 +499,11 @@ impl<'a, S> ScalarMeta<'a, S> {
         }
     }
 
-    /*
     /// Builds a new [`ScalarMeta`] information with the specified `name`.
     // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
     //       `explicit_generic_args_with_impl_trait` hits stable:
     //       https://github.com/rust-lang/rust/issues/83701
-    pub fn new_new<T, N>(name: N) -> Self
+    pub fn new_reworked<T, N>(name: N) -> Self
     where
         T: resolve::InputValueOwned<S> + resolve::ScalarToken<S>,
         Cow<'a, str>: From<N>,
@@ -513,13 +512,13 @@ impl<'a, S> ScalarMeta<'a, S> {
             name: name.into(),
             description: None,
             specified_by_url: None,
-            try_parse_fn: try_parse_fn_new::<S, T>,
+            try_parse_fn: try_parse_fn_reworked::<T, S>,
             parse_fn: <T as resolve::ScalarToken<S>>::parse_scalar_token,
         }
-    }*/
+    }
 
     /// Builds a new [`ScalarMeta`] information with the specified `name` for
-    /// the [`?Sized`] `T`ype that may only be parsed as a reference.
+    /// the non-[`Sized`] `T`ype that may only be parsed as a reference.
     // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
     //       `explicit_generic_args_with_impl_trait` hits stable:
     //       https://github.com/rust-lang/rust/issues/83701
@@ -889,16 +888,14 @@ where
         .map_err(T::Error::into_field_error)
 }
 
-/*
-fn try_parse_fn_new<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
+fn try_parse_fn_reworked<T, SV>(v: &InputValue<SV>) -> Result<(), FieldError<SV>>
 where
-    T: resolve::InputValueOwned<S>,
+    T: resolve::InputValueOwned<SV>,
 {
     T::try_from_input_value(v)
         .map(drop)
         .map_err(T::Error::into_field_error)
 }
-*/
 
 fn try_parse_unsized_fn<T, SV>(v: &InputValue<SV>) -> Result<(), FieldError<SV>>
 where
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index aeeac1edb..a51299335 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -121,13 +121,11 @@ where
 }
 
 impl<SV> resolve::ScalarToken<SV> for str
-//TODO: where String: resolve::ScalarToken<SV>,
 where
-    String: crate::ParseScalarValue<SV>,
+    String: resolve::ScalarToken<SV>,
 {
     fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
-        // TODO: <String as resolve::ScalarToken<SV>>::parse_scalar_token(token)
-        <String as crate::ParseScalarValue<SV>>::from_str(token)
+        <String as resolve::ScalarToken<SV>>::parse_scalar_token(token)
     }
 }
 
@@ -228,7 +226,7 @@ where
 }
 
 impl reflect::BaseType for str {
-    const NAME: reflect::Type = "String"; // TODO: <String as reflect::BaseType<BH>>::NAME;
+    const NAME: reflect::Type = <String as reflect::BaseType>::NAME;
 }
 
 impl reflect::BaseSubTypes for str {
diff --git a/juniper_codegen/src/common/behavior.rs b/juniper_codegen/src/common/behavior.rs
new file mode 100644
index 000000000..d20d7c167
--- /dev/null
+++ b/juniper_codegen/src/common/behavior.rs
@@ -0,0 +1,57 @@
+//! Common functions, definitions and extensions for parsing and code generation
+//! related to [`Behaviour`] type parameter.
+//!
+//! [`Behaviour`]: juniper::behavior
+
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::{
+    parse::{Parse, ParseStream},
+    parse_quote,
+};
+
+/// [`Behaviour`] parametrization of the code generation.
+///
+/// [`Behaviour`]: juniper::behavior
+#[derive(Clone, Debug)]
+pub(crate) enum Type {
+    /// [`behavior::Standard`] should be used in the generated code.
+    ///
+    /// [`behavior::Standard`]: juniper::behavior::Standard
+    Standard,
+
+    /// Concrete custom Rust type should be used as [`Behaviour`] in the
+    /// generated code.
+    ///
+    /// [`Behaviour`]: juniper::behavior
+    Custom(syn::Type),
+}
+
+impl Default for Type {
+    fn default() -> Self {
+        Self::Standard
+    }
+}
+
+impl Parse for Type {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        input.parse::<syn::Type>().map(Self::Custom)
+    }
+}
+
+impl ToTokens for Type {
+    fn to_tokens(&self, into: &mut TokenStream) {
+        self.ty().to_tokens(into)
+    }
+}
+
+impl Type {
+    /// Returns a Rust type representing this [`Type`].
+    #[must_use]
+    pub(crate) fn ty(&self) -> syn::Type {
+        match self {
+            Self::Standard => parse_quote! { ::juniper::behavior::Standard },
+            Self::Custom(ty) => ty.clone(),
+        }
+    }
+}
diff --git a/juniper_codegen/src/common/mod.rs b/juniper_codegen/src/common/mod.rs
index fd16d954d..ae2e92575 100644
--- a/juniper_codegen/src/common/mod.rs
+++ b/juniper_codegen/src/common/mod.rs
@@ -4,3 +4,4 @@ pub(crate) mod field;
 pub(crate) mod gen;
 pub(crate) mod parse;
 pub(crate) mod scalar;
+pub(crate) mod behavior;
diff --git a/juniper_codegen/src/graphql_scalar/attr.rs b/juniper_codegen/src/graphql_scalar/attr.rs
index b9ff5b587..0c99f041c 100644
--- a/juniper_codegen/src/graphql_scalar/attr.rs
+++ b/juniper_codegen/src/graphql_scalar/attr.rs
@@ -64,6 +64,7 @@ fn expand_on_type_alias(
         description: attr.description.as_deref().cloned(),
         specified_by_url: attr.specified_by_url.as_deref().cloned(),
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
     };
 
     Ok(quote! {
@@ -96,6 +97,7 @@ fn expand_on_derive_input(
         description: attr.description.as_deref().cloned(),
         specified_by_url: attr.specified_by_url.as_deref().cloned(),
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
     };
 
     Ok(quote! {
diff --git a/juniper_codegen/src/graphql_scalar/derive.rs b/juniper_codegen/src/graphql_scalar/derive.rs
index e16bcd7d4..885bc0764 100644
--- a/juniper_codegen/src/graphql_scalar/derive.rs
+++ b/juniper_codegen/src/graphql_scalar/derive.rs
@@ -33,6 +33,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         description: attr.description.as_deref().cloned(),
         specified_by_url: attr.specified_by_url.as_deref().cloned(),
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
     }
     .to_token_stream())
 }
@@ -82,7 +83,11 @@ pub(super) fn parse_derived_methods(ast: &syn::DeriveInput, attr: &Attr) -> syn:
                     .first()
                     .filter(|_| fields.unnamed.len() == 1)
                     .cloned()
-                    .map(Field::Unnamed)
+                    .map(|f| Field {
+                        itself: f,
+                        is_named: false,
+                        behavior: None.unwrap_or_default(), // TODO: Parse attribute!
+                    })
                     .ok_or_else(|| {
                         ERR.custom_error(
                             ast.span(),
@@ -95,7 +100,11 @@ pub(super) fn parse_derived_methods(ast: &syn::DeriveInput, attr: &Attr) -> syn:
                     .first()
                     .filter(|_| fields.named.len() == 1)
                     .cloned()
-                    .map(Field::Named)
+                    .map(|f| Field {
+                        itself: f,
+                        is_named: true,
+                        behavior: None.unwrap_or_default(), // TODO: Parse attribute!
+                    })
                     .ok_or_else(|| {
                         ERR.custom_error(
                             ast.span(),
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 5a706851a..35b168658 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -16,6 +16,7 @@ use url::Url;
 
 use crate::{
     common::{
+        behavior,
         parse::{
             attr::{err, OptionExt as _},
             ParseBufferExt as _,
@@ -63,6 +64,17 @@ struct Attr {
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
     scalar: Option<SpanContainer<scalar::AttrValue>>,
 
+    /// Explicitly specified type of the custom [`Behavior`] to parametrize this
+    /// [GraphQL scalar][0] type 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-Scalars
+    behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified function to be used as
     /// [`ToInputValue::to_input_value`] implementation.
     ///
@@ -88,7 +100,7 @@ struct Attr {
     /// Explicit where clause added to [`syn::WhereClause`].
     where_clause: Option<SpanContainer<Vec<syn::WherePredicate>>>,
 
-    /// Indicator for single-field structs allowing to delegate implmemntations
+    /// Indicator for single-field structs allowing to delegate implementations
     /// of non-provided resolvers to that field.
     transparent: bool,
 }
@@ -138,6 +150,13 @@ impl Parse for Attr {
                         .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "to_output_with" => {
                     input.parse::<token::Eq>()?;
                     let scl = input.parse::<syn::ExprPath>()?;
@@ -238,6 +257,7 @@ impl Attr {
             description: try_merge_opt!(description: self, another),
             specified_by_url: try_merge_opt!(specified_by_url: self, another),
             scalar: try_merge_opt!(scalar: self, another),
+            behavior: try_merge_opt!(behavior: self, another),
             to_output: try_merge_opt!(to_output: self, another),
             from_input: try_merge_opt!(from_input: self, another),
             parse_token: try_merge_opt!(parse_token: self, another),
@@ -318,6 +338,13 @@ struct Definition {
     /// [`ScalarValue`]: juniper::ScalarValue
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
     scalar: scalar::Type,
+
+    /// [`Behavior`] parametrization to generate code with for this
+    /// [GraphQL scalar][0].
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    behavior: behavior::Type,
 }
 
 impl ToTokens for Definition {
@@ -331,17 +358,17 @@ impl ToTokens for Definition {
         self.impl_parse_scalar_value_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        //self.impl_resolve_type().to_tokens(into);
-        //self.impl_resolve_type_name().to_tokens(into);
+        self.impl_resolve_type().to_tokens(into);
+        self.impl_resolve_type_name().to_tokens(into);
         //self.impl_resolve_value().to_tokens(into);
         //self.impl_resolve_value_async().to_tokens(into);
         //self.impl_resolve_to_input_value().to_tokens(into);
-        //self.impl_resolve_input_value().to_tokens(into);
-        //self.impl_resolve_scalar_token().to_tokens(into);
+        self.impl_resolve_input_value().to_tokens(into);
+        self.impl_resolve_scalar_token().to_tokens(into);
         //self.impl_graphql_output_type().to_tokens(into);
         //self.impl_graphql_output_type().to_tokens(into);
         //self.impl_graphql_scalar().to_tokens(into);
-        //self.impl_reflect().to_tokens(into);
+        self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -472,17 +499,18 @@ impl Definition {
     /// [`resolve::TypeName`]: juniper::resolve::TypeName
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_type_name(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (inf, generics) = self.mix_type_info(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::TypeName<#inf> for #ty
+            impl#impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
                 #where_clause
             {
                 fn type_name(_: &#inf) -> &'static str {
-                    <Self as ::juniper::reflect::BaseType<()>>::NAME
+                    <Self as ::juniper::reflect::BaseType<#bh>>::NAME
                 }
             }
         }
@@ -494,13 +522,16 @@ impl Definition {
     /// [`resolve::Type`]: juniper::resolve::Type
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_type(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (inf, generics) = self.mix_type_info(generics);
         let (sv, mut generics) = self.mix_scalar_value(generics);
-        generics.make_where_clause().predicates.push(parse_quote! {
-            Self: ::juniper::resolve::TypeName<#inf>
-                  + ::juniper::resolve::ScalarToken<#sv>
-                  + ::juniper::resolve::InputValueOwned<#sv>
+        let predicates = &mut generics.make_where_clause().predicates;
+        predicates.push(parse_quote! { #sv: Clone });
+        predicates.push(parse_quote! {
+            Self: ::juniper::resolve::TypeName<#inf, #bh>
+                  + ::juniper::resolve::ScalarToken<#sv, #bh>
+                  + ::juniper::resolve::InputValueOwned<#sv, #bh>
         });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
@@ -516,20 +547,22 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Type<#inf, #sv> for #ty
+            impl#impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
                 #where_clause
             {
-                fn meta<'__r>(
+                fn meta<'__r, '__ti: '__r>(
                     registry: &mut ::juniper::Registry<'__r, #sv>,
-                    info: &#inf,
+                    type_info: &'__ti #inf,
                 ) -> ::juniper::meta::MetaType<'__r, #sv>
                 where
                     #sv: '__r,
                 {
-                    registry.build_scalar_type_new::<Self, _>(info)
-                        #description
-                        #specified_by_url
-                        .into_meta()
+                    registry.register_scalar_with::<
+                        ::juniper::behavior::Coerce<Self, #bh>, _, _,
+                    >(type_info, |meta| {
+                        meta#description
+                            #specified_by_url;
+                    })
                 }
             }
         }
@@ -762,6 +795,7 @@ impl Definition {
     /// [`resolve::InputValue`]: juniper::resolve::InputValue
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_input_value(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (sv, mut generics) = self.mix_scalar_value(generics);
         let lt: syn::GenericParam = parse_quote! { '__inp };
@@ -769,14 +803,14 @@ impl Definition {
         generics
             .make_where_clause()
             .predicates
-            .push(self.methods.bound_try_from_input_value(sv, &lt));
+            .push(self.methods.bound_try_from_input_value(&lt, sv, bh));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let conversion = self.methods.expand_try_from_input_value(sv);
+        let conversion = self.methods.expand_try_from_input_value(sv, bh);
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::InputValue<#lt, #sv> for #ty
+            impl#impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh> for #ty
                 #where_clause
             {
                 type Error = ::juniper::FieldError<#sv>;
@@ -825,19 +859,20 @@ impl Definition {
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_scalar_token(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (sv, mut generics) = self.mix_scalar_value(generics);
         generics
             .make_where_clause()
             .predicates
-            .extend(self.methods.bound_parse_scalar_token(sv));
+            .extend(self.methods.bound_parse_scalar_token(sv, bh));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let body = self.methods.expand_parse_scalar_token(sv);
+        let body = self.methods.expand_parse_scalar_token(sv, bh);
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ScalarToken<#sv> for #ty
+            impl#impl_gens ::juniper::resolve::ScalarToken<#sv, #bh> for #ty
                 #where_clause
             {
                 fn parse_scalar_token(
@@ -900,30 +935,30 @@ impl Definition {
     /// [`reflect::WrappedType`]: juniper::reflection::WrappedType
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_reflect(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (sv, generics) = self.mix_scalar_value(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         let name = &self.name;
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseType<#sv> for #ty
+            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<#sv> for #ty
+            impl#impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
-                    &[<Self as ::juniper::reflect::BaseType<#sv>>::NAME];
+                    &[<Self as ::juniper::reflect::BaseType<#bh>>::NAME];
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::WrappedType<#sv> for #ty
+            impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
                 #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
@@ -1038,7 +1073,7 @@ impl Definition {
     /// [`syn::Generics`] and returns its [`syn::Ident`].
     #[must_use]
     fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __Info };
+        let ty = parse_quote! { __TypeInfo };
 
         generics.params.push(parse_quote! { #ty: ?Sized });
 
@@ -1049,7 +1084,7 @@ impl Definition {
     /// [`syn::Generics`] and returns its [`syn::Ident`].
     #[must_use]
     fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __Ctx };
+        let ty = parse_quote! { __Context };
 
         generics.params.push(parse_quote! { #ty: ?Sized });
 
@@ -1089,29 +1124,30 @@ impl VisitMut for ModifyLifetimes {
     }
 }
 
-/// Methods representing [GraphQL scalar][1].
+/// User-provided methods for implementing a [GraphQL scalar][0].
 ///
-/// [1]: https://spec.graphql.org/October2021#sec-Scalars
+/// [0]: https://spec.graphql.org/October2021#sec-Scalars
 enum Methods {
-    /// [GraphQL scalar][1] represented with only custom resolvers.
+    /// [GraphQL scalar][0] represented with custom resolving methods only.
     ///
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     Custom {
-        /// Function provided with `#[graphql(to_output_with = ...)]`.
+        /// Function provided with `#[graphql(to_output_with = ...)]` attribute.
         to_output: syn::ExprPath,
 
-        /// Function provided with `#[graphql(from_input_with = ...)]`.
+        /// Function provided with `#[graphql(from_input_with = ...)]`
+        /// attribute.
         from_input: syn::ExprPath,
 
         /// [`ParseToken`] provided with `#[graphql(parse_token_with = ...)]`
-        /// or `#[graphql(parse_token(...))]`.
+        /// or `#[graphql(parse_token(...))]` attribute.
         parse_token: ParseToken,
     },
 
-    /// [GraphQL scalar][1] maybe partially represented with custom resolver.
-    /// Other methods are used from [`Field`].
+    /// [GraphQL scalar][0] maybe partially represented with custom resolving
+    /// methods. Other methods are re-used from its inner [`Field`].
     ///
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     Delegated {
         /// Function provided with `#[graphql(to_output_with = ...)]`.
         to_output: Option<syn::ExprPath>,
@@ -1323,7 +1359,7 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::InputValue::try_from_input_value
-    fn expand_try_from_input_value(&self, sv: &scalar::Type) -> TokenStream {
+    fn expand_try_from_input_value(&self, sv: &scalar::Type, bh: &behavior::Type) -> TokenStream {
         match self {
             Self::Custom { from_input, .. }
             | Self::Delegated {
@@ -1335,11 +1371,14 @@ impl Methods {
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
                 let self_constructor = field.closure_constructor();
 
                 quote! {
-                    <#field_ty as ::juniper::resolve::InputValue<'_, #sv>>
+                    <::juniper::behavior::Coerce<#field_ty, #bh> as
+                     ::juniper::resolve::InputValue<'_, #sv, #field_bh>>
                         ::try_from_input_value(input)
+                            .into_inner()
                             .map(#self_constructor)
                 }
             }
@@ -1354,8 +1393,9 @@ impl Methods {
     /// [0]: juniper::resolve::InputValue::try_from_input_value
     fn bound_try_from_input_value(
         &self,
-        sv: &scalar::Type,
         lt: &syn::GenericParam,
+        sv: &scalar::Type,
+        bh: &behavior::Type,
     ) -> syn::WherePredicate {
         match self {
             Self::Custom { .. }
@@ -1370,9 +1410,11 @@ impl Methods {
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
 
                 parse_quote! {
-                    #field_ty: ::juniper::resolve::InputValue<#lt, #sv>
+                    ::juniper::behavior::Coerce<#field_ty, #bh>:
+                        ::juniper::resolve::InputValue<#lt, #sv, #field_bh>
                 }
             }
         }
@@ -1404,19 +1446,21 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, sv: &scalar::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &scalar::Type, bh: &behavior::Type) -> TokenStream {
         match self {
             Self::Custom { parse_token, .. }
             | Self::Delegated {
                 parse_token: Some(parse_token),
                 ..
-            } => parse_token.expand_parse_scalar_token(sv),
+            } => parse_token.expand_parse_scalar_token(sv, bh),
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
 
                 quote! {
-                    <#field_ty as ::juniper::resolve::ScalarToken<#sv>>
+                    <::juniper::behavior::Coerce<#field_ty, #bh> as
+                     ::juniper::resolve::ScalarToken<#sv, #field_bh>>
                         ::parse_scalar_token(token)
                 }
             }
@@ -1429,19 +1473,25 @@ impl Methods {
     ///
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn bound_parse_scalar_token(&self, sv: &scalar::Type) -> Vec<syn::WherePredicate> {
+    fn bound_parse_scalar_token(
+        &self,
+        sv: &scalar::Type,
+        bh: &behavior::Type,
+    ) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom { parse_token, .. }
             | Self::Delegated {
                 parse_token: Some(parse_token),
                 ..
-            } => parse_token.bound_parse_scalar_token(sv),
+            } => parse_token.bound_parse_scalar_token(sv, bh),
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
 
                 vec![parse_quote! {
-                    #field_ty: ::juniper::resolve::ScalarToken<#sv>
+                    ::juniper::behavior::Coerce<#field_ty, #bh>:
+                        ::juniper::resolve::ScalarToken<#sv, #field_bh>
                 }]
             }
         }
@@ -1494,7 +1544,7 @@ impl ParseToken {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, sv: &scalar::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &scalar::Type, bh: &behavior::Type) -> TokenStream {
         match self {
             Self::Custom(parse_token) => {
                 quote! { #parse_token(token) }
@@ -1506,14 +1556,16 @@ impl ParseToken {
                     acc.map_or_else(
                         || {
                             Some(quote! {
-                                <#ty as ::juniper::resolve::ScalarToken<#sv>>
+                                <::juniper::behavior::Coerce<#ty, #bh> as
+                                 ::juniper::resolve::ScalarToken<#sv>>
                                     ::parse_scalar_token(token)
                             })
                         },
                         |prev| {
                             Some(quote! {
                                 #prev.or_else(|_| {
-                                    <#ty as ::juniper::resolve::ScalarToken<#sv>>
+                                    <::juniper::behavior::Coerce<#ty, #bh> as
+                                     ::juniper::resolve::ScalarToken<#sv>>
                                         ::parse_scalar_token(token)
                                 })
                             })
@@ -1530,7 +1582,11 @@ impl ParseToken {
     ///
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn bound_parse_scalar_token(&self, sv: &scalar::Type) -> Vec<syn::WherePredicate> {
+    fn bound_parse_scalar_token(
+        &self,
+        sv: &scalar::Type,
+        bh: &behavior::Type,
+    ) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom(_) => {
                 vec![parse_quote! {
@@ -1542,7 +1598,8 @@ impl ParseToken {
                 .iter()
                 .map(|ty| {
                     parse_quote! {
-                        #ty: ::juniper::resolve::ScalarToken<#sv>
+                        ::juniper::behavior::Coerce<#ty, #bh>:
+                            ::juniper::resolve::ScalarToken<#sv>
                     }
                 })
                 .collect(),
@@ -1550,20 +1607,29 @@ impl ParseToken {
     }
 }
 
-/// Struct field to resolve not provided methods.
-enum Field {
-    /// Named [`Field`].
-    Named(syn::Field),
+/// Inner field of a type implementing [GraphQL scalar][0], that the
+/// implementation delegates calls to.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Scalars
+struct Field {
+    /// This [`Field`] itself.
+    itself: syn::Field,
+
+    /// Indicator whether this [`Field`] is named.
+    is_named: bool,
 
-    /// Unnamed [`Field`].
-    Unnamed(syn::Field),
+    /// [`Behavior`] parametrization of this [`Field`].
+    ///
+    /// [`Behavior`]: juniper::behavior
+    behavior: behavior::Type,
 }
 
 impl ToTokens for Field {
     fn to_tokens(&self, tokens: &mut TokenStream) {
-        match self {
-            Self::Named(f) => f.ident.to_tokens(tokens),
-            Self::Unnamed(_) => tokens.append(Literal::u8_unsuffixed(0)),
+        if self.is_named {
+            self.itself.ident.to_tokens(tokens)
+        } else {
+            tokens.append(Literal::u8_unsuffixed(0))
         }
     }
 }
@@ -1571,21 +1637,20 @@ impl ToTokens for Field {
 impl Field {
     /// [`syn::Type`] of this [`Field`].
     fn ty(&self) -> &syn::Type {
-        match self {
-            Self::Named(f) | Self::Unnamed(f) => &f.ty,
-        }
+        &self.itself.ty
     }
 
-    /// Generates closure to construct a [GraphQL scalar][0] struct from a
-    /// [`Field`] value.
+    /// Generates closure to construct a [GraphQL scalar][0] struct from an
+    /// inner [`Field`] value.
     ///
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn closure_constructor(&self) -> TokenStream {
-        match self {
-            Field::Named(syn::Field { ident, .. }) => {
-                quote! { |v| Self { #ident: v } }
-            }
-            Field::Unnamed(_) => quote! { Self },
+        if self.is_named {
+            let ident = &self.itself.ident;
+
+            quote! { |v| Self { #ident: v } }
+        } else {
+            quote! { Self }
         }
     }
 }

From a05a0091f6a2ac970de408c8bbdc56c60f5e7438 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Fri, 17 Jun 2022 21:30:30 +0200
Subject: [PATCH 30/58] Impl macro for scalars, vol.2 [skip ci]

---
 juniper/src/executor/mod.rs               | 17 ++++++-----------
 juniper_codegen/src/graphql_scalar/mod.rs |  9 +++++----
 2 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 6cf83769f..2026f97b6 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -4,6 +4,7 @@ use std::{
     borrow::Cow,
     cmp::Ordering,
     collections::{hash_map, HashMap},
+    convert,
     fmt::{Debug, Display},
     sync::{Arc, RwLock},
 };
@@ -1297,14 +1298,12 @@ impl<'r, S: 'r> Registry<'r, S> {
         T: resolve::TypeName<TI> + resolve::InputValueOwned<S> + resolve::ScalarToken<S>,
         TI: ?Sized,
         'ti: 'r,
-        F: FnOnce(&mut ScalarMeta<'r, S>),
+        F: FnOnce(ScalarMeta<'r, S>) -> ScalarMeta<'r, S>,
         S: Clone,
     {
         self.entry_type::<T, _>(type_info)
             .or_insert_with(move || {
-                let mut scalar = ScalarMeta::new_reworked::<T, _>(T::type_name(type_info));
-                customize(&mut scalar);
-                scalar.into_meta()
+                customize(ScalarMeta::new_reworked::<T, _>(T::type_name(type_info))).into_meta()
             })
             .clone()
     }
@@ -1326,9 +1325,7 @@ impl<'r, S: 'r> Registry<'r, S> {
         'ti: 'r,
         S: Clone,
     {
-        // TODO: Use `drop` instead of `|_| {}` once Rust's inference becomes
-        //       better for HRTB closures.
-        self.register_scalar_unsized_with::<T, TI, _>(type_info, |_| {})
+        self.register_scalar_unsized_with::<T, TI, _>(type_info, convert::identity)
     }
 
     /// Builds a [`ScalarMeta`] information for the specified non-[`Sized`]
@@ -1351,14 +1348,12 @@ impl<'r, S: 'r> Registry<'r, S> {
         T: resolve::TypeName<TI> + resolve::InputValueAsRef<S> + resolve::ScalarToken<S> + ?Sized,
         TI: ?Sized,
         'ti: 'r,
-        F: FnOnce(&mut ScalarMeta<'r, S>),
+        F: FnOnce(ScalarMeta<'r, S>) -> 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()
+                customize(ScalarMeta::new_unsized::<T, _>(T::type_name(type_info))).into_meta()
             })
             .clone()
     }
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 35b168658..e7a9e1a1f 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -529,9 +529,10 @@ impl Definition {
         let predicates = &mut generics.make_where_clause().predicates;
         predicates.push(parse_quote! { #sv: Clone });
         predicates.push(parse_quote! {
-            Self: ::juniper::resolve::TypeName<#inf, #bh>
-                  + ::juniper::resolve::ScalarToken<#sv, #bh>
-                  + ::juniper::resolve::InputValueOwned<#sv, #bh>
+            ::juniper::behavior::Coerce<Self, #bh>:
+                ::juniper::resolve::TypeName<#inf, #bh>
+                + ::juniper::resolve::ScalarToken<#sv, #bh>
+                + ::juniper::resolve::InputValueOwned<#sv, #bh>
         });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
@@ -561,7 +562,7 @@ impl Definition {
                         ::juniper::behavior::Coerce<Self, #bh>, _, _,
                     >(type_info, |meta| {
                         meta#description
-                            #specified_by_url;
+                            #specified_by_url
                     })
                 }
             }

From 679c1c1162842b870ee96b53eb82fa4aea7c24a8 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Fri, 17 Jun 2022 23:53:18 +0200
Subject: [PATCH 31/58] Impl macro for scalars, vol.3 [skip ci]

---
 juniper/src/ast.rs                           |  38 +++++-
 juniper_codegen/src/graphql_scalar/attr.rs   |   2 +
 juniper_codegen/src/graphql_scalar/derive.rs |   1 +
 juniper_codegen/src/graphql_scalar/mod.rs    | 129 +++++++++++++------
 4 files changed, 130 insertions(+), 40 deletions(-)

diff --git a/juniper/src/ast.rs b/juniper/src/ast.rs
index b535f9215..c5f9897f8 100644
--- a/juniper/src/ast.rs
+++ b/juniper/src/ast.rs
@@ -1,4 +1,4 @@
-use std::{borrow::Cow, fmt, hash::Hash, slice, vec};
+use std::{any::TypeId, borrow::Cow, convert::Into, fmt, hash::Hash, mem, slice, vec};
 
 use indexmap::IndexMap;
 
@@ -461,6 +461,42 @@ impl<S> InputValue<S> {
             _ => false,
         }
     }
+
+    /// Maps the [`ScalarValue`] type of this [`InputValue`] into the specified
+    /// one.
+    pub fn map_scalar_value<To>(self) -> InputValue<To>
+    where
+        To: From<S> + 'static,
+        S: 'static,
+    {
+        if TypeId::of::<To>() == TypeId::of::<S>() {
+            // SAFETY: This is safe, because we're transmuting the value into
+            //         itself, so no invariants may change and we're just
+            //         satisfying the type checker.
+            //         As `mem::transmute_copy` creates a copy of data, we need
+            //         `mem::ManuallyDrop` here to omit double-free when
+            //         `S: Drop`.
+            let val = mem::ManuallyDrop::new(self);
+            unsafe { mem::transmute_copy(&*val) }
+        } else {
+            match self {
+                Self::Null => InputValue::Null,
+                Self::Scalar(s) => InputValue::Scalar(s.into()),
+                Self::Enum(v) => InputValue::Enum(v),
+                Self::Variable(n) => InputValue::Variable(n),
+                Self::List(l) => InputValue::List(
+                    l.into_iter()
+                        .map(|i| i.map(InputValue::map_scalar_value))
+                        .collect(),
+                ),
+                Self::Object(o) => InputValue::Object(
+                    o.into_iter()
+                        .map(|(k, v)| (k, v.map(InputValue::map_scalar_value)))
+                        .collect(),
+                ),
+            }
+        }
+    }
 }
 
 impl<S: ScalarValue> fmt::Display for InputValue<S> {
diff --git a/juniper_codegen/src/graphql_scalar/attr.rs b/juniper_codegen/src/graphql_scalar/attr.rs
index 0c99f041c..e9754e970 100644
--- a/juniper_codegen/src/graphql_scalar/attr.rs
+++ b/juniper_codegen/src/graphql_scalar/attr.rs
@@ -64,6 +64,7 @@ fn expand_on_type_alias(
         description: attr.description.as_deref().cloned(),
         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(),
     };
 
@@ -97,6 +98,7 @@ fn expand_on_derive_input(
         description: attr.description.as_deref().cloned(),
         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(),
     };
 
diff --git a/juniper_codegen/src/graphql_scalar/derive.rs b/juniper_codegen/src/graphql_scalar/derive.rs
index 885bc0764..835ea37b2 100644
--- a/juniper_codegen/src/graphql_scalar/derive.rs
+++ b/juniper_codegen/src/graphql_scalar/derive.rs
@@ -33,6 +33,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         description: attr.description.as_deref().cloned(),
         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(),
     }
     .to_token_stream())
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index e7a9e1a1f..15c44703d 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -339,6 +339,13 @@ struct Definition {
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
     scalar: scalar::Type,
 
+    /// [`ScalarValue`] parametrization to generate code with for this
+    /// [GraphQL scalar][0].
+    ///
+    /// [`ScalarValue`]: juniper::ScalarValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    scalar_value: ScalarValue,
+
     /// [`Behavior`] parametrization to generate code with for this
     /// [GraphQL scalar][0].
     ///
@@ -804,7 +811,7 @@ impl Definition {
         generics
             .make_where_clause()
             .predicates
-            .push(self.methods.bound_try_from_input_value(&lt, sv, bh));
+            .extend(self.methods.bound_try_from_input_value(&lt, sv, bh));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         let conversion = self.methods.expand_try_from_input_value(sv, bh);
@@ -866,10 +873,10 @@ impl Definition {
         generics
             .make_where_clause()
             .predicates
-            .extend(self.methods.bound_parse_scalar_token(sv, bh));
+            .extend(self.methods.bound_parse_scalar_token(&sv, bh));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let body = self.methods.expand_parse_scalar_token(sv, bh);
+        let body = self.methods.expand_parse_scalar_token(&sv, bh);
 
         quote! {
             #[automatically_derived]
@@ -1075,9 +1082,7 @@ impl Definition {
     #[must_use]
     fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
         let ty = parse_quote! { __TypeInfo };
-
         generics.params.push(parse_quote! { #ty: ?Sized });
-
         (ty, generics)
     }
 
@@ -1086,32 +1091,23 @@ impl Definition {
     #[must_use]
     fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
         let ty = parse_quote! { __Context };
-
         generics.params.push(parse_quote! { #ty: ?Sized });
-
         (ty, generics)
     }
 
     /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`scalar::Type`].
+    /// [`syn::Generics`] and returns it.
     ///
     /// [`ScalarValue`] trait bound is not made here, because some trait
-    /// implementations may not require it depending on the generated code or
+    /// implementations may not require it, depending on the generated code or
     /// even at all.
     ///
     /// [`ScalarValue`]: juniper::ScalarValue
     #[must_use]
-    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (&scalar::Type, syn::Generics) {
-        let scalar = &self.scalar;
-
-        if scalar.is_implicit_generic() {
-            generics.params.push(parse_quote! { #scalar });
-        }
-        if let Some(bound) = scalar.bounds() {
-            generics.make_where_clause().predicates.push(bound);
-        }
-
-        (scalar, generics)
+    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (&ScalarValue, syn::Generics) {
+        let sv = &self.scalar_value;
+        generics.params.push(parse_quote! { #sv });
+        (sv, generics)
     }
 }
 
@@ -1198,7 +1194,7 @@ impl Methods {
         &self,
         inf: &syn::Ident,
         cx: &syn::Ident,
-        sv: &scalar::Type,
+        sv: &ScalarValue,
     ) -> TokenStream {
         match self {
             Self::Custom { to_output, .. }
@@ -1234,7 +1230,7 @@ impl Methods {
         &self,
         inf: &syn::Ident,
         cx: &syn::Ident,
-        sv: &scalar::Type,
+        sv: &ScalarValue,
     ) -> syn::WherePredicate {
         match self {
             Self::Custom { .. }
@@ -1282,7 +1278,7 @@ impl Methods {
     /// Expands body of [`resolve::ToInputValue::to_input_value()`][0] method.
     ///
     /// [0]: juniper::resolve::ToInputValue::to_input_value
-    fn expand_to_input_value(&self, sv: &scalar::Type) -> TokenStream {
+    fn expand_to_input_value(&self, sv: &ScalarValue) -> TokenStream {
         match self {
             Self::Custom { to_output, .. }
             | Self::Delegated {
@@ -1312,7 +1308,7 @@ impl Methods {
     ///
     /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
     /// [0]: juniper::resolve::ToInputValue::to_input_value
-    fn bound_to_input_value(&self, sv: &scalar::Type) -> syn::WherePredicate {
+    fn bound_to_input_value(&self, sv: &ScalarValue) -> syn::WherePredicate {
         match self {
             Self::Custom { .. }
             | Self::Delegated {
@@ -1360,14 +1356,21 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::InputValue::try_from_input_value
-    fn expand_try_from_input_value(&self, sv: &scalar::Type, bh: &behavior::Type) -> TokenStream {
+    fn expand_try_from_input_value(&self, sv: &ScalarValue, bh: &behavior::Type) -> TokenStream {
         match self {
             Self::Custom { from_input, .. }
             | Self::Delegated {
                 from_input: Some(from_input),
                 ..
             } => {
-                quote! { #from_input(input) }
+                let map_sv = sv.custom.as_ref().map(|custom_ty| {
+                    quote! {
+                        .map_scalar_value()
+                    }
+                });
+                quote! {
+                    #from_input(input#map_sv)
+                }
             }
 
             Self::Delegated { field, .. } => {
@@ -1395,17 +1398,23 @@ impl Methods {
     fn bound_try_from_input_value(
         &self,
         lt: &syn::GenericParam,
-        sv: &scalar::Type,
+        sv: &ScalarValue,
         bh: &behavior::Type,
-    ) -> syn::WherePredicate {
+    ) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom { .. }
             | Self::Delegated {
                 from_input: Some(_),
                 ..
             } => {
-                parse_quote! {
-                    #sv: ::juniper::ScalarValue
+                if let Some(custom_sv) = &sv.custom {
+                    vec![
+                        parse_quote! { #custom_sv: ::std::convert::From<#sv> },
+                        parse_quote! { #custom_sv: 'static },
+                        parse_quote! { #sv: 'static },
+                    ]
+                } else {
+                    vec![parse_quote! { #sv: ::juniper::ScalarValue }]
                 }
             }
 
@@ -1413,10 +1422,10 @@ impl Methods {
                 let field_ty = field.ty();
                 let field_bh = &field.behavior;
 
-                parse_quote! {
+                vec![parse_quote! {
                     ::juniper::behavior::Coerce<#field_ty, #bh>:
                         ::juniper::resolve::InputValue<#lt, #sv, #field_bh>
-                }
+                }]
             }
         }
     }
@@ -1447,7 +1456,7 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, sv: &scalar::Type, bh: &behavior::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &ScalarValue, bh: &behavior::Type) -> TokenStream {
         match self {
             Self::Custom { parse_token, .. }
             | Self::Delegated {
@@ -1476,7 +1485,7 @@ impl Methods {
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
     fn bound_parse_scalar_token(
         &self,
-        sv: &scalar::Type,
+        sv: &ScalarValue,
         bh: &behavior::Type,
     ) -> Vec<syn::WherePredicate> {
         match self {
@@ -1545,10 +1554,17 @@ impl ParseToken {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, sv: &scalar::Type, bh: &behavior::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &ScalarValue, bh: &behavior::Type) -> TokenStream {
         match self {
             Self::Custom(parse_token) => {
-                quote! { #parse_token(token) }
+                let into = sv.custom.as_ref().map(|custom_ty| {
+                    quote! {
+                        .map(<#sv as ::std::convert::From<#custom_ty>>::from)
+                    }
+                });
+                quote! {
+                    #parse_token(token)#into
+                }
             }
 
             Self::Delegated(delegated) => delegated
@@ -1585,13 +1601,19 @@ impl ParseToken {
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
     fn bound_parse_scalar_token(
         &self,
-        sv: &scalar::Type,
+        sv: &ScalarValue,
         bh: &behavior::Type,
     ) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom(_) => {
-                vec![parse_quote! {
-                    #sv: ::juniper::ScalarValue
+                vec![if let Some(custom_sv) = &sv.custom {
+                    parse_quote! {
+                        #sv: ::std::convert::From<#custom_sv>
+                    }
+                } else {
+                    parse_quote! {
+                        #sv: ::juniper::ScalarValue
+                    }
                 }]
             }
 
@@ -1655,3 +1677,32 @@ impl Field {
         }
     }
 }
+
+/// [`ScalarValue`] parametrization of a [GraphQL scalar][0] implementation.
+///
+/// [`ScalarValue`]: juniper::ScalarValue
+/// [0]: https://spec.graphql.org/October2021#sec-Scalars
+struct ScalarValue {
+    /// Concrete custom Rust type used in user-provided [`Methods`] as
+    /// [`ScalarValue`].
+    ///
+    /// [`ScalarValue`]: juniper::ScalarValue
+    custom: Option<syn::Type>,
+}
+
+impl ToTokens for ScalarValue {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        (quote! { __ScalarValue }).to_tokens(tokens)
+    }
+}
+
+impl<'a> From<Option<&'a scalar::AttrValue>> for ScalarValue {
+    fn from(attr: Option<&'a scalar::AttrValue>) -> Self {
+        Self {
+            custom: match attr {
+                Some(scalar::AttrValue::Concrete(ty)) => Some(ty.clone()),
+                Some(scalar::AttrValue::Generic(_)) | None => None,
+            },
+        }
+    }
+}

From 1aafd3da5de5c6ea371b662d20b1f8363ef63524 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Sun, 19 Jun 2022 22:18:50 +0200
Subject: [PATCH 32/58] Impl macro for scalars, vol.4 [skip ci]

---
 juniper/src/ast.rs                           |  10 +-
 juniper/src/graphql/mod.rs                   |   1 +
 juniper_codegen/src/graphql_scalar/derive.rs |  16 +-
 juniper_codegen/src/graphql_scalar/mod.rs    | 193 ++++++++++++++-----
 4 files changed, 157 insertions(+), 63 deletions(-)

diff --git a/juniper/src/ast.rs b/juniper/src/ast.rs
index c5f9897f8..40cceee4a 100644
--- a/juniper/src/ast.rs
+++ b/juniper/src/ast.rs
@@ -464,12 +464,12 @@ impl<S> InputValue<S> {
 
     /// Maps the [`ScalarValue`] type of this [`InputValue`] into the specified
     /// one.
-    pub fn map_scalar_value<To>(self) -> InputValue<To>
+    pub fn map_scalar_value<Into>(self) -> InputValue<Into>
     where
-        To: From<S> + 'static,
-        S: 'static,
+        S: ScalarValue,
+        Into: ScalarValue,
     {
-        if TypeId::of::<To>() == TypeId::of::<S>() {
+        if TypeId::of::<Into>() == TypeId::of::<S>() {
             // SAFETY: This is safe, because we're transmuting the value into
             //         itself, so no invariants may change and we're just
             //         satisfying the type checker.
@@ -481,7 +481,7 @@ impl<S> InputValue<S> {
         } else {
             match self {
                 Self::Null => InputValue::Null,
-                Self::Scalar(s) => InputValue::Scalar(s.into()),
+                Self::Scalar(s) => InputValue::Scalar(s.into_another()),
                 Self::Enum(v) => InputValue::Enum(v),
                 Self::Variable(n) => InputValue::Variable(n),
                 Self::List(l) => InputValue::List(
diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 9e0e1af92..a88b154dc 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -6,6 +6,7 @@ pub use crate::{
     macros::{input_value, value, vars},
     resolve::Type,
     value::Value,
+    GraphQLScalar as Scalar,
 };
 
 /*
diff --git a/juniper_codegen/src/graphql_scalar/derive.rs b/juniper_codegen/src/graphql_scalar/derive.rs
index 835ea37b2..b4503796f 100644
--- a/juniper_codegen/src/graphql_scalar/derive.rs
+++ b/juniper_codegen/src/graphql_scalar/derive.rs
@@ -1,5 +1,7 @@
 //! Code generation for `#[derive(GraphQLScalar)]` macro.
 
+use std::convert::TryFrom;
+
 use proc_macro2::TokenStream;
 use quote::ToTokens;
 use syn::{parse_quote, spanned::Spanned};
@@ -84,11 +86,8 @@ pub(super) fn parse_derived_methods(ast: &syn::DeriveInput, attr: &Attr) -> syn:
                     .first()
                     .filter(|_| fields.unnamed.len() == 1)
                     .cloned()
-                    .map(|f| Field {
-                        itself: f,
-                        is_named: false,
-                        behavior: None.unwrap_or_default(), // TODO: Parse attribute!
-                    })
+                    .map(Field::try_from)
+                    .transpose()?
                     .ok_or_else(|| {
                         ERR.custom_error(
                             ast.span(),
@@ -101,11 +100,8 @@ pub(super) fn parse_derived_methods(ast: &syn::DeriveInput, attr: &Attr) -> syn:
                     .first()
                     .filter(|_| fields.named.len() == 1)
                     .cloned()
-                    .map(|f| Field {
-                        itself: f,
-                        is_named: true,
-                        behavior: None.unwrap_or_default(), // TODO: Parse attribute!
-                    })
+                    .map(Field::try_from)
+                    .transpose()?
                     .ok_or_else(|| {
                         ERR.custom_error(
                             ast.span(),
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 15c44703d..0434ecfff 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -2,6 +2,8 @@
 //!
 //! [1]: https://spec.graphql.org/October2021#sec-Scalars
 
+use std::convert::TryFrom;
+
 use proc_macro2::{Literal, TokenStream};
 use quote::{format_ident, quote, ToTokens, TokenStreamExt};
 use syn::{
@@ -536,10 +538,10 @@ impl Definition {
         let predicates = &mut generics.make_where_clause().predicates;
         predicates.push(parse_quote! { #sv: Clone });
         predicates.push(parse_quote! {
-            ::juniper::behavior::Coerce<Self, #bh>:
-                ::juniper::resolve::TypeName<#inf, #bh>
-                + ::juniper::resolve::ScalarToken<#sv, #bh>
-                + ::juniper::resolve::InputValueOwned<#sv, #bh>
+            ::juniper::behavior::Coerce<Self>:
+                ::juniper::resolve::TypeName<#inf>
+                + ::juniper::resolve::ScalarToken<#sv>
+                + ::juniper::resolve::InputValueOwned<#sv>
         });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
@@ -566,7 +568,7 @@ impl Definition {
                     #sv: '__r,
                 {
                     registry.register_scalar_with::<
-                        ::juniper::behavior::Coerce<Self, #bh>, _, _,
+                        ::juniper::behavior::Coerce<Self>, _, _,
                     >(type_info, |meta| {
                         meta#description
                             #specified_by_url
@@ -808,27 +810,25 @@ impl Definition {
         let (sv, mut generics) = self.mix_scalar_value(generics);
         let lt: syn::GenericParam = parse_quote! { '__inp };
         generics.params.push(lt.clone());
-        generics
-            .make_where_clause()
-            .predicates
-            .extend(self.methods.bound_try_from_input_value(&lt, sv, bh));
+        let predicates = &mut generics.make_where_clause().predicates;
+        predicates.push(parse_quote! { #sv: #lt });
+        predicates.extend(self.methods.bound_try_from_input_value(&lt, sv, bh));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let conversion = self.methods.expand_try_from_input_value(sv, bh);
+        let error_ty = self.methods.expand_try_from_input_value_error(&lt, sv, bh);
+        let body = self.methods.expand_try_from_input_value(sv, bh);
 
         quote! {
             #[automatically_derived]
             impl#impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh> for #ty
                 #where_clause
             {
-                type Error = ::juniper::FieldError<#sv>;
+                type Error = #error_ty;
 
                 fn try_from_input_value(
                     input: &#lt ::juniper::graphql::InputValue<#sv>,
                 ) -> ::std::result::Result<Self, Self::Error> {
-                    #conversion.map_err(
-                        ::juniper::IntoFieldError::<#sv>::into_field_error,
-                    )
+                    #body
                 }
             }
         }
@@ -1363,13 +1363,14 @@ impl Methods {
                 from_input: Some(from_input),
                 ..
             } => {
-                let map_sv = sv.custom.as_ref().map(|custom_ty| {
-                    quote! {
-                        .map_scalar_value()
-                    }
+                let map_sv = sv.custom.is_some().then(|| {
+                    quote! { .map_scalar_value() }
                 });
                 quote! {
                     #from_input(input#map_sv)
+                        .map_err(
+                            ::juniper::IntoFieldError::<#sv>::into_field_error,
+                        )
                 }
             }
 
@@ -1382,13 +1383,45 @@ impl Methods {
                     <::juniper::behavior::Coerce<#field_ty, #bh> as
                      ::juniper::resolve::InputValue<'_, #sv, #field_bh>>
                         ::try_from_input_value(input)
-                            .into_inner()
+                            .map(::juniper::behavior::Coerce::into_inner)
                             .map(#self_constructor)
                 }
             }
         }
     }
 
+    /// Expands error type of [`resolve::InputValue`] trait.
+    ///
+    /// [`resolve::InputValue`]: juniper::resolve::InputValue
+    fn expand_try_from_input_value_error(
+        &self,
+        lt: &syn::GenericParam,
+        sv: &ScalarValue,
+        bh: &behavior::Type,
+    ) -> syn::Type {
+        match self {
+            Self::Custom { .. }
+            | Self::Delegated {
+                from_input: Some(_),
+                ..
+            } => {
+                parse_quote! {
+                    ::juniper::FieldError<#sv>
+                }
+            }
+
+            Self::Delegated { field, .. } => {
+                let field_ty = field.ty();
+                let field_bh = &field.behavior;
+
+                parse_quote! {
+                    <::juniper::behavior::Coerce<#field_ty, #bh> as
+                     ::juniper::resolve::InputValue<#lt, #sv, #field_bh>>::Error
+                }
+            }
+        }
+    }
+
     /// Generates additional trait bounds for [`resolve::InputValue`]
     /// implementation allowing to execute
     /// [`resolve::InputValue::try_from_input_value()`][0] method.
@@ -1407,15 +1440,15 @@ impl Methods {
                 from_input: Some(_),
                 ..
             } => {
+                let mut bounds = vec![parse_quote! {
+                    #sv: ::juniper::ScalarValue
+                }];
                 if let Some(custom_sv) = &sv.custom {
-                    vec![
-                        parse_quote! { #custom_sv: ::std::convert::From<#sv> },
-                        parse_quote! { #custom_sv: 'static },
-                        parse_quote! { #sv: 'static },
-                    ]
-                } else {
-                    vec![parse_quote! { #sv: ::juniper::ScalarValue }]
+                    bounds.push(parse_quote! {
+                        #custom_sv: ::juniper::ScalarValue
+                    });
                 }
+                bounds
             }
 
             Self::Delegated { field, .. } => {
@@ -1557,10 +1590,8 @@ impl ParseToken {
     fn expand_parse_scalar_token(&self, sv: &ScalarValue, bh: &behavior::Type) -> TokenStream {
         match self {
             Self::Custom(parse_token) => {
-                let into = sv.custom.as_ref().map(|custom_ty| {
-                    quote! {
-                        .map(<#sv as ::std::convert::From<#custom_ty>>::from)
-                    }
+                let into = sv.custom.is_some().then(|| {
+                    quote! { .map(::juniper::ScalarValue::into_another) }
                 });
                 quote! {
                     #parse_token(token)#into
@@ -1606,15 +1637,15 @@ impl ParseToken {
     ) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom(_) => {
-                vec![if let Some(custom_sv) = &sv.custom {
-                    parse_quote! {
-                        #sv: ::std::convert::From<#custom_sv>
-                    }
-                } else {
-                    parse_quote! {
-                        #sv: ::juniper::ScalarValue
-                    }
-                }]
+                let mut bounds = vec![parse_quote! {
+                    #sv: ::juniper::ScalarValue
+                }];
+                if let Some(custom_sv) = &sv.custom {
+                    bounds.push(parse_quote! {
+                        #custom_sv: ::juniper::ScalarValue
+                    });
+                }
+                bounds
             }
 
             Self::Delegated(delegated) => delegated
@@ -1630,6 +1661,65 @@ impl ParseToken {
     }
 }
 
+/// Available arguments behind `#[graphql]` attribute on a [`Field`] when
+/// generating code for a [GraphQL scalar][0] implementation.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Scalars
+#[derive(Debug, Default)]
+struct FieldAttr {
+    /// Explicitly specified type of the custom [`Behavior`] used for
+    /// [GraphQL scalar][0] implementation by the [`Field`].
+    ///
+    /// 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-Scalars
+    behavior: Option<SpanContainer<behavior::Type>>,
+}
+
+impl Parse for FieldAttr {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        let mut out = Self::default();
+        while !input.is_empty() {
+            let ident = input.parse_any_ident()?;
+            match ident.to_string().as_str() {
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
+                name => {
+                    return Err(err::unknown_arg(&ident, name));
+                }
+            }
+            input.try_parse::<token::Comma>()?;
+        }
+        Ok(out)
+    }
+}
+
+impl FieldAttr {
+    /// Tries to merge two [`FieldAttr`]s into a single one, reporting about
+    /// duplicates, if any.
+    fn try_merge(self, mut another: Self) -> syn::Result<Self> {
+        Ok(Self {
+            behavior: try_merge_opt!(behavior: self, another),
+        })
+    }
+
+    /// Parses [`FieldAttr`] from the given multiple `name`d [`syn::Attribute`]s
+    /// placed on a field definition.
+    fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> syn::Result<Self> {
+        filter_attrs(name, attrs)
+            .map(|attr| attr.parse_args())
+            .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))
+    }
+}
+
 /// Inner field of a type implementing [GraphQL scalar][0], that the
 /// implementation delegates calls to.
 ///
@@ -1638,19 +1728,28 @@ struct Field {
     /// This [`Field`] itself.
     itself: syn::Field,
 
-    /// Indicator whether this [`Field`] is named.
-    is_named: bool,
-
     /// [`Behavior`] parametrization of this [`Field`].
     ///
     /// [`Behavior`]: juniper::behavior
     behavior: behavior::Type,
 }
 
+impl TryFrom<syn::Field> for Field {
+    type Error = syn::Error;
+
+    fn try_from(field: syn::Field) -> syn::Result<Self> {
+        let attr = FieldAttr::from_attrs("graphql", &field.attrs)?;
+        Ok(Self {
+            itself: field,
+            behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
+        })
+    }
+}
+
 impl ToTokens for Field {
     fn to_tokens(&self, tokens: &mut TokenStream) {
-        if self.is_named {
-            self.itself.ident.to_tokens(tokens)
+        if let Some(name) = &self.itself.ident {
+            name.to_tokens(tokens)
         } else {
             tokens.append(Literal::u8_unsuffixed(0))
         }
@@ -1668,10 +1767,8 @@ impl Field {
     ///
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn closure_constructor(&self) -> TokenStream {
-        if self.is_named {
-            let ident = &self.itself.ident;
-
-            quote! { |v| Self { #ident: v } }
+        if let Some(name) = &self.itself.ident {
+            quote! { |v| Self { #name: v } }
         } else {
             quote! { Self }
         }

From 4d7770d226b2085f2d087d73a7b6bcd067ae2942 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Sun, 19 Jun 2022 23:06:59 +0200
Subject: [PATCH 33/58] Impl macro for scalars, vol.5 [skip ci]

---
 juniper/src/behavior.rs                      |   7 +-
 juniper_codegen/src/graphql_scalar/attr.rs   |   6 +-
 juniper_codegen/src/graphql_scalar/derive.rs |  18 +--
 juniper_codegen/src/graphql_scalar/mod.rs    | 138 ++++++++-----------
 4 files changed, 76 insertions(+), 93 deletions(-)

diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
index 6ad3fee4b..c98c959f3 100644
--- a/juniper/src/behavior.rs
+++ b/juniper/src/behavior.rs
@@ -1,4 +1,4 @@
-//! Default GraphQL behaviors.
+//! GraphQL types behavior machinery.
 
 use std::{marker::PhantomData, sync::atomic::AtomicPtr};
 
@@ -13,22 +13,25 @@ use crate::{
 #[derive(Debug)]
 pub enum Standard {}
 
-/// Coercion of behavior types and type parameters.
+/// Transparent wrapper allowing coercion of behavior types and type parameters.
 #[repr(transparent)]
 pub struct Coerce<T: ?Sized, To: ?Sized = Standard>(PhantomData<AtomicPtr<Box<To>>>, T);
 
 impl<T, To: ?Sized> Coerce<T, To> {
+    /// Wraps the provided `value` into a [`Coerce`] wrapper.
     #[must_use]
     pub const fn wrap(value: T) -> Self {
         Self(PhantomData, value)
     }
 
+    /// Unwraps into the inner value.
     #[must_use]
     pub fn into_inner(self) -> T {
         self.1
     }
 }
 
+/// Wraps the provided `value` into a [`Coerce`] wrapper.
 #[must_use]
 pub const fn coerce<T, To: ?Sized>(value: T) -> Coerce<T, To> {
     Coerce::wrap(value)
diff --git a/juniper_codegen/src/graphql_scalar/attr.rs b/juniper_codegen/src/graphql_scalar/attr.rs
index e9754e970..01b34dd43 100644
--- a/juniper_codegen/src/graphql_scalar/attr.rs
+++ b/juniper_codegen/src/graphql_scalar/attr.rs
@@ -6,7 +6,6 @@ use syn::{parse_quote, spanned::Spanned};
 
 use crate::{
     common::{parse, scalar},
-    graphql_scalar::TypeOrIdent,
     GraphQLScope,
 };
 
@@ -50,7 +49,7 @@ fn expand_on_type_alias(
     let scalar = scalar::Type::parse(attr.scalar.as_deref(), &ast.generics);
 
     let def = Definition {
-        ty: TypeOrIdent::Type(ast.ty.clone()),
+        ident: ast.ident.clone(),
         where_clause: attr
             .where_clause
             .map_or_else(Vec::new, |cl| cl.into_inner()),
@@ -80,11 +79,12 @@ fn expand_on_derive_input(
     ast: syn::DeriveInput,
 ) -> syn::Result<TokenStream> {
     let attr = Attr::from_attrs("graphql_scalar", &attrs)?;
+
     let methods = parse_derived_methods(&ast, &attr)?;
     let scalar = scalar::Type::parse(attr.scalar.as_deref(), &ast.generics);
 
     let def = Definition {
-        ty: TypeOrIdent::Ident(ast.ident.clone()),
+        ident: ast.ident.clone(),
         where_clause: attr
             .where_clause
             .map_or_else(Vec::new, |cl| cl.into_inner()),
diff --git a/juniper_codegen/src/graphql_scalar/derive.rs b/juniper_codegen/src/graphql_scalar/derive.rs
index b4503796f..33c0db850 100644
--- a/juniper_codegen/src/graphql_scalar/derive.rs
+++ b/juniper_codegen/src/graphql_scalar/derive.rs
@@ -8,7 +8,7 @@ use syn::{parse_quote, spanned::Spanned};
 
 use crate::{common::scalar, result::GraphQLScope};
 
-use super::{Attr, Definition, Field, Methods, ParseToken, TypeOrIdent};
+use super::{Attr, Definition, Field, Methods, ParseToken};
 
 /// [`GraphQLScope`] of errors for `#[derive(GraphQLScalar)]` macro.
 const ERR: GraphQLScope = GraphQLScope::ScalarDerive;
@@ -17,21 +17,23 @@ const ERR: GraphQLScope = GraphQLScope::ScalarDerive;
 pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
     let ast = syn::parse2::<syn::DeriveInput>(input)?;
     let attr = Attr::from_attrs("graphql", &ast.attrs)?;
+
     let methods = parse_derived_methods(&ast, &attr)?;
     let scalar = scalar::Type::parse(attr.scalar.as_deref(), &ast.generics);
+    let name = attr
+        .name
+        .as_deref()
+        .cloned()
+        .unwrap_or_else(|| ast.ident.to_string());
 
     Ok(Definition {
-        ty: TypeOrIdent::Ident(ast.ident.clone()),
+        ident: ast.ident,
         where_clause: attr
             .where_clause
             .map_or_else(Vec::new, |cl| cl.into_inner()),
-        generics: ast.generics.clone(),
+        generics: ast.generics,
         methods,
-        name: attr
-            .name
-            .as_deref()
-            .cloned()
-            .unwrap_or_else(|| ast.ident.to_string()),
+        name,
         description: attr.description.as_deref().cloned(),
         specified_by_url: attr.specified_by_url.as_deref().cloned(),
         scalar,
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 0434ecfff..aca8dce99 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -284,17 +284,6 @@ impl Attr {
     }
 }
 
-/// [`syn::Type`] in case of `#[graphql_scalar]` or [`syn::Ident`] in case of
-/// `#[derive(GraphQLScalar)]`.
-#[derive(Clone)]
-enum TypeOrIdent {
-    /// [`syn::Type`].
-    Type(Box<syn::Type>),
-
-    /// [`syn::Ident`].
-    Ident(syn::Ident),
-}
-
 /// Definition of [GraphQL scalar][1] for code generation.
 ///
 /// [1]: https://spec.graphql.org/October2021#sec-Scalars
@@ -304,10 +293,10 @@ struct Definition {
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
     name: String,
 
-    /// [`TypeOrIdent`] of this [GraphQL scalar][1] in GraphQL schema.
+    /// [`syn::Ident`] of the Rust type implementing this [GraphQL scalar][0].
     ///
-    /// [1]: https://spec.graphql.org/October2021#sec-Scalars
-    ty: TypeOrIdent,
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    ident: syn::Ident,
 
     /// Additional [`Self::generics`] [`syn::WhereClause`] predicates.
     where_clause: Vec<syn::WherePredicate>,
@@ -371,7 +360,7 @@ impl ToTokens for Definition {
         self.impl_resolve_type_name().to_tokens(into);
         //self.impl_resolve_value().to_tokens(into);
         //self.impl_resolve_value_async().to_tokens(into);
-        //self.impl_resolve_to_input_value().to_tokens(into);
+        self.impl_resolve_to_input_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
         //self.impl_graphql_output_type().to_tokens(into);
@@ -749,19 +738,20 @@ impl Definition {
     /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_to_input_value(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (sv, mut generics) = self.mix_scalar_value(generics);
         generics
             .make_where_clause()
             .predicates
-            .push(self.methods.bound_to_input_value(sv));
+            .extend(self.methods.bound_to_input_value(sv));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         let body = self.methods.expand_to_input_value(sv);
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ToInputValue<#sv> for #ty
+            impl#impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
                 #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
@@ -812,11 +802,11 @@ impl Definition {
         generics.params.push(lt.clone());
         let predicates = &mut generics.make_where_clause().predicates;
         predicates.push(parse_quote! { #sv: #lt });
-        predicates.extend(self.methods.bound_try_from_input_value(&lt, sv, bh));
+        predicates.extend(self.methods.bound_try_from_input_value(&lt, sv));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let error_ty = self.methods.expand_try_from_input_value_error(&lt, sv, bh);
-        let body = self.methods.expand_try_from_input_value(sv, bh);
+        let error_ty = self.methods.expand_try_from_input_value_error(&lt, sv);
+        let body = self.methods.expand_try_from_input_value(sv);
 
         quote! {
             #[automatically_derived]
@@ -873,10 +863,10 @@ impl Definition {
         generics
             .make_where_clause()
             .predicates
-            .extend(self.methods.bound_parse_scalar_token(&sv, bh));
+            .extend(self.methods.bound_parse_scalar_token(sv));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let body = self.methods.expand_parse_scalar_token(&sv, bh);
+        let body = self.methods.expand_parse_scalar_token(sv);
 
         quote! {
             #[automatically_derived]
@@ -987,12 +977,10 @@ impl Definition {
     fn impl_self_and_generics(&self, for_async: bool) -> (TokenStream, syn::Generics) {
         let mut generics = self.generics.clone();
 
-        let ty = match &self.ty {
-            TypeOrIdent::Type(ty) => ty.into_token_stream(),
-            TypeOrIdent::Ident(ident) => {
-                let (_, ty_gen, _) = self.generics.split_for_impl();
-                quote! { #ident#ty_gen }
-            }
+        let ty = {
+            let ident = &self.ident;
+            let (_, ty_gen, _) = self.generics.split_for_impl();
+            quote! { #ident#ty_gen }
         };
 
         if !self.where_clause.is_empty() {
@@ -1022,15 +1010,10 @@ impl Definition {
                 ModifyLifetimes.visit_generics_mut(&mut generics);
 
                 let lifetimes = generics.lifetimes().map(|lt| &lt.lifetime);
-                let ty = match self.ty.clone() {
-                    TypeOrIdent::Type(mut ty) => {
-                        ModifyLifetimes.visit_type_mut(&mut ty);
-                        ty.into_token_stream()
-                    }
-                    TypeOrIdent::Ident(ident) => {
-                        let (_, ty_gens, _) = generics.split_for_impl();
-                        quote! { #ident#ty_gens }
-                    }
+                let ty = {
+                    let ident = &self.ident;
+                    let (_, ty_gen, _) = generics.split_for_impl();
+                    quote! { #ident#ty_gen }
                 };
 
                 quote! { for<#( #lifetimes ),*> #ty }
@@ -1059,12 +1042,10 @@ impl Definition {
     fn ty_and_generics(&self) -> (syn::Type, syn::Generics) {
         let mut generics = self.generics.clone();
 
-        let ty = match &self.ty {
-            TypeOrIdent::Type(ty) => (**ty).clone(),
-            TypeOrIdent::Ident(ident) => {
-                let (_, ty_gen, _) = self.generics.split_for_impl();
-                parse_quote! { #ident#ty_gen }
-            }
+        let ty = {
+            let ident = &self.ident;
+            let (_, ty_gen, _) = self.generics.split_for_impl();
+            parse_quote! { #ident#ty_gen }
         };
 
         if !self.where_clause.is_empty() {
@@ -1285,17 +1266,22 @@ impl Methods {
                 to_output: Some(to_output),
                 ..
             } => {
+                let into = sv.custom.is_some().then(|| {
+                    quote! { .map_scalar_value() }
+                });
                 quote! {
-                    let v = #to_output(self);
+                    let v = #to_output(self)#into;
                     ::juniper::resolve::ToInputValue::<#sv>::to_input_value(&v)
                 }
             }
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
 
                 quote! {
-                    <#field_ty as ::juniper::resolve::ToInputValue<#sv>>
+                    <#field_ty as
+                     ::juniper::resolve::ToInputValue<#sv, #field_bh>>
                         ::to_input_value(&self.#field)
                 }
             }
@@ -1308,23 +1294,30 @@ impl Methods {
     ///
     /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
     /// [0]: juniper::resolve::ToInputValue::to_input_value
-    fn bound_to_input_value(&self, sv: &ScalarValue) -> syn::WherePredicate {
+    fn bound_to_input_value(&self, sv: &ScalarValue) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom { .. }
             | Self::Delegated {
                 to_output: Some(_), ..
             } => {
-                parse_quote! {
+                let mut bounds = vec![parse_quote! {
                     #sv: ::juniper::ScalarValue
+                }];
+                if let Some(custom_sv) = &sv.custom {
+                    bounds.push(parse_quote! {
+                        #custom_sv: ::juniper::ScalarValue
+                    });
                 }
+                bounds
             }
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
 
-                parse_quote! {
-                    #field_ty: ::juniper::resolve::ToInputValue<#sv>>
-                }
+                vec![parse_quote! {
+                    #field_ty: ::juniper::resolve::ToInputValue<#sv, #field_bh>
+                }]
             }
         }
     }
@@ -1356,7 +1349,7 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::InputValue::try_from_input_value
-    fn expand_try_from_input_value(&self, sv: &ScalarValue, bh: &behavior::Type) -> TokenStream {
+    fn expand_try_from_input_value(&self, sv: &ScalarValue) -> TokenStream {
         match self {
             Self::Custom { from_input, .. }
             | Self::Delegated {
@@ -1380,10 +1373,9 @@ impl Methods {
                 let self_constructor = field.closure_constructor();
 
                 quote! {
-                    <::juniper::behavior::Coerce<#field_ty, #bh> as
+                    <#field_ty as
                      ::juniper::resolve::InputValue<'_, #sv, #field_bh>>
                         ::try_from_input_value(input)
-                            .map(::juniper::behavior::Coerce::into_inner)
                             .map(#self_constructor)
                 }
             }
@@ -1397,7 +1389,6 @@ impl Methods {
         &self,
         lt: &syn::GenericParam,
         sv: &ScalarValue,
-        bh: &behavior::Type,
     ) -> syn::Type {
         match self {
             Self::Custom { .. }
@@ -1415,7 +1406,7 @@ impl Methods {
                 let field_bh = &field.behavior;
 
                 parse_quote! {
-                    <::juniper::behavior::Coerce<#field_ty, #bh> as
+                    <#field_ty as
                      ::juniper::resolve::InputValue<#lt, #sv, #field_bh>>::Error
                 }
             }
@@ -1432,7 +1423,6 @@ impl Methods {
         &self,
         lt: &syn::GenericParam,
         sv: &ScalarValue,
-        bh: &behavior::Type,
     ) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom { .. }
@@ -1456,7 +1446,7 @@ impl Methods {
                 let field_bh = &field.behavior;
 
                 vec![parse_quote! {
-                    ::juniper::behavior::Coerce<#field_ty, #bh>:
+                    #field_ty:
                         ::juniper::resolve::InputValue<#lt, #sv, #field_bh>
                 }]
             }
@@ -1489,20 +1479,20 @@ impl Methods {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, sv: &ScalarValue, bh: &behavior::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &ScalarValue) -> TokenStream {
         match self {
             Self::Custom { parse_token, .. }
             | Self::Delegated {
                 parse_token: Some(parse_token),
                 ..
-            } => parse_token.expand_parse_scalar_token(sv, bh),
+            } => parse_token.expand_parse_scalar_token(sv),
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
                 let field_bh = &field.behavior;
 
                 quote! {
-                    <::juniper::behavior::Coerce<#field_ty, #bh> as
+                    <#field_ty as
                      ::juniper::resolve::ScalarToken<#sv, #field_bh>>
                         ::parse_scalar_token(token)
                 }
@@ -1516,25 +1506,20 @@ impl Methods {
     ///
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn bound_parse_scalar_token(
-        &self,
-        sv: &ScalarValue,
-        bh: &behavior::Type,
-    ) -> Vec<syn::WherePredicate> {
+    fn bound_parse_scalar_token(&self, sv: &ScalarValue) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom { parse_token, .. }
             | Self::Delegated {
                 parse_token: Some(parse_token),
                 ..
-            } => parse_token.bound_parse_scalar_token(sv, bh),
+            } => parse_token.bound_parse_scalar_token(sv),
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
                 let field_bh = &field.behavior;
 
                 vec![parse_quote! {
-                    ::juniper::behavior::Coerce<#field_ty, #bh>:
-                        ::juniper::resolve::ScalarToken<#sv, #field_bh>
+                    #field_ty: ::juniper::resolve::ScalarToken<#sv, #field_bh>
                 }]
             }
         }
@@ -1587,7 +1572,7 @@ impl ParseToken {
     /// method.
     ///
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn expand_parse_scalar_token(&self, sv: &ScalarValue, bh: &behavior::Type) -> TokenStream {
+    fn expand_parse_scalar_token(&self, sv: &ScalarValue) -> TokenStream {
         match self {
             Self::Custom(parse_token) => {
                 let into = sv.custom.is_some().then(|| {
@@ -1604,16 +1589,14 @@ impl ParseToken {
                     acc.map_or_else(
                         || {
                             Some(quote! {
-                                <::juniper::behavior::Coerce<#ty, #bh> as
-                                 ::juniper::resolve::ScalarToken<#sv>>
+                                <#ty as ::juniper::resolve::ScalarToken<#sv>>
                                     ::parse_scalar_token(token)
                             })
                         },
                         |prev| {
                             Some(quote! {
                                 #prev.or_else(|_| {
-                                    <::juniper::behavior::Coerce<#ty, #bh> as
-                                     ::juniper::resolve::ScalarToken<#sv>>
+                                    <#ty as ::juniper::resolve::ScalarToken<#sv>>
                                         ::parse_scalar_token(token)
                                 })
                             })
@@ -1630,11 +1613,7 @@ impl ParseToken {
     ///
     /// [`resolve::ScalarToken`]: juniper::resolve::ScalarToken
     /// [0]: juniper::resolve::ScalarToken::parse_scalar_token
-    fn bound_parse_scalar_token(
-        &self,
-        sv: &ScalarValue,
-        bh: &behavior::Type,
-    ) -> Vec<syn::WherePredicate> {
+    fn bound_parse_scalar_token(&self, sv: &ScalarValue) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom(_) => {
                 let mut bounds = vec![parse_quote! {
@@ -1652,8 +1631,7 @@ impl ParseToken {
                 .iter()
                 .map(|ty| {
                     parse_quote! {
-                        ::juniper::behavior::Coerce<#ty, #bh>:
-                            ::juniper::resolve::ScalarToken<#sv>
+                        #ty: ::juniper::resolve::ScalarToken<#sv>
                     }
                 })
                 .collect(),

From 66c11ec7825b49a617f75b4671a7a9143e305c54 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 20 Jun 2022 17:41:45 +0200
Subject: [PATCH 34/58] Impl macro for scalars, vol.6 [skip ci]

---
 juniper_codegen/src/graphql_scalar/mod.rs | 167 ++++++++++++++++------
 1 file changed, 121 insertions(+), 46 deletions(-)

diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index aca8dce99..876ec9fa0 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -358,14 +358,14 @@ impl ToTokens for Definition {
         ////////////////////////////////////////////////////////////////////////
         self.impl_resolve_type().to_tokens(into);
         self.impl_resolve_type_name().to_tokens(into);
-        //self.impl_resolve_value().to_tokens(into);
-        //self.impl_resolve_value_async().to_tokens(into);
+        self.impl_resolve_value().to_tokens(into);
+        self.impl_resolve_value_async().to_tokens(into);
         self.impl_resolve_to_input_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
-        //self.impl_graphql_output_type().to_tokens(into);
-        //self.impl_graphql_output_type().to_tokens(into);
-        //self.impl_graphql_scalar().to_tokens(into);
+        self.impl_graphql_input_type().to_tokens(into);
+        self.impl_graphql_output_type().to_tokens(into);
+        self.impl_graphql_scalar().to_tokens(into);
         self.impl_reflect().to_tokens(into);
     }
 }
@@ -395,29 +395,58 @@ impl Definition {
         }
     }
 
-    /// Returns generated code implementing [`graphql::InputType`] and
-    /// [`graphql::OutputType`] traits for this [GraphQL scalar][0].
+    /// Returns generated code implementing [`graphql::InputType`] trait for
+    /// this [GraphQL scalar][0].
     ///
     /// [`graphql::InputType`]: juniper::graphql::InputType
-    /// [`graphql::OutputType`]: juniper::graphql::OutputType
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     #[must_use]
-    fn impl_graphql_input_and_output_type(&self) -> TokenStream {
+    fn impl_graphql_input_type(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
         let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::resolve::Type<#inf, #sv, #bh>
+                  + ::juniper::resolve::ToInputValue<#sv, #bh>
+                  + ::juniper::resolve::InputValue<#lt, #sv, #bh>
+        });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::InputType<#sv> for #ty
-                #where_clause
+            impl#impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+                for #ty #where_clause
             {
                 fn assert_input_type() {}
             }
+        }
+    }
 
+    /// Returns generated code implementing [`graphql::OutputType`] trait for
+    /// this [GraphQL scalar][0].
+    ///
+    /// [`graphql::OutputType`]: juniper::graphql::OutputType
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    #[must_use]
+    fn impl_graphql_output_type(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::resolve::Type<#inf, #sv, #bh>
+                  + ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+                  + ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::OutputType<#sv> for #ty
-                #where_clause
+            impl#impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
+                for #ty #where_clause
             {
                 fn assert_output_type() {}
             }
@@ -431,14 +460,23 @@ impl Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     #[must_use]
     fn impl_graphql_scalar(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
         let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+                  + ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
+                  + ::juniper::resolve::ScalarToken<#sv, #bh>
+        });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::Scalar<#sv> for #ty
-                #where_clause
+            impl#impl_gens ::juniper::graphql::Scalar<#lt, #inf, #cx, #sv, #bh>
+                for #ty #where_clause
             {
                 fn assert_scalar() {}
             }
@@ -524,9 +562,9 @@ impl Definition {
         let (ty, generics) = self.ty_and_generics();
         let (inf, generics) = self.mix_type_info(generics);
         let (sv, mut generics) = self.mix_scalar_value(generics);
-        let predicates = &mut generics.make_where_clause().predicates;
-        predicates.push(parse_quote! { #sv: Clone });
-        predicates.push(parse_quote! {
+        let preds = &mut generics.make_where_clause().predicates;
+        preds.push(parse_quote! { #sv: Clone });
+        preds.push(parse_quote! {
             ::juniper::behavior::Coerce<Self>:
                 ::juniper::resolve::TypeName<#inf>
                 + ::juniper::resolve::ScalarToken<#sv>
@@ -610,6 +648,7 @@ impl Definition {
     /// [`resolve::Value`]: juniper::resolve::Value
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_value(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (inf, generics) = self.mix_type_info(generics);
         let (cx, generics) = self.mix_context(generics);
@@ -617,20 +656,20 @@ impl Definition {
         generics
             .make_where_clause()
             .predicates
-            .push(self.methods.bound_resolve_value(&inf, &cx, sv));
+            .extend(self.methods.bound_resolve_value(&inf, &cx, sv));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         let body = self.methods.expand_resolve_value(&inf, &cx, sv);
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #sv> for #ty
-                #where_clause
+            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+                for #ty #where_clause
             {
                 fn resolve_value(
                     &self,
-                    selection: Option<&[::juniper::Selection<'_, #sv>]>,
-                    info: &#inf,
+                    selection_set: Option<&[::juniper::Selection<'_, #sv>]>,
+                    type_info: &#inf,
                     executor: &::juniper::Executor<'_, '_, #cx, #sv>,
                 ) -> ::juniper::ExecutionResult<#sv> {
                     #body
@@ -675,13 +714,14 @@ impl Definition {
     /// [`resolve::ValueAsync`]: juniper::resolve::ValueAsync
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_resolve_value_async(&self) -> TokenStream {
+        let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (inf, generics) = self.mix_type_info(generics);
         let (cx, generics) = self.mix_context(generics);
         let (sv, mut generics) = self.mix_scalar_value(generics);
         let preds = &mut generics.make_where_clause().predicates;
         preds.push(parse_quote! {
-            Self: ::juniper::resolve::Value<#inf, #cx, #sv>
+            Self: ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
         });
         preds.push(parse_quote! {
             #sv: Send
@@ -690,17 +730,20 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv> for #ty
-                #where_clause
+            impl#impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
+                for #ty #where_clause
             {
                 fn resolve_value_async<'__r>(
                     &'__r self,
-                    selection: Option<&'__r [::juniper::Selection<'_, #sv>]>,
-                    info: &'__r #inf,
+                    sel_set: Option<&'__r [::juniper::Selection<'_, #sv>]>,
+                    type_info: &'__r #inf,
                     executor: &'__r ::juniper::Executor<'_, '_, #cx, #sv>,
-                ) -> ::juniper::BoxFuture<'__r, ::juniper::ExecutionResult<#sv>> {
-                    let v = <Self as ::juniper::resolve::Value<#inf, #cx, #sv>>
-                        ::resolve_value(self, selection, info, executor);
+                ) -> ::juniper::BoxFuture<
+                    '__r, ::juniper::ExecutionResult<#sv>,
+                > {
+                    let v =
+                        <Self as ::juniper::resolve::Value<#inf, #cx, #sv, #bh>>
+                            ::resolve_value(self, sel_set, type_info, executor);
                     ::std::boxed::Box::pin(::juniper::futures::future::ready(v))
                 }
             }
@@ -797,12 +840,12 @@ impl Definition {
     fn impl_resolve_input_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (sv, mut generics) = self.mix_scalar_value(generics);
-        let lt: syn::GenericParam = parse_quote! { '__inp };
-        generics.params.push(lt.clone());
-        let predicates = &mut generics.make_where_clause().predicates;
-        predicates.push(parse_quote! { #sv: #lt });
-        predicates.extend(self.methods.bound_try_from_input_value(&lt, sv));
+        let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        generics
+            .make_where_clause()
+            .predicates
+            .extend(self.methods.bound_try_from_input_value(&lt, sv));
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         let error_ty = self.methods.expand_try_from_input_value_error(&lt, sv);
@@ -1090,6 +1133,25 @@ impl Definition {
         generics.params.push(parse_quote! { #sv });
         (sv, generics)
     }
+
+    /// Mixes an [`InputValue`]'s lifetime [`syn::GenericParam`] into the
+    /// provided [`syn::Generics`] and returns it.
+    ///
+    /// [`InputValue`]: juniper::resolve::InputValue
+    #[must_use]
+    fn mix_input_lifetime(
+        &self,
+        mut generics: syn::Generics,
+        sv: &ScalarValue,
+    ) -> (syn::GenericParam, syn::Generics) {
+        let lt: syn::GenericParam = parse_quote! { '__inp };
+        generics.params.push(lt.clone());
+        generics
+            .make_where_clause()
+            .predicates
+            .push(parse_quote! { #sv: #lt });
+        (lt, generics)
+    }
 }
 
 /// Adds `__fa__` prefix to all lifetimes to avoid "lifetime name `'a` shadows a
@@ -1183,18 +1245,23 @@ impl Methods {
                 to_output: Some(to_output),
                 ..
             } => {
-                quote! { Ok(#to_output(self)) }
+                let into = sv.custom.is_some().then(|| {
+                    quote! { .map_scalar_value() }
+                });
+                quote! { Ok(#to_output(self)#into) }
             }
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
 
                 quote! {
-                    <#field_ty as ::juniper::resolve::Value<#inf, #cx, #sv>>
+                    <#field_ty as
+                     ::juniper::resolve::Value<#inf, #cx, #sv, #field_bh>>
                         ::resolve_value(
                             &self.#field,
-                            info,
-                            selection,
+                            selection_set,
+                            type_info,
                             executor,
                         )
                 }
@@ -1212,23 +1279,31 @@ impl Methods {
         inf: &syn::Ident,
         cx: &syn::Ident,
         sv: &ScalarValue,
-    ) -> syn::WherePredicate {
+    ) -> Vec<syn::WherePredicate> {
         match self {
             Self::Custom { .. }
             | Self::Delegated {
                 to_output: Some(_), ..
             } => {
-                parse_quote! {
+                let mut bounds = vec![parse_quote! {
                     #sv: ::juniper::ScalarValue
+                }];
+                if let Some(custom_sv) = &sv.custom {
+                    bounds.push(parse_quote! {
+                        #custom_sv: ::juniper::ScalarValue
+                    });
                 }
+                bounds
             }
 
             Self::Delegated { field, .. } => {
                 let field_ty = field.ty();
+                let field_bh = &field.behavior;
 
-                parse_quote! {
-                    #field_ty: ::juniper::resolve::Value<#inf, #cx, #sv>
-                }
+                vec![parse_quote! {
+                    #field_ty:
+                        ::juniper::resolve::Value<#inf, #cx, #sv, #field_bh>
+                }]
             }
         }
     }

From 2d89de3403e4e22d2df49d0e88bffa0391ac0486 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 20 Jun 2022 19:12:58 +0200
Subject: [PATCH 35/58] Impl new machinery for `Vec` [skip ci]

---
 juniper/src/executor/mod.rs       |  20 ++--
 juniper/src/schema/meta.rs        |   4 +-
 juniper/src/types/iter.rs         |  47 +++++-----
 juniper/src/types/mod.rs          |   2 +-
 juniper/src/types/vec.rs          | 147 +++++++++++++++++++++---------
 juniper_codegen/src/common/mod.rs |   2 +-
 6 files changed, 146 insertions(+), 76 deletions(-)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 2026f97b6..73d8b6a48 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -85,6 +85,12 @@ where
     field_path: Arc<FieldPath<'a>>,
 }
 
+impl<'r, 'a, CX: ?Sized, SV> Executor<'r, 'a, CX, SV> {
+    pub(crate) fn current_type_reworked(&self) -> &TypeType<'a, SV> {
+        &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
@@ -1381,17 +1387,17 @@ impl<'r, S: 'r> Registry<'r, S> {
     /// values of this type matches it.
     ///
     /// [`graphql::Type`]: resolve::Type
-    pub fn build_list_type_new<T, Info>(
+    pub fn wrap_list<'ti, T, TI>(
         &mut self,
-        info: &Info,
+        type_info: &'ti TI,
         expected_size: Option<usize>,
-    ) -> ListMeta<'r>
+    ) -> MetaType<'r, S>
     where
-        T: resolve::Type<Info, S> + ?Sized,
-        Info: ?Sized,
+        T: resolve::Type<TI, S> + ?Sized,
+        TI: ?Sized,
+        'ti: 'r,
     {
-        todo!()
-        //ListMeta::new(T::meta(self, info).as_type(), expected_size)
+        ListMeta::new(T::meta(self, type_info).into(), expected_size).into_meta()
     }
 
     /// Creates a [`NullableMeta`] type.
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index 1113cffe6..47e7f705a 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -563,7 +563,7 @@ impl<'a, S> ScalarMeta<'a, S> {
 }
 
 impl<'a> ListMeta<'a> {
-    /// Build a new [`ListMeta`] type by wrapping the specified [`Type`].
+    /// Builds a new [`ListMeta`] type by wrapping the specified [`Type`].
     ///
     /// Specifying `expected_size` will be used to ensure that values of this
     /// type will always match it.
@@ -581,7 +581,7 @@ impl<'a> ListMeta<'a> {
 }
 
 impl<'a> NullableMeta<'a> {
-    /// Build a new [`NullableMeta`] type by wrapping the specified [`Type`].
+    /// Builds a new [`NullableMeta`] type by wrapping the specified [`Type`].
     pub fn new(of_type: Type<'a>) -> Self {
         Self { of_type }
     }
diff --git a/juniper/src/types/iter.rs b/juniper/src/types/iter.rs
index 8d6aad9df..f0f599a04 100644
--- a/juniper/src/types/iter.rs
+++ b/juniper/src/types/iter.rs
@@ -2,28 +2,28 @@
 
 use crate::{graphql, resolve, ExecutionResult, Executor, Selection};
 
-/*
-pub fn resolve_list<'t, T, S, Info, Ctx, I>(
+pub fn resolve_list<'t, T, TI, CX, SV, BH, I>(
     iter: I,
-    selection_set: Option<&[Selection<'_, S>]>,
-    info: &Info,
-    executor: &Executor<Ctx, S>,
-) -> ExecutionResult<S>
+    selection_set: Option<&[Selection<'_, SV>]>,
+    type_info: &TI,
+    executor: &Executor<CX, SV>,
+) -> ExecutionResult<SV>
 where
     I: Iterator<Item = &'t T> + ExactSizeIterator,
-    T: resolve::Value<Info, Ctx, S> + ?Sized + 't,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH> + ?Sized + 't,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     let is_non_null = executor
-        .current_type_new()
+        .current_type_reworked()
         .list_contents()
         .ok_or("Iterating over non-list type")?
         .is_non_null();
 
     let mut values = Vec::with_capacity(iter.len());
     for v in iter {
-        let val = v.resolve_value(selection_set, info, executor)?;
+        let val = v.resolve_value(selection_set, type_info, executor)?;
         if is_non_null && val.is_null() {
             return Err("Resolved `null` on non-null type".into());
         }
@@ -32,28 +32,32 @@ where
     Ok(graphql::Value::list(values))
 }
 
-pub async fn resolve_list_async<'a, 't, T, S, Info, Ctx, I>(
+pub async fn resolve_list_async<'t, 'r, T, TI, CX, SV, BH, I>(
     iter: I,
-    selection_set: Option<&[Selection<'_, S>]>,
-    info: &'a Info,
-    executor: &'a Executor<'a, 'a, Ctx, S>,
-) -> ExecutionResult<S>
+    selection_set: Option<&[Selection<'_, SV>]>,
+    type_info: &'r TI,
+    executor: &'r Executor<'r, '_, CX, SV>,
+) -> ExecutionResult<SV>
 where
     I: Iterator<Item = &'t T> + ExactSizeIterator,
-    T: resolve::ValueAsync<Info, Ctx, S> + ?Sized + 't,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + ?Sized + 't,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     use futures::stream::{FuturesOrdered, StreamExt as _};
 
     let is_non_null = executor
-        .current_type_new()
+        .current_type_reworked()
         .list_contents()
         .ok_or("Iterating over non-list type")?
         .is_non_null();
 
     let mut futs = iter
-        .map(|v| async move { v.resolve_value_async(selection_set, info, executor).await })
+        .map(|v| async move {
+            v.resolve_value_async(selection_set, type_info, executor)
+                .await
+        })
         .collect::<FuturesOrdered<_>>();
 
     let mut values = Vec::with_capacity(futs.len());
@@ -66,4 +70,3 @@ where
     }
     Ok(graphql::Value::list(values))
 }
-*/
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index d331959a3..44635ccd1 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -10,7 +10,7 @@ mod ref_mut;
 mod result;
 mod slice;
 mod r#str;
-mod vec;
+pub mod vec;
 
 pub mod async_await;
 pub mod base;
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
index ad4cd8edb..df2d87a68 100644
--- a/juniper/src/types/vec.rs
+++ b/juniper/src/types/vec.rs
@@ -1,114 +1,175 @@
 //! GraphQL implementation for [`Vec`].
 
 use crate::{
+    behavior,
     executor::{ExecutionResult, Executor, Registry},
     graphql, reflect, resolve,
     schema::meta::MetaType,
-    BoxFuture, Selection,
+    BoxFuture, FieldError, IntoFieldError, Selection,
 };
 
 use super::iter;
 
-/*
-impl<T, Info, S> resolve::Type<Info, S> for Vec<T>
+impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Vec<T>
 where
-    T: resolve::Type<Info, S>,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH>,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
-        registry.build_list_type_new::<T, _>(info, None).into_meta()
+        registry.wrap_list::<behavior::Coerce<T, BH>, _>(type_info, None)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for Vec<T>
+impl<T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for Vec<T>
 where
-    T: resolve::Value<Info, Ctx, S>,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        iter::resolve_list(self.iter(), selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        iter::resolve_list(self.iter(), selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for Vec<T>
+impl<T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for Vec<T>
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + Sync,
-    Info: Sync + ?Sized,
-    Ctx: Sync + ?Sized,
-    S: Send + Sync,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + Sync,
+    TI: Sync + ?Sized,
+    CX: Sync + ?Sized,
+    SV: Send + Sync,
+    BH: ?Sized + 'static, // TODO: Lift `'static` bound if possible.
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
         Box::pin(iter::resolve_list_async(
             self.iter(),
             selection_set,
-            info,
+            type_info,
             executor,
         ))
     }
 }
 
-impl<T, S> resolve::ToInputValue<S> for Vec<T>
+impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Vec<T>
 where
-    T: resolve::ToInputValue<S>,
+    T: resolve::ToInputValue<SV, BH>,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         graphql::InputValue::list(self.iter().map(T::to_input_value))
     }
 }
 
+impl<'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Vec<T>
+where
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
+{
+    type Error = TryFromInputValueError<T::Error>;
 
-impl<'i, T, Info, S> graphql::InputType<'i, Info, S> for Vec<T>
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        match v {
+            graphql::InputValue::List(l) => l
+                .iter()
+                .map(|i| T::try_from_input_value(&i.item).map_err(TryFromInputValueError::Item))
+                .collect(),
+            // See "Input Coercion" on List types:
+            // https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
+            graphql::InputValue::Null => Err(TryFromInputValueError::IsNull),
+            other => T::try_from_input_value(other)
+                .map(|e| vec![e])
+                .map_err(TryFromInputValueError::Item),
+        }
+    }
+}
+
+impl<'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Vec<T>
 where
-    T: graphql::InputType<'i, Info, S>,
-    Info: ?Sized,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
 
-
-impl<T, S> graphql::OutputType<S> for Vec<T>
+impl<T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for Vec<T>
 where
-    T: graphql::OutputType<S>,
+    T: graphql::OutputType<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: resolve::ValueAsync<TI, CX, SV, BH>,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<T, S> reflect::BaseType<S> for Vec<T>
+impl<T, BH> reflect::BaseType<BH> for Vec<T>
 where
-    T: reflect::BaseType<S>,
+    T: reflect::BaseType<BH>,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S> reflect::BaseSubTypes<S> for Vec<T>
+impl<T, BH> reflect::BaseSubTypes<BH> for Vec<T>
 where
-    T: reflect::BaseSubTypes<S>,
+    T: reflect::BaseSubTypes<BH>,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S> reflect::WrappedType<S> for Vec<T>
+impl<T, BH> reflect::WrappedType<BH> for Vec<T>
 where
-    T: reflect::WrappedType<S>,
+    T: reflect::WrappedType<BH>,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
 }
-*/
+
+/// Possible errors of converting a [`graphql::InputValue`] into a [`Vec`].
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum TryFromInputValueError<E> {
+    /// [`graphql::InputValue`] cannot be [`Null`].
+    ///
+    /// See ["Combining List and Non-Null" section of spec][0].
+    ///
+    /// [`Null`]: [`InputValue::Null`]
+    /// [0]: https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
+    IsNull,
+
+    /// Error of converting a [`graphql::InputValue::List`]'s item.
+    Item(E),
+}
+
+impl<E, SV> IntoFieldError<SV> for TryFromInputValueError<E>
+where
+    E: IntoFieldError<SV>,
+{
+    fn into_field_error(self) -> FieldError<SV> {
+        match self {
+            Self::IsNull => "Failed to convert into `Vec`: Value cannot be `null`".into(),
+            Self::Item(e) => e.into_field_error(),
+        }
+    }
+}
diff --git a/juniper_codegen/src/common/mod.rs b/juniper_codegen/src/common/mod.rs
index ae2e92575..638042dd5 100644
--- a/juniper_codegen/src/common/mod.rs
+++ b/juniper_codegen/src/common/mod.rs
@@ -1,7 +1,7 @@
 //! Common functions, definitions and extensions for code generation, used by this crate.
 
+pub(crate) mod behavior;
 pub(crate) mod field;
 pub(crate) mod gen;
 pub(crate) mod parse;
 pub(crate) mod scalar;
-pub(crate) mod behavior;

From d648181b26d4734614ac1a22e53321e7708e7fa4 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 21 Jun 2022 14:50:16 +0200
Subject: [PATCH 36/58] Fix `reflect` impls for `Result`

---
 juniper/src/types/result.rs | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/juniper/src/types/result.rs b/juniper/src/types/result.rs
index 51ec79ad1..62d28d108 100644
--- a/juniper/src/types/result.rs
+++ b/juniper/src/types/result.rs
@@ -2,25 +2,26 @@
 
 use crate::reflect;
 
-/*
-impl<T, E, S> reflect::BaseType<S> for Result<T, E>
+impl<T, E, BH> reflect::BaseType<BH> for Result<T, E>
 where
-    T: reflect::BaseType<S>,
+    T: reflect::BaseType<BH>,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, E, S> reflect::BaseSubTypes<S> for Result<T, E>
+impl<T, E, BH> reflect::BaseSubTypes<BH> for Result<T, E>
 where
-    T: reflect::BaseSubTypes<S>,
+    T: reflect::BaseSubTypes<BH>,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, E, S> reflect::WrappedType<S> for Result<T, E>
+impl<T, E, BH> reflect::WrappedType<BH> for Result<T, E>
 where
-    T: reflect::WrappedType<S>,
+    T: reflect::WrappedType<BH>,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = T::VALUE;
 }
-*/

From 17af7c5ac526cd2d6f09b2618d69cc5a4b0a12f8 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 21 Jun 2022 15:25:06 +0200
Subject: [PATCH 37/58] Impl new machinery for array

---
 juniper/src/types/array.rs | 277 ++++++++++++++++++++++++++++++-------
 juniper/src/types/mod.rs   |   2 +-
 2 files changed, 231 insertions(+), 48 deletions(-)

diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
index f730c39da..5e7e48efa 100644
--- a/juniper/src/types/array.rs
+++ b/juniper/src/types/array.rs
@@ -1,118 +1,301 @@
 //! GraphQL implementation for [array].
 //!
-//! [array]: primitive@std::array
+//! [array]: prim@array
+
+use std::{
+    mem::{self, MaybeUninit},
+    ptr,
+};
 
 use crate::{
+    behavior,
     executor::{ExecutionResult, Executor, Registry},
     graphql, reflect, resolve,
     schema::meta::MetaType,
-    BoxFuture, Selection,
+    BoxFuture, FieldError, IntoFieldError, Selection,
 };
 
 use super::iter;
 
-/*
-impl<T, Info, S, const N: usize> resolve::Type<Info, S> for [T; N]
+impl<T, TI, SV, BH, const N: usize> resolve::Type<TI, SV, BH> for [T; N]
 where
-    T: resolve::Type<Info, S>,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH>,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
-        registry
-            .build_list_type_new::<T, _>(info, Some(N))
-            .into_meta()
+        registry.wrap_list::<behavior::Coerce<T, BH>, _>(type_info, None)
     }
 }
 
-impl<T, Info, Ctx, S, const N: usize> resolve::Value<Info, Ctx, S> for [T; N]
+impl<T, TI, CX, SV, BH, const N: usize> resolve::Value<TI, CX, SV, BH> for [T; N]
 where
-    T: resolve::Value<Info, Ctx, S>,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        iter::resolve_list(self.iter(), selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        iter::resolve_list(self.iter(), selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S, const N: usize> resolve::ValueAsync<Info, Ctx, S> for [T; N]
+impl<T, TI, CX, SV, BH, const N: usize> resolve::ValueAsync<TI, CX, SV, BH> for [T; N]
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + Sync,
-    Info: Sync + ?Sized,
-    Ctx: Sync + ?Sized,
-    S: Send + Sync,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + Sync,
+    TI: Sync + ?Sized,
+    CX: Sync + ?Sized,
+    SV: Send + Sync,
+    BH: ?Sized + 'static, // TODO: Lift `'static` bound if possible.
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
         Box::pin(iter::resolve_list_async(
             self.iter(),
             selection_set,
-            info,
+            type_info,
             executor,
         ))
     }
 }
 
-impl<T, S, const N: usize> resolve::ToInputValue<S> for [T; N]
+impl<T, SV, BH, const N: usize> resolve::ToInputValue<SV, BH> for [T; N]
 where
-    T: resolve::ToInputValue<S>,
+    T: resolve::ToInputValue<SV, BH>,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         graphql::InputValue::list(self.iter().map(T::to_input_value))
     }
 }
 
-/*
-impl<'i, T, Info, S, const N: usize> graphql::InputType<'i, Info, S> for [T; N]
+impl<'i, T, SV, BH, const N: usize> resolve::InputValue<'i, SV, BH> for [T; N]
+where
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
+{
+    type Error = TryFromInputValueError<T::Error>;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        struct PartiallyInitializedArray<T, const N: usize> {
+            arr: [MaybeUninit<T>; N],
+            init_len: usize,
+            no_drop: bool,
+        }
+
+        impl<T, const N: usize> Drop for PartiallyInitializedArray<T, N> {
+            fn drop(&mut self) {
+                if self.no_drop {
+                    return;
+                }
+                // Dropping a `MaybeUninit` does nothing, thus we need to drop
+                // the initialized elements manually, otherwise we may introduce
+                // a memory/resource leak if `T: Drop`.
+                for elem in &mut self.arr[0..self.init_len] {
+                    // SAFETY: This is safe, because `self.init_len` represents
+                    //         the number of the initialized elements exactly.
+                    unsafe {
+                        ptr::drop_in_place(elem.as_mut_ptr());
+                    }
+                }
+            }
+        }
+
+        match v {
+            graphql::InputValue::List(ls) => {
+                if ls.len() != N {
+                    return Err(TryFromInputValueError::WrongCount {
+                        actual: ls.len(),
+                        expected: N,
+                    });
+                }
+                if N == 0 {
+                    // TODO: Use `mem::transmute` instead of
+                    //       `mem::transmute_copy` below, once it's allowed
+                    //       for const generics:
+                    //       https://github.com/rust-lang/rust/issues/61956
+                    // SAFETY: `mem::transmute_copy` is safe here, because we
+                    //         check `N` to be `0`. It's no-op, actually.
+                    return Ok(unsafe { mem::transmute_copy::<[T; 0], Self>(&[]) });
+                }
+
+                // SAFETY: The reason we're using a wrapper struct implementing
+                //         `Drop` here is to be panic safe:
+                //         `T: resolve::InputValue` implementation is not
+                //         controlled by us, so calling
+                //         `T::try_from_input_value(&i.item)` below may cause a
+                //         panic when our array is initialized only partially.
+                //         In such situation we need to drop already initialized
+                //         values to avoid possible memory/resource leaks if
+                //         `T: Drop`.
+                let mut out = PartiallyInitializedArray::<T, N> {
+                    // SAFETY: The `.assume_init()` here is safe, because the
+                    //         type we are claiming to have initialized here is
+                    //         a bunch of `MaybeUninit`s, which do not require
+                    //         any initialization.
+                    arr: unsafe { MaybeUninit::uninit().assume_init() },
+                    init_len: 0,
+                    no_drop: false,
+                };
+
+                let mut items = ls.iter().map(|i| T::try_from_input_value(&i.item));
+                for elem in &mut out.arr[..] {
+                    if let Some(i) = items
+                        .next()
+                        .transpose()
+                        .map_err(TryFromInputValueError::Item)?
+                    {
+                        *elem = MaybeUninit::new(i);
+                        out.init_len += 1;
+                    }
+                }
+
+                // Do not drop collected `items`, because we're going to return
+                // them.
+                out.no_drop = true;
+
+                // TODO: Use `mem::transmute` instead of `mem::transmute_copy`
+                //       below, once it's allowed for const generics:
+                //       https://github.com/rust-lang/rust/issues/61956
+                // SAFETY: `mem::transmute_copy` is safe here, because we have
+                //         exactly `N` initialized `items`.
+                //         Also, despite `mem::transmute_copy` copies the value,
+                //         we won't have a double-free when `T: Drop` here,
+                //         because original array elements are `MaybeUninit`, so
+                //         do nothing on `Drop`.
+                Ok(unsafe { mem::transmute_copy::<_, Self>(&out.arr) })
+            }
+            // See "Input Coercion" on List types:
+            // https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
+            graphql::InputValue::Null => Err(TryFromInputValueError::IsNull),
+            other => T::try_from_input_value(other)
+                .map_err(TryFromInputValueError::Item)
+                .and_then(|e: T| {
+                    // TODO: Use `mem::transmute` instead of
+                    //       `mem::transmute_copy` below, once it's allowed
+                    //       for const generics:
+                    //       https://github.com/rust-lang/rust/issues/61956
+                    if N == 1 {
+                        // SAFETY: `mem::transmute_copy` is safe here, because
+                        //         we check `N` to be `1`. Also, despite
+                        //         `mem::transmute_copy` copies the value, we
+                        //         won't have a double-free when `T: Drop` here,
+                        //         because original `e: T` value is wrapped into
+                        //         `mem::ManuallyDrop`, so does nothing on
+                        //         `Drop`.
+                        Ok(unsafe { mem::transmute_copy::<_, Self>(&[mem::ManuallyDrop::new(e)]) })
+                    } else {
+                        Err(TryFromInputValueError::WrongCount {
+                            actual: 1,
+                            expected: N,
+                        })
+                    }
+                }),
+        }
+    }
+}
+
+impl<'i, T, TI, SV, BH, const N: usize> graphql::InputType<'i, TI, SV, BH> for [T; N]
 where
-    T: graphql::InputType<'i, Info, S>,
-    Info: ?Sized,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
-*/
 
-impl<T, S, const N: usize> graphql::OutputType<S> for [T; N]
+impl<T, TI, CX, SV, BH, const N: usize> graphql::OutputType<TI, CX, SV, BH> for [T; N]
 where
-    T: graphql::OutputType<S>,
+    T: graphql::OutputType<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: resolve::ValueAsync<TI, CX, SV, BH>,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<T, S, const N: usize> reflect::BaseType<S> for [T; N]
+impl<T, BH, const N: usize> reflect::BaseType<BH> for [T; N]
 where
-    T: reflect::BaseType<S>,
+    T: reflect::BaseType<BH>,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S, const N: usize> reflect::BaseSubTypes<S> for [T; N]
+impl<T, BH, const N: usize> reflect::BaseSubTypes<BH> for [T; N]
 where
-    T: reflect::BaseSubTypes<S>,
+    T: reflect::BaseSubTypes<BH>,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S, const N: usize> reflect::WrappedType<S> for [T; N]
+impl<T, BH, const N: usize> reflect::WrappedType<BH> for [T; N]
 where
-    T: reflect::WrappedType<S>,
+    T: reflect::WrappedType<BH>,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
 }
-*/
+
+/// Possible errors of converting a [`graphql::InputValue`] into an exact-size
+/// [array](prim@array).
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum TryFromInputValueError<E> {
+    /// [`graphql::InputValue`] cannot be [`Null`].
+    ///
+    /// See ["Combining List and Non-Null" section of spec][0].
+    ///
+    /// [`Null`]: [`InputValue::Null`]
+    /// [0]: https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
+    IsNull,
+
+    /// Wrong count of items.
+    WrongCount {
+        /// Actual count of items.
+        actual: usize,
+
+        /// Expected count of items ([array](prim@array) size).
+        expected: usize,
+    },
+
+    /// Error of converting a [`graphql::InputValue::List`]'s item.
+    Item(E),
+}
+
+impl<E, SV> IntoFieldError<SV> for TryFromInputValueError<E>
+where
+    E: IntoFieldError<SV>,
+{
+    fn into_field_error(self) -> FieldError<SV> {
+        const ERROR_PREFIX: &str = "Failed to convert into exact-size array";
+        match self {
+            Self::IsNull => format!("{}: Value cannot be `null`", ERROR_PREFIX).into(),
+            Self::WrongCount { actual, expected } => format!(
+                "{}: wrong elements count: {} instead of {}",
+                ERROR_PREFIX, actual, expected,
+            )
+            .into(),
+            Self::Item(s) => s.into_field_error(),
+        }
+    }
+}
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 44635ccd1..1fe0dfe24 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -1,5 +1,5 @@
 mod arc;
-mod array;
+pub mod array;
 mod r#box;
 pub mod iter;
 mod nullable;

From 4a6b3abfc69cd35e083822fd8ed7dc0eb3e51f84 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 21 Jun 2022 16:15:21 +0200
Subject: [PATCH 38/58] Impl new machinery for slice [skip ci]

---
 juniper/src/types/slice.rs | 190 +++++++++++++++++++++++++++++--------
 1 file changed, 148 insertions(+), 42 deletions(-)

diff --git a/juniper/src/types/slice.rs b/juniper/src/types/slice.rs
index 0b31c7a99..6eabb1fc9 100644
--- a/juniper/src/types/slice.rs
+++ b/juniper/src/types/slice.rs
@@ -1,114 +1,220 @@
 //! GraphQL implementation for [slice].
 //!
-//! [slice]: primitive@std::slice
+//! [slice]: prim@slice
+
+use std::{rc::Rc, sync::Arc};
 
 use crate::{
+    behavior,
     executor::{ExecutionResult, Executor, Registry},
     graphql, reflect, resolve,
     schema::meta::MetaType,
     BoxFuture, Selection,
 };
 
-use super::iter;
+use super::{iter, vec::TryFromInputValueError};
 
-/*
-impl<T, Info, S> resolve::Type<Info, S> for [T]
+impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for [T]
 where
-    T: resolve::Type<Info, S>,
-    Info: ?Sized,
+    T: resolve::Type<TI, SV, BH>,
+    TI: ?Sized,
+    BH: ?Sized,
 {
-    fn meta<'r>(registry: &mut Registry<'r, S>, info: &Info) -> MetaType<'r, S>
+    fn meta<'r, 'ti: 'r>(registry: &mut Registry<'r, SV>, type_info: &'ti TI) -> MetaType<'r, SV>
     where
-        S: 'r,
+        SV: 'r,
     {
-        registry.build_list_type_new::<T, _>(info, None).into_meta()
+        registry.wrap_list::<behavior::Coerce<T, BH>, _>(type_info, None)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::Value<Info, Ctx, S> for [T]
+impl<T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for [T]
 where
-    T: resolve::Value<Info, Ctx, S>,
-    Info: ?Sized,
-    Ctx: ?Sized,
+    T: resolve::Value<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
 {
     fn resolve_value(
         &self,
-        selection_set: Option<&[Selection<'_, S>]>,
-        info: &Info,
-        executor: &Executor<Ctx, S>,
-    ) -> ExecutionResult<S> {
-        iter::resolve_list(self.iter(), selection_set, info, executor)
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        iter::resolve_list(self.iter(), selection_set, type_info, executor)
     }
 }
 
-impl<T, Info, Ctx, S> resolve::ValueAsync<Info, Ctx, S> for [T]
+impl<T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for [T]
 where
-    T: resolve::ValueAsync<Info, Ctx, S> + Sync,
-    Info: Sync + ?Sized,
-    Ctx: Sync + ?Sized,
-    S: Send + Sync,
+    T: resolve::ValueAsync<TI, CX, SV, BH> + Sync,
+    TI: Sync + ?Sized,
+    CX: Sync + ?Sized,
+    SV: Send + Sync,
+    BH: ?Sized + 'static, // TODO: Lift `'static` bound if possible.
 {
     fn resolve_value_async<'r>(
         &'r self,
-        selection_set: Option<&'r [Selection<'_, S>]>,
-        info: &'r Info,
-        executor: &'r Executor<Ctx, S>,
-    ) -> BoxFuture<'r, ExecutionResult<S>> {
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
         Box::pin(iter::resolve_list_async(
             self.iter(),
             selection_set,
-            info,
+            type_info,
             executor,
         ))
     }
 }
 
-impl<T, S> resolve::ToInputValue<S> for [T]
+impl<T, SV, BH> resolve::ToInputValue<SV, BH> for [T]
 where
-    T: resolve::ToInputValue<S>,
+    T: resolve::ToInputValue<SV, BH>,
+    BH: ?Sized,
 {
-    fn to_input_value(&self) -> graphql::InputValue<S> {
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
         graphql::InputValue::list(self.iter().map(T::to_input_value))
     }
 }
 
-impl<T, S> graphql::InputType<S> for [T]
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Box<Self>, SV, BH> for [T]
+where
+    Vec<T>: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
+{
+    type Error = <Vec<T> as resolve::InputValue<'i, SV, BH>>::Error;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Box<Self>, Self::Error> {
+        <Vec<T> as resolve::InputValue<'i, SV, BH>>::try_from_input_value(v)
+            .map(Vec::into_boxed_slice)
+    }
+}
+
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Rc<Self>, SV, BH> for [T]
+where
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
+{
+    type Error = TryFromInputValueError<T::Error>;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Rc<Self>, Self::Error> {
+        // We don't want to reuse `Vec<T>` implementation in the same way we do
+        // for `Box<[T]>`, because `impl From<Vec<T>> for Rc<[T]>` reallocates.
+        match v {
+            graphql::InputValue::List(l) => l
+                .iter()
+                .map(|i| T::try_from_input_value(&i.item).map_err(TryFromInputValueError::Item))
+                .collect(),
+            // See "Input Coercion" on List types:
+            // https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
+            graphql::InputValue::Null => Err(TryFromInputValueError::IsNull),
+            // TODO: Use `.into_iter()` after upgrade to 2021 Rust edition.
+            other => T::try_from_input_value(other)
+                .map(|e| std::iter::once(e).collect())
+                .map_err(TryFromInputValueError::Item),
+        }
+    }
+}
+
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Arc<Self>, SV, BH> for [T]
+where
+    T: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
+{
+    type Error = TryFromInputValueError<T::Error>;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Arc<Self>, Self::Error> {
+        // We don't want to reuse `Vec<T>` implementation in the same way we do
+        // for `Box<[T]>`, because `impl From<Vec<T>> for Arc<[T]>` reallocates.
+        match v {
+            graphql::InputValue::List(l) => l
+                .iter()
+                .map(|i| T::try_from_input_value(&i.item).map_err(TryFromInputValueError::Item))
+                .collect(),
+            // See "Input Coercion" on List types:
+            // https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
+            graphql::InputValue::Null => Err(TryFromInputValueError::IsNull),
+            // TODO: Use `.into_iter()` after upgrade to 2021 Rust edition.
+            other => T::try_from_input_value(other)
+                .map(|e| std::iter::once(e).collect())
+                .map_err(TryFromInputValueError::Item),
+        }
+    }
+}
+
+impl<'i, T, TI, SV, BH> graphql::InputTypeAs<'i, Box<Self>, TI, SV, BH> for [T]
+where
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<'i, T, TI, SV, BH> graphql::InputTypeAs<'i, Rc<Self>, TI, SV, BH> for [T]
 where
-    T: graphql::InputType<S>,
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
 {
     fn assert_input_type() {
         T::assert_input_type()
     }
 }
 
+impl<'i, T, TI, SV, BH> graphql::InputTypeAs<'i, Arc<Self>, TI, SV, BH> for [T]
+where
+    T: graphql::InputType<'i, TI, SV, BH>,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
 
-impl<T, S> graphql::OutputType<S> for [T]
+impl<T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for [T]
 where
-    T: graphql::OutputType<S>,
+    T: graphql::OutputType<TI, CX, SV, BH>,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: resolve::ValueAsync<TI, CX, SV, BH>,
 {
     fn assert_output_type() {
         T::assert_output_type()
     }
 }
 
-impl<T, S> reflect::BaseType<S> for [T]
+impl<T, BH> reflect::BaseType<BH> for [T]
 where
-    T: reflect::BaseType<S>,
+    T: reflect::BaseType<BH>,
+    BH: ?Sized,
 {
     const NAME: reflect::Type = T::NAME;
 }
 
-impl<T, S> reflect::BaseSubTypes<S> for [T]
+impl<T, BH> reflect::BaseSubTypes<BH> for [T]
 where
-    T: reflect::BaseSubTypes<S>,
+    T: reflect::BaseSubTypes<BH>,
+    BH: ?Sized,
 {
     const NAMES: reflect::Types = T::NAMES;
 }
 
-impl<T, S> reflect::WrappedType<S> for [T]
+impl<T, BH> reflect::WrappedType<BH> for [T]
 where
-    T: reflect::WrappedType<S>,
+    T: reflect::WrappedType<BH>,
+    BH: ?Sized,
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::list(T::VALUE);
 }
-*/

From 3cfc4eb0e4a4d2b905f31f4b78870fb1cc391211 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 21 Jun 2022 17:49:35 +0200
Subject: [PATCH 39/58] Impl new machinery for `Cow` [skip ci]

---
 juniper/src/types/arc.rs   |   2 +-
 juniper/src/types/box.rs   |   2 +-
 juniper/src/types/cow.rs   | 291 +++++++++++++++++++++++++++++++++++++
 juniper/src/types/mod.rs   |   1 +
 juniper/src/types/rc.rs    |   2 +-
 juniper/src/types/ref.rs   |   8 +-
 juniper/src/types/slice.rs |  17 ++-
 juniper/src/types/str.rs   |  37 ++++-
 8 files changed, 351 insertions(+), 9 deletions(-)
 create mode 100644 juniper/src/types/cow.rs

diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index db4c6cba7..c49d9a452 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -178,7 +178,7 @@ where
     }
 }
 
-impl<'i, T, SV, BH> resolve::InputValueAs<'i, Arc<T>, SV, BH> for T
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Arc<Self>, SV, BH> for T
 where
     T: resolve::InputValue<'i, SV, BH>,
     SV: 'i,
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 845343d22..9724d307f 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -176,7 +176,7 @@ where
     }
 }
 
-impl<'i, T, SV, BH> resolve::InputValueAs<'i, Box<T>, SV, BH> for T
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Box<Self>, SV, BH> for T
 where
     T: resolve::InputValue<'i, SV, BH>,
     SV: 'i,
diff --git a/juniper/src/types/cow.rs b/juniper/src/types/cow.rs
new file mode 100644
index 000000000..9626a8703
--- /dev/null
+++ b/juniper/src/types/cow.rs
@@ -0,0 +1,291 @@
+//! GraphQL implementation for [`Cow`].
+
+use std::{borrow::Cow, ops::Deref};
+
+use crate::{
+    graphql,
+    meta::MetaType,
+    parser::{ParseError, ScalarToken},
+    reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection,
+};
+
+impl<'me, T, TI, SV, BH> resolve::Type<TI, SV, BH> for Cow<'me, T>
+where
+    T: resolve::Type<TI, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    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)
+    }
+}
+
+impl<'me, T, TI, BH> resolve::TypeName<TI, BH> for Cow<'me, T>
+where
+    T: resolve::TypeName<TI, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn type_name(type_info: &TI) -> &str {
+        T::type_name(type_info)
+    }
+}
+
+impl<'me, T, TI, BH> resolve::ConcreteTypeName<TI, BH> for Cow<'me, T>
+where
+    T: resolve::ConcreteTypeName<TI, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn concrete_type_name<'i>(&self, type_info: &'i TI) -> &'i str {
+        (**self).concrete_type_name(type_info)
+    }
+}
+
+impl<'me, T, TI, CX, SV, BH> resolve::Value<TI, CX, SV, BH> for Cow<'me, T>
+where
+    T: resolve::Value<TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn resolve_value(
+        &self,
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_value(selection_set, type_info, executor)
+    }
+}
+
+impl<'me, T, TI, CX, SV, BH> resolve::ValueAsync<TI, CX, SV, BH> for Cow<'me, T>
+where
+    T: resolve::ValueAsync<TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn resolve_value_async<'r>(
+        &'r self,
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_value_async(selection_set, type_info, executor)
+    }
+}
+
+impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Cow<'me, T>
+where
+    T: resolve::ConcreteValue<TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn resolve_concrete_value(
+        &self,
+        type_name: &str,
+        selection_set: Option<&[Selection<'_, SV>]>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_concrete_value(type_name, selection_set, type_info, executor)
+    }
+}
+
+impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValueAsync<TI, CX, SV, BH> for Cow<'me, T>
+where
+    T: resolve::ConcreteValueAsync<TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn resolve_concrete_value_async<'r>(
+        &'r self,
+        type_name: &str,
+        selection_set: Option<&'r [Selection<'_, SV>]>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_concrete_value_async(type_name, selection_set, type_info, executor)
+    }
+}
+
+impl<'me, T, TI, CX, SV, BH> resolve::Field<TI, CX, SV, BH> for Cow<'me, T>
+where
+    T: resolve::Field<TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn resolve_field(
+        &self,
+        field_name: &str,
+        arguments: &Arguments<SV>,
+        type_info: &TI,
+        executor: &Executor<CX, SV>,
+    ) -> ExecutionResult<SV> {
+        (**self).resolve_field(field_name, arguments, type_info, executor)
+    }
+}
+
+impl<'me, T, TI, CX, SV, BH> resolve::FieldAsync<TI, CX, SV, BH> for Cow<'me, T>
+where
+    T: resolve::FieldAsync<TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn resolve_field_async<'r>(
+        &'r self,
+        field_name: &'r str,
+        arguments: &'r Arguments<SV>,
+        type_info: &'r TI,
+        executor: &'r Executor<CX, SV>,
+    ) -> BoxFuture<'r, ExecutionResult<SV>> {
+        (**self).resolve_field_async(field_name, arguments, type_info, executor)
+    }
+}
+
+impl<'me, T, SV, BH> resolve::ToInputValue<SV, BH> for Cow<'me, T>
+where
+    T: resolve::ToInputValue<SV, BH> + ToOwned + ?Sized + 'me,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
+        (**self).to_input_value()
+    }
+}
+
+impl<'me, 'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for Cow<'me, T>
+where
+    'i: 'me,
+    T: resolve::InputValueAs<'i, Self, SV, BH> + ToOwned + ?Sized + 'me,
+    SV: 'i,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    type Error = T::Error;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Self, Self::Error> {
+        T::try_from_input_value(v)
+    }
+
+    fn try_from_implicit_null() -> Result<Self, Self::Error> {
+        T::try_from_implicit_null()
+    }
+}
+
+impl<'me, 'i, T, SV, BH> resolve::InputValueAs<'i, Cow<'me, Self>, SV, BH> for T
+where
+    'i: 'me,
+    T: resolve::InputValueAsRef<SV, BH> + ToOwned + 'me,
+    SV: 'i,
+    BH: ?Sized,
+    Cow<'me, Self>: Deref<Target = Self>,
+{
+    type Error = T::Error;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Cow<'me, Self>, Self::Error> {
+        T::try_from_input_value(v).map(Cow::Borrowed)
+    }
+
+    fn try_from_implicit_null() -> Result<Cow<'me, Self>, Self::Error> {
+        T::try_from_implicit_null().map(Cow::Borrowed)
+    }
+}
+
+impl<'me, T, SV, BH> resolve::ScalarToken<SV, BH> for Cow<'me, T>
+where
+    T: resolve::ScalarToken<SV, BH> + ToOwned + ?Sized + 'me,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+        T::parse_scalar_token(token)
+    }
+}
+
+impl<'me, 'i, T, TI, SV, BH> graphql::InputType<'i, TI, SV, BH> for Cow<'me, T>
+where
+    'i: 'me,
+    T: graphql::InputTypeAs<'i, Self, TI, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn assert_input_type() {
+        T::assert_input_type()
+    }
+}
+
+impl<'me, T, TI, CX, SV, BH> graphql::OutputType<TI, CX, SV, BH> for Cow<'me, T>
+where
+    T: graphql::OutputType<TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    fn assert_output_type() {
+        T::assert_output_type()
+    }
+}
+
+impl<'me, 'i, T, TI, CX, SV, BH> graphql::Scalar<'i, TI, CX, SV, BH> for Cow<'me, T>
+where
+    'i: 'me,
+    T: graphql::ScalarAs<'i, Self, TI, CX, SV, BH> + ToOwned + ?Sized + 'me,
+    TI: ?Sized,
+    CX: ?Sized,
+    SV: 'i,
+    BH: ?Sized,
+
+    Self: Deref<Target = T>,
+{
+    fn assert_scalar() {
+        T::assert_scalar()
+    }
+}
+
+impl<'me, T, BH> reflect::BaseType<BH> for Cow<'me, T>
+where
+    T: reflect::BaseType<BH> + ToOwned + ?Sized + 'me,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<'me, T, BH> reflect::BaseSubTypes<BH> for Cow<'me, T>
+where
+    T: reflect::BaseSubTypes<BH> + ToOwned + ?Sized + 'me,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<'me, T, BH> reflect::WrappedType<BH> for Cow<'me, T>
+where
+    T: reflect::WrappedType<BH> + ToOwned + ?Sized + 'me,
+    BH: ?Sized,
+    Self: Deref<Target = T>,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
diff --git a/juniper/src/types/mod.rs b/juniper/src/types/mod.rs
index 1fe0dfe24..fd5e0abbf 100644
--- a/juniper/src/types/mod.rs
+++ b/juniper/src/types/mod.rs
@@ -1,6 +1,7 @@
 mod arc;
 pub mod array;
 mod r#box;
+mod cow;
 pub mod iter;
 mod nullable;
 mod option;
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index f886e910c..8e00993d0 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -178,7 +178,7 @@ where
     }
 }
 
-impl<'i, T, SV, BH> resolve::InputValueAs<'i, Rc<T>, SV, BH> for T
+impl<'i, T, SV, BH> resolve::InputValueAs<'i, Rc<Self>, SV, BH> for T
 where
     T: resolve::InputValue<'i, SV, BH>,
     SV: 'i,
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 867f4f481..805b14720 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -164,7 +164,7 @@ where
 impl<'me, 'i, T, SV, BH> resolve::InputValue<'i, SV, BH> for &'me T
 where
     'i: 'me,
-    T: resolve::InputValueAs<'i, &'me T, SV, BH> + ?Sized,
+    T: resolve::InputValueAs<'i, Self, SV, BH> + ?Sized,
     SV: 'i,
     BH: ?Sized,
 {
@@ -179,7 +179,7 @@ where
     }
 }
 
-impl<'me, 'i, T, SV, BH> resolve::InputValueAs<'i, &'me T, SV, BH> for T
+impl<'me, 'i, T, SV, BH> resolve::InputValueAs<'i, &'me Self, SV, BH> for T
 where
     'i: 'me,
     T: resolve::InputValueAsRef<SV, BH> + ?Sized,
@@ -188,11 +188,11 @@ where
 {
     type Error = T::Error;
 
-    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<&'me T, Self::Error> {
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<&'me Self, Self::Error> {
         T::try_from_input_value(v)
     }
 
-    fn try_from_implicit_null() -> Result<&'me T, Self::Error> {
+    fn try_from_implicit_null() -> Result<&'me Self, Self::Error> {
         T::try_from_implicit_null()
     }
 }
diff --git a/juniper/src/types/slice.rs b/juniper/src/types/slice.rs
index 6eabb1fc9..6a3f0124b 100644
--- a/juniper/src/types/slice.rs
+++ b/juniper/src/types/slice.rs
@@ -2,7 +2,7 @@
 //!
 //! [slice]: prim@slice
 
-use std::{rc::Rc, sync::Arc};
+use std::{borrow::Cow, rc::Rc, sync::Arc};
 
 use crate::{
     behavior,
@@ -78,6 +78,21 @@ where
     }
 }
 
+impl<'me, 'i, T, SV, BH> resolve::InputValueAs<'i, Cow<'me, Self>, SV, BH> for [T]
+where
+    Vec<T>: resolve::InputValue<'i, SV, BH>,
+    SV: 'i,
+    BH: ?Sized,
+    Self: ToOwned,
+{
+    type Error = <Vec<T> as resolve::InputValue<'i, SV, BH>>::Error;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Cow<'me, Self>, Self::Error> {
+        <Vec<T> as resolve::InputValue<'i, SV, BH>>::try_from_input_value(v)
+            .map(|v| Cow::Owned(v.to_owned()))
+    }
+}
+
 impl<'i, T, SV, BH> resolve::InputValueAs<'i, Box<Self>, SV, BH> for [T]
 where
     Vec<T>: resolve::InputValue<'i, SV, BH>,
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index a51299335..5b874073b 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -2,7 +2,7 @@
 //!
 //! [`str`]: primitive@std::str
 
-use std::{rc::Rc, sync::Arc};
+use std::{borrow::Cow, rc::Rc, sync::Arc};
 
 use futures::future;
 
@@ -84,6 +84,19 @@ impl<SV: ScalarValue> resolve::InputValueAsRef<SV> for str {
     }
 }
 
+impl<'me, 'i, SV> resolve::InputValueAs<'i, Cow<'me, Self>, SV> for str
+where
+    'i: 'me,
+    SV: 'i,
+    Self: resolve::InputValueAsRef<SV>,
+{
+    type Error = <Self as resolve::InputValueAsRef<SV>>::Error;
+
+    fn try_from_input_value(v: &'i graphql::InputValue<SV>) -> Result<Cow<'me, Self>, Self::Error> {
+        <Self as resolve::InputValueAsRef<SV>>::try_from_input_value(v).map(Cow::Borrowed)
+    }
+}
+
 impl<'i, SV> resolve::InputValueAs<'i, Box<Self>, SV> for str
 where
     SV: 'i,
@@ -140,6 +153,17 @@ where
     fn assert_input_type() {}
 }
 
+impl<'me, 'i, TI, SV> graphql::InputTypeAs<'i, Cow<'me, Self>, TI, SV> for str
+where
+    Self: graphql::Type<TI, SV>
+        + resolve::ToInputValue<SV>
+        + resolve::InputValueAs<'i, Cow<'me, Self>, SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_input_type() {}
+}
+
 impl<'i, TI, SV> graphql::InputTypeAs<'i, Box<Self>, TI, SV> for str
 where
     Self: graphql::Type<TI, SV>
@@ -192,6 +216,17 @@ where
     fn assert_scalar() {}
 }
 
+impl<'me, 'i, TI, CX, SV> graphql::ScalarAs<'i, Cow<'me, Self>, TI, CX, SV> for str
+where
+    Self: graphql::InputTypeAs<'i, Cow<'me, Self>, TI, SV>
+        + graphql::OutputType<TI, CX, SV>
+        + resolve::ScalarToken<SV>,
+    TI: ?Sized,
+    SV: 'i,
+{
+    fn assert_scalar() {}
+}
+
 impl<'i, TI, CX, SV> graphql::ScalarAs<'i, Box<Self>, TI, CX, SV> for str
 where
     Self: graphql::InputTypeAs<'i, Box<Self>, TI, SV>

From 07ed785a51b21f1513197885469f769f832a1081 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 21 Jun 2022 18:10:33 +0200
Subject: [PATCH 40/58] Move tests for containers [skip ci]

---
 juniper/src/types/array.rs  | 137 ++++++++++++++++++++++++++++++++++++
 juniper/src/types/option.rs |  19 +++++
 juniper/src/types/vec.rs    | 127 +++++++++++++++++++++++++++++++++
 3 files changed, 283 insertions(+)

diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
index 5e7e48efa..3565294eb 100644
--- a/juniper/src/types/array.rs
+++ b/juniper/src/types/array.rs
@@ -299,3 +299,140 @@ where
         }
     }
 }
+
+// See "Input Coercion" examples on List types:
+// https://spec.graphql.org/October2021#sec-List.Input-Coercion
+#[cfg(test)]
+mod coercion {
+    use crate::{graphql, resolve::InputValue as _, IntoFieldError as _};
+
+    use super::TryFromInputValueError;
+
+    type V = graphql::InputValue;
+
+    #[test]
+    fn from_null() {
+        let v: V = graphql::input_value!(null);
+        assert_eq!(
+            <[i32; 0]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(
+            <[i32; 1]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(
+            <[Option<i32>; 0]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(
+            <[Option<i32>; 1]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(<Option<[i32; 0]>>::try_from_input_value(&v), Ok(None));
+        assert_eq!(<Option<[i32; 1]>>::try_from_input_value(&v), Ok(None));
+        assert_eq!(
+            <Option<[Option<i32>; 0]>>::try_from_input_value(&v),
+            Ok(None),
+        );
+        assert_eq!(
+            <Option<[Option<i32>; 1]>>::try_from_input_value(&v),
+            Ok(None),
+        );
+        assert_eq!(
+            <[[i32; 1]; 1]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(
+            <Option<[Option<[Option<i32>; 1]>; 1]>>::try_from_input_value(&v),
+            Ok(None),
+        );
+    }
+
+    #[test]
+    fn from_value() {
+        let v: V = graphql::input_value!(1);
+        assert_eq!(<[i32; 1]>::try_from_input_value(&v), Ok([1]));
+        assert_eq!(
+            <[i32; 0]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::WrongCount {
+                expected: 0,
+                actual: 1,
+            }),
+        );
+        assert_eq!(<[Option<i32>; 1]>::try_from_input_value(&v), Ok([Some(1)]));
+        assert_eq!(<Option<[i32; 1]>>::try_from_input_value(&v), Ok(Some([1])));
+        assert_eq!(
+            <Option<[Option<i32>; 1]>>::try_from_input_value(&v),
+            Ok(Some([Some(1)])),
+        );
+        assert_eq!(<[[i32; 1]; 1]>::try_from_input_value(&v), Ok([[1]]));
+        assert_eq!(
+            <Option<[Option<[Option<i32>; 1]>; 1]>>::try_from_input_value(&v),
+            Ok(Some([Some([Some(1)])])),
+        );
+    }
+
+    #[test]
+    fn from_list() {
+        let v: V = graphql::input_value!([1, 2, 3]);
+        assert_eq!(<[i32; 3]>::try_from_input_value(&v), Ok([1, 2, 3]));
+        assert_eq!(
+            <Option<[i32; 3]>>::try_from_input_value(&v),
+            Ok(Some([1, 2, 3])),
+        );
+        assert_eq!(
+            <[Option<i32>; 3]>::try_from_input_value(&v),
+            Ok([Some(1), Some(2), Some(3)]),
+        );
+        assert_eq!(
+            <Option<[Option<i32>; 3]>>::try_from_input_value(&v),
+            Ok(Some([Some(1), Some(2), Some(3)])),
+        );
+        assert_eq!(
+            <[[i32; 1]; 3]>::try_from_input_value(&v),
+            Ok([[1], [2], [3]]),
+        );
+        // Looks like the spec ambiguity.
+        // See: https://github.com/graphql/graphql-spec/pull/515
+        assert_eq!(
+            <Option<[Option<[Option<i32>; 1]>; 3]>>::try_from_input_value(&v),
+            Ok(Some([Some([Some(1)]), Some([Some(2)]), Some([Some(3)])])),
+        );
+    }
+
+    #[test]
+    fn from_list_with_null() {
+        let v: V = graphql::input_value!([1, 2, null]);
+        assert_eq!(
+            <[i32; 3]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::Item(
+                "Expected `Int`, found: null".into_field_error(),
+            )),
+        );
+        assert_eq!(
+            <Option<[i32; 3]>>::try_from_input_value(&v),
+            Err(TryFromInputValueError::Item(
+                "Expected `Int`, found: null".into_field_error(),
+            )),
+        );
+        assert_eq!(
+            <[Option<i32>; 3]>::try_from_input_value(&v),
+            Ok([Some(1), Some(2), None]),
+        );
+        assert_eq!(
+            <Option<[Option<i32>; 3]>>::try_from_input_value(&v),
+            Ok(Some([Some(1), Some(2), None])),
+        );
+        assert_eq!(
+            <[[i32; 1]; 3]>::try_from_input_value(&v),
+            Err(TryFromInputValueError::Item(TryFromInputValueError::IsNull)),
+        );
+        // Looks like the spec ambiguity.
+        // See: https://github.com/graphql/graphql-spec/pull/515
+        assert_eq!(
+            <Option<[Option<[Option<i32>; 1]>; 3]>>::try_from_input_value(&v),
+            Ok(Some([Some([Some(1)]), Some([Some(2)]), None])),
+        );
+    }
+}
diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs
index cdc919416..3f348de94 100644
--- a/juniper/src/types/option.rs
+++ b/juniper/src/types/option.rs
@@ -143,3 +143,22 @@ where
 {
     const VALUE: reflect::WrappedValue = reflect::wrap::nullable(T::VALUE);
 }
+
+#[cfg(test)]
+mod coercion {
+    use crate::{graphql, resolve::InputValue as _};
+
+    type V = graphql::InputValue;
+
+    #[test]
+    fn from_null() {
+        let v: V = graphql::input_value!(null);
+        assert_eq!(<Option<i32>>::try_from_input_value(&v), Ok(None));
+    }
+
+    #[test]
+    fn from_value() {
+        let v: V = graphql::input_value!(1);
+        assert_eq!(<Option<i32>>::try_from_input_value(&v), Ok(Some(1)));
+    }
+}
diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs
index df2d87a68..0882cd51a 100644
--- a/juniper/src/types/vec.rs
+++ b/juniper/src/types/vec.rs
@@ -173,3 +173,130 @@ where
         }
     }
 }
+
+// See "Input Coercion" examples on List types:
+// https://spec.graphql.org/October2021#sec-List.Input-Coercion
+#[cfg(test)]
+mod coercion {
+    use crate::{graphql, resolve::InputValue as _, IntoFieldError as _};
+
+    use super::TryFromInputValueError;
+
+    type V = graphql::InputValue;
+
+    #[test]
+    fn from_null() {
+        let v: V = graphql::input_value!(null);
+        assert_eq!(
+            <Vec<i32>>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(
+            <Vec<Option<i32>>>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(<Option<Vec<i32>>>::try_from_input_value(&v), Ok(None));
+        assert_eq!(
+            <Option<Vec<Option<i32>>>>::try_from_input_value(&v),
+            Ok(None),
+        );
+        assert_eq!(
+            <Vec<Vec<i32>>>::try_from_input_value(&v),
+            Err(TryFromInputValueError::IsNull),
+        );
+        assert_eq!(
+            <Option<Vec<Option<Vec<Option<i32>>>>>>::try_from_input_value(&v),
+            Ok(None),
+        );
+    }
+
+    #[test]
+    fn from_value() {
+        let v: V = graphql::input_value!(1);
+        assert_eq!(<Vec<i32>>::try_from_input_value(&v), Ok(vec![1]));
+        assert_eq!(
+            <Vec<Option<i32>>>::try_from_input_value(&v),
+            Ok(vec![Some(1)]),
+        );
+        assert_eq!(
+            <Option<Vec<i32>>>::try_from_input_value(&v),
+            Ok(Some(vec![1])),
+        );
+        assert_eq!(
+            <Option<Vec<Option<i32>>>>::try_from_input_value(&v),
+            Ok(Some(vec![Some(1)])),
+        );
+        assert_eq!(<Vec<Vec<i32>>>::try_from_input_value(&v), Ok(vec![vec![1]]));
+        assert_eq!(
+            <Option<Vec<Option<Vec<Option<i32>>>>>>::try_from_input_value(&v),
+            Ok(Some(vec![Some(vec![Some(1)])])),
+        );
+    }
+
+    #[test]
+    fn from_list() {
+        let v: V = graphql::input_value!([1, 2, 3]);
+        assert_eq!(<Vec<i32>>::try_from_input_value(&v), Ok(vec![1, 2, 3]));
+        assert_eq!(
+            <Option<Vec<i32>>>::try_from_input_value(&v),
+            Ok(Some(vec![1, 2, 3])),
+        );
+        assert_eq!(
+            <Vec<Option<i32>>>::try_from_input_value(&v),
+            Ok(vec![Some(1), Some(2), Some(3)]),
+        );
+        assert_eq!(
+            <Option<Vec<Option<i32>>>>::try_from_input_value(&v),
+            Ok(Some(vec![Some(1), Some(2), Some(3)])),
+        );
+        assert_eq!(
+            <Vec<Vec<i32>>>::try_from_input_value(&v),
+            Ok(vec![vec![1], vec![2], vec![3]]),
+        );
+        // Looks like the spec ambiguity.
+        // See: https://github.com/graphql/graphql-spec/pull/515
+        assert_eq!(
+            <Option<Vec<Option<Vec<Option<i32>>>>>>::try_from_input_value(&v),
+            Ok(Some(vec![
+                Some(vec![Some(1)]),
+                Some(vec![Some(2)]),
+                Some(vec![Some(3)]),
+            ])),
+        );
+    }
+
+    #[test]
+    fn from_list_with_null() {
+        let v: V = graphql::input_value!([1, 2, null]);
+        assert_eq!(
+            <Vec<i32>>::try_from_input_value(&v),
+            Err(TryFromInputValueError::Item(
+                "Expected `Int`, found: null".into_field_error(),
+            )),
+        );
+        assert_eq!(
+            <Option<Vec<i32>>>::try_from_input_value(&v),
+            Err(TryFromInputValueError::Item(
+                "Expected `Int`, found: null".into_field_error(),
+            )),
+        );
+        assert_eq!(
+            <Vec<Option<i32>>>::try_from_input_value(&v),
+            Ok(vec![Some(1), Some(2), None]),
+        );
+        assert_eq!(
+            <Option<Vec<Option<i32>>>>::try_from_input_value(&v),
+            Ok(Some(vec![Some(1), Some(2), None])),
+        );
+        assert_eq!(
+            <Vec<Vec<i32>>>::try_from_input_value(&v),
+            Err(TryFromInputValueError::Item(TryFromInputValueError::IsNull)),
+        );
+        // Looks like the spec ambiguity.
+        // See: https://github.com/graphql/graphql-spec/pull/515
+        assert_eq!(
+            <Option<Vec<Option<Vec<Option<i32>>>>>>::try_from_input_value(&v),
+            Ok(Some(vec![Some(vec![Some(1)]), Some(vec![Some(2)]), None])),
+        );
+    }
+}

From 42e278014272beb0b9a57a559cdf5f1a6ec840e0 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 23 Jun 2022 16:41:16 +0200
Subject: [PATCH 41/58] Fix tests

---
 juniper/src/executor_tests/interfaces_unions.rs | 4 ++--
 juniper/src/tests/introspection_tests.rs        | 2 +-
 juniper/src/tests/schema_introspection.rs       | 6 +++---
 juniper_codegen/src/util/mod.rs                 | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/juniper/src/executor_tests/interfaces_unions.rs b/juniper/src/executor_tests/interfaces_unions.rs
index 1044baafd..c25512154 100644
--- a/juniper/src/executor_tests/interfaces_unions.rs
+++ b/juniper/src/executor_tests/interfaces_unions.rs
@@ -1,6 +1,6 @@
 mod interface {
     use crate::{
-        graphql_interface, graphql_object,
+        graphql_interface, graphql_object, graphql_value,
         schema::model::RootNode,
         types::scalars::{EmptyMutation, EmptySubscription},
         GraphQLObject,
@@ -96,7 +96,7 @@ mod interface {
 
 mod union {
     use crate::{
-        graphql_object, graphql_union,
+        graphql_object, graphql_union, graphql_value,
         schema::model::RootNode,
         types::scalars::{EmptyMutation, EmptySubscription},
     };
diff --git a/juniper/src/tests/introspection_tests.rs b/juniper/src/tests/introspection_tests.rs
index f4f064914..a887907ce 100644
--- a/juniper/src/tests/introspection_tests.rs
+++ b/juniper/src/tests/introspection_tests.rs
@@ -1,7 +1,7 @@
 use std::collections::HashSet;
 
 use crate::{
-    graphql_vars,
+    graphql_value, graphql_vars,
     introspection::IntrospectionFormat,
     schema::model::RootNode,
     tests::fixtures::starwars::schema::{Database, Query},
diff --git a/juniper/src/tests/schema_introspection.rs b/juniper/src/tests/schema_introspection.rs
index 1e1b03e0a..291c85f16 100644
--- a/juniper/src/tests/schema_introspection.rs
+++ b/juniper/src/tests/schema_introspection.rs
@@ -1,4 +1,4 @@
-use crate::value::Value;
+use crate::graphql::{self, Value};
 
 // Sort a nested schema Value.
 // In particular, lists are sorted by the "name" key of children, if present.
@@ -34,7 +34,7 @@ pub(super) fn sort_schema_value(value: &mut Value) {
 }
 
 pub(crate) fn schema_introspection_result() -> Value {
-    let mut v = graphql_value!({
+    let mut v = graphql::value!({
         "__schema": {
           "description": null,
           "queryType": {
@@ -1451,7 +1451,7 @@ pub(crate) fn schema_introspection_result() -> Value {
 }
 
 pub(crate) fn schema_introspection_result_without_descriptions() -> Value {
-    let mut v = graphql_value!({
+    let mut v = graphql::value!({
         "__schema": {
           "queryType": {
             "name": "Query"
diff --git a/juniper_codegen/src/util/mod.rs b/juniper_codegen/src/util/mod.rs
index 510c3aeb2..d83cc000f 100644
--- a/juniper_codegen/src/util/mod.rs
+++ b/juniper_codegen/src/util/mod.rs
@@ -1144,9 +1144,9 @@ impl GraphQLTypeDefiniton {
                 #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
-                    ::juniper::InputValue::object(vec![
+                    ::juniper::InputValue::object([
                         #( #to_inputs )*
-                    ].into_iter().collect())
+                    ])
                 }
             }
 

From 23e01956b348cf2820c1366dcda330fb98412ec2 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 23 Jun 2022 17:42:55 +0200
Subject: [PATCH 42/58] Impl `reflect` traits for objects and interfaces [skip
 ci]

---
 juniper/src/behavior.rs                       |  38 ++++++-
 juniper_codegen/src/graphql_interface/attr.rs |   2 +
 .../src/graphql_interface/derive.rs           |   1 +
 juniper_codegen/src/graphql_interface/mod.rs  |  97 ++++++++++++++++-
 juniper_codegen/src/graphql_object/attr.rs    |   1 +
 juniper_codegen/src/graphql_object/derive.rs  |   1 +
 juniper_codegen/src/graphql_object/mod.rs     | 100 +++++++++++++++++-
 juniper_codegen/src/graphql_scalar/mod.rs     |   8 +-
 8 files changed, 241 insertions(+), 7 deletions(-)

diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
index c98c959f3..506cc3841 100644
--- a/juniper/src/behavior.rs
+++ b/juniper/src/behavior.rs
@@ -6,7 +6,7 @@ use crate::{
     graphql,
     meta::MetaType,
     parser::{ParseError, ScalarToken},
-    resolve, Registry,
+    reflect, resolve, Registry,
 };
 
 /// Default standard behavior of GraphQL types implementation.
@@ -92,3 +92,39 @@ where
         T::parse_scalar_token(token)
     }
 }
+
+impl<T, B1, B2> reflect::BaseType<B1> for Coerce<T, B2>
+where
+    T: reflect::BaseType<B2> + ?Sized,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    const NAME: reflect::Type = T::NAME;
+}
+
+impl<T, B1, B2> reflect::BaseSubTypes<B1> for Coerce<T, B2>
+where
+    T: reflect::BaseSubTypes<B2> + ?Sized,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
+
+impl<T, B1, B2> reflect::WrappedType<B1> for Coerce<T, B2>
+where
+    T: reflect::WrappedType<B2> + ?Sized,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    const VALUE: reflect::WrappedValue = T::VALUE;
+}
+
+impl<T, B1, B2> reflect::Implements<B1> for Coerce<T, B2>
+where
+    T: reflect::Implements<B2> + ?Sized,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    const NAMES: reflect::Types = T::NAMES;
+}
diff --git a/juniper_codegen/src/graphql_interface/attr.rs b/juniper_codegen/src/graphql_interface/attr.rs
index 746b7af76..ba7a456d1 100644
--- a/juniper_codegen/src/graphql_interface/attr.rs
+++ b/juniper_codegen/src/graphql_interface/attr.rs
@@ -123,6 +123,7 @@ fn expand_on_trait(
         description: attr.description.as_deref().cloned(),
         context,
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         fields,
         implemented_for: attr
             .implemented_for
@@ -304,6 +305,7 @@ fn expand_on_derive_input(
         description: attr.description.as_deref().cloned(),
         context,
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         fields,
         implemented_for: attr
             .implemented_for
diff --git a/juniper_codegen/src/graphql_interface/derive.rs b/juniper_codegen/src/graphql_interface/derive.rs
index e113bdced..bf60e5cff 100644
--- a/juniper_codegen/src/graphql_interface/derive.rs
+++ b/juniper_codegen/src/graphql_interface/derive.rs
@@ -96,6 +96,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         description: attr.description.as_deref().cloned(),
         context,
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         fields,
         implemented_for: attr
             .implemented_for
diff --git a/juniper_codegen/src/graphql_interface/mod.rs b/juniper_codegen/src/graphql_interface/mod.rs
index 2114e2cf5..fae351574 100644
--- a/juniper_codegen/src/graphql_interface/mod.rs
+++ b/juniper_codegen/src/graphql_interface/mod.rs
@@ -21,7 +21,7 @@ use syn::{
 
 use crate::{
     common::{
-        field, gen,
+        behavior, field, gen,
         parse::{
             attr::{err, OptionExt as _},
             GenericsExt as _, ParseBufferExt as _,
@@ -111,6 +111,17 @@ struct Attr {
     /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
     scalar: Option<SpanContainer<scalar::AttrValue>>,
 
+    /// Explicitly specified type of the custom [`Behavior`] to parametrize this
+    /// [GraphQL interface][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-Interfaces
+    behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified marker indicating that the Rust trait should be
     /// transformed into [`async_trait`].
     ///
@@ -173,6 +184,13 @@ impl Parse for Attr {
                         .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "for" | "implementers" => {
                     input.parse::<token::Eq>()?;
                     for impler in input.parse_maybe_wrapped_and_punctuated::<
@@ -231,6 +249,7 @@ impl Attr {
             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),
             implemented_for: try_merge_hashset!(implemented_for: self, another => span_joined),
             r#enum: try_merge_opt!(r#enum: self, another),
             asyncness: try_merge_opt!(asyncness: self, another),
@@ -309,6 +328,13 @@ struct Definition {
     /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
     scalar: scalar::Type,
 
+    /// [`Behavior`] parametrization to generate code with for this
+    /// [GraphQL interface][0].
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
+    behavior: behavior::Type,
+
     /// Defined [GraphQL fields][2] of this [GraphQL interface][1].
     ///
     /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
@@ -347,6 +373,8 @@ impl ToTokens for Definition {
         self.impl_field_meta_tokens().to_tokens(into);
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
+        ////////////////////////////////////////////////////////////////////////
+        self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -847,6 +875,59 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`reflect::BaseType`],
+    /// [`reflect::BaseSubTypes`], [`reflect::WrappedType`] and
+    /// [`reflect::Fields`] traits for this [GraphQL interface][0].
+    ///
+    /// [`reflect::BaseSubTypes`]: juniper::reflect::BaseSubTypes
+    /// [`reflect::BaseType`]: juniper::reflect::BaseType
+    /// [`reflect::Fields`]: juniper::reflect::Fields
+    /// [`reflect::WrappedType`]: juniper::reflect::WrappedType
+    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
+    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;
+        let implers = &self.implemented_for;
+        let fields = self.fields.iter().map(|f| &f.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 = &[
+                    <Self as ::juniper::reflect::BaseType<#bh>>::NAME,
+                    #( <#implers as ::juniper::reflect::BaseType<#bh>>::NAME ),*
+                ];
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
+                #where_clause
+            {
+                const VALUE: ::juniper::reflect::WrappedValue =
+                    ::juniper::reflect::wrap::SINGULAR;
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::reflect::Fields<#bh> for #ty
+                #where_clause
+            {
+                const NAMES: ::juniper::reflect::Names = &[#( #fields ),*];
+            }
+        }
+    }
+
     /// Returns generated code implementing [`FieldMeta`] for each field of this
     /// [GraphQL interface][1].
     ///
@@ -1267,6 +1348,20 @@ impl Definition {
         generics
     }
 
+    /// Returns prepared self [`syn::Type`] and [`syn::Generics`] for a trait
+    /// implementation.
+    fn ty_and_generics(&self) -> (syn::Type, syn::Generics) {
+        let generics = self.generics.clone();
+
+        let ty = {
+            let ident = &self.enum_alias_ident;
+            let (_, ty_gen, _) = generics.split_for_impl();
+            parse_quote! { #ident#ty_gen }
+        };
+
+        (ty, generics)
+    }
+
     /// Indicates whether this enum has non-exhaustive phantom variant to hold
     /// type parameters.
     #[must_use]
diff --git a/juniper_codegen/src/graphql_object/attr.rs b/juniper_codegen/src/graphql_object/attr.rs
index 34a70c211..5461bf848 100644
--- a/juniper_codegen/src/graphql_object/attr.rs
+++ b/juniper_codegen/src/graphql_object/attr.rs
@@ -121,6 +121,7 @@ where
         description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         fields,
         interfaces: attr
             .interfaces
diff --git a/juniper_codegen/src/graphql_object/derive.rs b/juniper_codegen/src/graphql_object/derive.rs
index 7cbe961b8..e20f533cb 100644
--- a/juniper_codegen/src/graphql_object/derive.rs
+++ b/juniper_codegen/src/graphql_object/derive.rs
@@ -98,6 +98,7 @@ fn expand_struct(ast: syn::DeriveInput) -> syn::Result<Definition<Query>> {
             .map(SpanContainer::into_inner)
             .unwrap_or_else(|| parse_quote! { () }),
         scalar,
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         fields,
         interfaces: attr
             .interfaces
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index 0f3b05acb..c51cab094 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -18,7 +18,7 @@ use syn::{
 
 use crate::{
     common::{
-        field, gen,
+        behavior, field, gen,
         parse::{
             attr::{err, OptionExt as _},
             GenericsExt as _, ParseBufferExt as _, TypeExt,
@@ -73,6 +73,17 @@ pub(crate) struct Attr {
     /// [1]: https://spec.graphql.org/June2018/#sec-Objects
     pub(crate) scalar: Option<SpanContainer<scalar::AttrValue>>,
 
+    /// Explicitly specified type of the custom [`Behavior`] to parametrize this
+    /// [GraphQL object][0] type 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-Objects
+    pub(crate) behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified [GraphQL interfaces][2] this [GraphQL object][1]
     /// type implements.
     ///
@@ -135,6 +146,13 @@ impl Parse for Attr {
                         .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "impl" | "implements" | "interfaces" => {
                     input.parse::<token::Eq>()?;
                     for iface in input.parse_maybe_wrapped_and_punctuated::<
@@ -180,6 +198,7 @@ impl Attr {
             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),
             interfaces: try_merge_hashset!(interfaces: self, another => span_joined),
             rename_fields: try_merge_opt!(rename_fields: self, another),
             is_internal: self.is_internal || another.is_internal,
@@ -245,6 +264,13 @@ pub(crate) struct Definition<Operation: ?Sized> {
     /// [1]: https://spec.graphql.org/June2018/#sec-Objects
     pub(crate) scalar: scalar::Type,
 
+    /// [`Behavior`] parametrization to generate code with for this
+    /// [GraphQL object][0].
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Objects
+    pub(crate) behavior: behavior::Type,
+
     /// Defined [GraphQL fields][2] of this [GraphQL object][1].
     ///
     /// [1]: https://spec.graphql.org/June2018/#sec-Objects
@@ -329,6 +355,13 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
         (quote! { #impl_generics }, where_clause.cloned())
     }
 
+    /// Returns prepared self [`syn::Type`] and [`syn::Generics`] for a trait
+    /// implementation.
+    #[must_use]
+    fn ty_and_generics(&self) -> (&syn::Type, syn::Generics) {
+        (&self.ty, self.generics.clone())
+    }
+
     /// Returns generated code implementing [`marker::IsOutputType`] trait for
     /// this [GraphQL object][1].
     ///
@@ -423,6 +456,69 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
         }
     }
 
+    /// Returns generated code implementing [`reflect::BaseType`],
+    /// [`reflect::BaseSubTypes`], [`reflect::Implements`],
+    /// [`reflect::WrappedType`] and [`reflect::Fields`] traits for this
+    /// [GraphQL object][0].
+    ///
+    /// [`reflect::BaseSubTypes`]: juniper::reflect::BaseSubTypes
+    /// [`reflect::BaseType`]: juniper::reflect::BaseType
+    /// [`reflect::Fields`]: juniper::reflect::Fields
+    /// [`reflect::Implements`]: juniper::reflect::Implements
+    /// [`reflect::WrappedType`]: juniper::reflect::WrappedType
+    /// [0]: https://spec.graphql.org/October2021#sec-Objects
+    #[must_use]
+    pub(crate) 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;
+        let interfaces = self.interfaces.iter();
+        let fields = self.fields.iter().map(|f| &f.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 =
+                    &[<Self as ::juniper::reflect::BaseType<#bh>>::NAME];
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::reflect::Implements<#bh> for #ty
+                #where_clause
+            {
+                const NAMES: ::juniper::reflect::Types = &[#(
+                    <#interfaces as ::juniper::reflect::BaseType<#bh>>::NAME
+                ),*];
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
+                #where_clause
+            {
+                const VALUE: ::juniper::reflect::WrappedValue =
+                    ::juniper::reflect::wrap::SINGULAR;
+            }
+
+            #[automatically_derived]
+            impl#impl_gens ::juniper::reflect::Fields<#bh> for #ty
+                #where_clause
+            {
+                const NAMES: ::juniper::reflect::Names = &[#( #fields ),*];
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLType`] trait for this
     /// [GraphQL object][1].
     ///
@@ -504,6 +600,8 @@ impl ToTokens for Definition<Query> {
         self.impl_field_meta_tokens().to_tokens(into);
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
+        ////////////////////////////////////////////////////////////////////////
+        self.impl_reflect().to_tokens(into);
     }
 }
 
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 876ec9fa0..643707968 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -971,9 +971,9 @@ impl Definition {
     /// [`reflect::BaseSubTypes`] and [`reflect::WrappedType`] traits for this
     /// [GraphQL scalar][0].
     ///
-    /// [`reflect::BaseSubTypes`]: juniper::reflection::BaseSubTypes
-    /// [`reflect::BaseType`]: juniper::reflection::BaseType
-    /// [`reflect::WrappedType`]: juniper::reflection::WrappedType
+    /// [`reflect::BaseSubTypes`]: juniper::reflect::BaseSubTypes
+    /// [`reflect::BaseType`]: juniper::reflect::BaseType
+    /// [`reflect::WrappedType`]: juniper::reflect::WrappedType
     /// [0]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_reflect(&self) -> TokenStream {
         let bh = &self.behavior;
@@ -1087,7 +1087,7 @@ impl Definition {
 
         let ty = {
             let ident = &self.ident;
-            let (_, ty_gen, _) = self.generics.split_for_impl();
+            let (_, ty_gen, _) = generics.split_for_impl();
             parse_quote! { #ident#ty_gen }
         };
 

From 1819ab6e12f4b686be61a5b81587278a8c4f5721 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 23 Jun 2022 18:37:14 +0200
Subject: [PATCH 43/58] Impl `reflect` traits for objects and interfaces
 fields, vol.1 [skip ci]

---
 juniper_codegen/src/common/field/arg.rs       | 31 +++++++++
 juniper_codegen/src/common/field/mod.rs       | 30 +++++++++
 juniper_codegen/src/graphql_interface/attr.rs |  2 +
 .../src/graphql_interface/derive.rs           |  1 +
 juniper_codegen/src/graphql_object/attr.rs    |  1 +
 juniper_codegen/src/graphql_object/derive.rs  |  1 +
 juniper_codegen/src/graphql_object/mod.rs     | 66 +++++++++++++++++++
 7 files changed, 132 insertions(+)

diff --git a/juniper_codegen/src/common/field/arg.rs b/juniper_codegen/src/common/field/arg.rs
index 9eeb72cf6..a65b5e701 100644
--- a/juniper_codegen/src/common/field/arg.rs
+++ b/juniper_codegen/src/common/field/arg.rs
@@ -16,6 +16,7 @@ use syn::{
 
 use crate::{
     common::{
+        behavior,
         parse::{
             attr::{err, OptionExt as _},
             ParseBufferExt as _, TypeExt as _,
@@ -58,6 +59,19 @@ pub(crate) struct Attr {
     /// [2]: https://spec.graphql.org/June2018/#sec-Required-Arguments
     pub(crate) default: Option<SpanContainer<Option<syn::Expr>>>,
 
+    /// Explicitly specified type of the custom [`Behavior`] this
+    /// [GraphQL argument][0] implementation is parametrized with, to [coerce]
+    /// in the generated code from.
+    ///
+    /// 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-Language.Arguments
+    /// [coerce]: juniper::behavior::Coerce
+    pub(crate) behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified marker indicating that this method argument doesn't
     /// represent a [GraphQL argument][1], but is a [`Context`] being injected
     /// into a [GraphQL field][2] resolving function.
@@ -121,6 +135,13 @@ impl Parse for Attr {
                         ))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "ctx" | "context" | "Context" => {
                     let span = ident.span();
                     out.context
@@ -151,6 +172,7 @@ impl Attr {
             name: try_merge_opt!(name: self, another),
             description: try_merge_opt!(description: self, another),
             default: try_merge_opt!(default: self, another),
+            behavior: try_merge_opt!(behavior: self, another),
             context: try_merge_opt!(context: self, another),
             executor: try_merge_opt!(executor: self, another),
         })
@@ -253,6 +275,14 @@ pub(crate) struct OnField {
     /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
     /// [2]: https://spec.graphql.org/June2018/#sec-Required-Arguments
     pub(crate) default: Option<Option<syn::Expr>>,
+
+    /// [`Behavior`] parametrization of this [GraphQL argument][0]
+    /// implementation to [coerce] from in the generated code.
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [coerce]: juniper::behavior::Coerce
+    pub(crate) behavior: behavior::Type,
 }
 
 /// Possible kinds of Rust method arguments for code generation.
@@ -464,6 +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(),
         })))
     }
 }
diff --git a/juniper_codegen/src/common/field/mod.rs b/juniper_codegen/src/common/field/mod.rs
index 2efe969f6..3ea86e406 100644
--- a/juniper_codegen/src/common/field/mod.rs
+++ b/juniper_codegen/src/common/field/mod.rs
@@ -16,6 +16,7 @@ use syn::{
 
 use crate::{
     common::{
+        behavior,
         parse::{
             attr::{err, OptionExt as _},
             ParseBufferExt as _,
@@ -58,6 +59,19 @@ pub(crate) struct Attr {
     /// [2]: https://spec.graphql.org/June2018/#sec-Deprecation
     pub(crate) deprecated: Option<SpanContainer<Option<syn::LitStr>>>,
 
+    /// Explicitly specified type of the custom [`Behavior`] this
+    /// [GraphQL field][0] implementation is parametrized with, to [coerce] in
+    /// the generated code from.
+    ///
+    /// 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-Language.Fields
+    /// [coerce]: juniper::behavior::Coerce
+    pub(crate) behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified marker indicating that this method (or struct
     /// field) should be omitted by code generation and not considered as the
     /// [GraphQL field][1] definition.
@@ -100,6 +114,13 @@ impl Parse for Attr {
                         ))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "ignore" | "skip" => out
                     .ignore
                     .replace(SpanContainer::new(ident.span(), None, ident.clone()))
@@ -122,6 +143,7 @@ impl Attr {
             name: try_merge_opt!(name: self, another),
             description: try_merge_opt!(description: self, another),
             deprecated: try_merge_opt!(deprecated: self, another),
+            behavior: try_merge_opt!(behavior: self, another),
             ignore: try_merge_opt!(ignore: self, another),
         })
     }
@@ -199,6 +221,14 @@ pub(crate) struct Definition {
     /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
     pub(crate) ident: syn::Ident,
 
+    /// [`Behavior`] parametrization of this [GraphQL field][0] implementation
+    /// to [coerce] from in the generated code.
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [coerce]: juniper::behavior::Coerce
+    pub(crate) behavior: behavior::Type,
+
     /// Rust [`MethodArgument`]s required to call the method representing this
     /// [GraphQL field][1].
     ///
diff --git a/juniper_codegen/src/graphql_interface/attr.rs b/juniper_codegen/src/graphql_interface/attr.rs
index ba7a456d1..505e02db6 100644
--- a/juniper_codegen/src/graphql_interface/attr.rs
+++ b/juniper_codegen/src/graphql_interface/attr.rs
@@ -212,6 +212,7 @@ fn parse_trait_method(
         description,
         deprecated,
         ident: method_ident.clone(),
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         arguments: Some(arguments),
         has_receiver: method.sig.receiver().is_some(),
         is_async: method.sig.asyncness.is_some(),
@@ -375,6 +376,7 @@ fn parse_struct_field(field: &mut syn::Field, renaming: &RenameRule) -> Option<f
         description,
         deprecated,
         ident: field_ident.clone(),
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         arguments: None,
         has_receiver: false,
         is_async: false,
diff --git a/juniper_codegen/src/graphql_interface/derive.rs b/juniper_codegen/src/graphql_interface/derive.rs
index bf60e5cff..5cc51e7dc 100644
--- a/juniper_codegen/src/graphql_interface/derive.rs
+++ b/juniper_codegen/src/graphql_interface/derive.rs
@@ -154,6 +154,7 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Defin
         description,
         deprecated,
         ident: field_ident.clone(),
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         arguments: None,
         has_receiver: false,
         is_async: false,
diff --git a/juniper_codegen/src/graphql_object/attr.rs b/juniper_codegen/src/graphql_object/attr.rs
index 5461bf848..054148ba8 100644
--- a/juniper_codegen/src/graphql_object/attr.rs
+++ b/juniper_codegen/src/graphql_object/attr.rs
@@ -229,6 +229,7 @@ fn parse_field(
         description,
         deprecated,
         ident: method_ident.clone(),
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         arguments: Some(arguments),
         has_receiver: method.sig.receiver().is_some(),
         is_async: method.sig.asyncness.is_some(),
diff --git a/juniper_codegen/src/graphql_object/derive.rs b/juniper_codegen/src/graphql_object/derive.rs
index e20f533cb..76fa57d1f 100644
--- a/juniper_codegen/src/graphql_object/derive.rs
+++ b/juniper_codegen/src/graphql_object/derive.rs
@@ -154,6 +154,7 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Defin
         description,
         deprecated,
         ident: field_ident.clone(),
+        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
         arguments: None,
         has_receiver: false,
         is_async: false,
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index c51cab094..10925b238 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -519,6 +519,70 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
         }
     }
 
+    /// Returns generated code implementing [`reflect::Field`] trait for each
+    /// [field][1] of this [GraphQL object][0].
+    ///
+    /// [`reflect::Field`]: juniper::reflect::Field
+    /// [0]: https://spec.graphql.org/October2021#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    #[must_use]
+    pub(crate) fn impl_reflect_field(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        self.fields
+            .iter()
+            .map(|field| {
+                let (f_name, f_ty, f_bh) = (&field.name, &field.ty, &field.behavior);
+
+                let arguments = field
+                    .arguments
+                    .as_ref()
+                    .iter()
+                    .flat_map(|vec| vec.iter().filter_map(field::MethodArgument::as_regular))
+                    .map(|arg| {
+                        let (a_name, a_ty, a_bh) = (&arg.name, &arg.ty, &arg.behavior);
+
+                        quote! {(
+                            #a_name,
+                            <#a_ty as ::juniper::reflect::BaseType<#a_bh>>
+                                ::NAME,
+                            <#a_ty as ::juniper::reflect::WrappedType<#a_bh>>
+                                ::VALUE,
+                        )}
+                    })
+                    .collect::<Vec<_>>();
+
+                quote! {
+                    #[allow(deprecated, non_snake_case)]
+                    #[automatically_derived]
+                    impl#impl_gens ::juniper::reflect::Field<
+                        { ::juniper::reflect::fnv1a128(#f_name) }, #bh,
+                    > for #ty #where_clause {
+                        const TYPE: ::juniper::reflect::Type =
+                            <#f_ty as ::juniper::reflect::BaseType<#f_bh>>
+                                ::NAME;
+
+                        const SUB_TYPES: ::juniper::reflect::Types =
+                            <#f_ty as ::juniper::reflect::BaseSubTypes<#f_bh>>
+                                ::NAMES;
+
+                        const WRAPPED_VALUE: juniper::reflect::WrappedValue =
+                            <#f_ty as ::juniper::reflect::WrappedType<#f_bh>>
+                                ::VALUE;
+
+                        const ARGUMENTS: &'static [(
+                            ::juniper::reflect::Name,
+                            ::juniper::reflect::Type,
+                            ::juniper::reflect::WrappedValue,
+                        )] = &[#( #arguments ),*];
+                    }
+                }
+            })
+            .collect()
+    }
+
     /// Returns generated code implementing [`GraphQLType`] trait for this
     /// [GraphQL object][1].
     ///
@@ -602,6 +666,8 @@ impl ToTokens for Definition<Query> {
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
         self.impl_reflect().to_tokens(into);
+        self.impl_reflect_field().to_tokens(into);
+        //self.impl_resolve_field_static().to_tokens(into);
     }
 }
 

From 505e25cea2e43e642d56fdd2b31606a6ff0317a5 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 27 Jun 2022 14:53:49 +0200
Subject: [PATCH 44/58] Temporary disable new reflection for fields as it
 requires all leaf types implement

---
 juniper_codegen/src/graphql_object/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index 10925b238..ba4d72ad6 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -666,7 +666,7 @@ impl ToTokens for Definition<Query> {
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
         self.impl_reflect().to_tokens(into);
-        self.impl_reflect_field().to_tokens(into);
+        //self.impl_reflect_field().to_tokens(into);
         //self.impl_resolve_field_static().to_tokens(into);
     }
 }

From 48631e9b25d089a422f1bb7d2595ac14aa837464 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 27 Jun 2022 15:14:05 +0200
Subject: [PATCH 45/58] 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 d20d7c167..5976c9d07 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<Option<SpanContainer<Self>>> for Type {
+    fn from(attr: Option<SpanContainer<Self>>) -> 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 a65b5e701..3bd1f9f37 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 7600226e8..c386827b5 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<TokenStream> {
         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 8556d8b6e..bebe05c2e 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<SpanContainer<scalar::AttrValue>>,
 
+    /// 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<SpanContainer<behavior::Type>>,
+
     /// 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::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "rename_all" => {
                     input.parse::<token::Eq>()?;
                     let val = input.parse::<syn::LitStr>()?;
@@ -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 =
+                    &[<Self as ::juniper::reflect::BaseType<#bh>>::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 dc4a52ff3..6d5464119 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<f
         description,
         deprecated,
         ident: field_ident.clone(),
-        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
+        behavior: attr.behavior.into(),
         arguments: None,
         has_receiver: false,
         is_async: false,
diff --git a/juniper_codegen/src/graphql_interface/derive.rs b/juniper_codegen/src/graphql_interface/derive.rs
index 135b7c334..542624082 100644
--- a/juniper_codegen/src/graphql_interface/derive.rs
+++ b/juniper_codegen/src/graphql_interface/derive.rs
@@ -97,7 +97,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         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<field::Defin
         description,
         deprecated,
         ident: field_ident.clone(),
-        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
+        behavior: attr.behavior.into(),
         arguments: None,
         has_receiver: false,
         is_async: false,
diff --git a/juniper_codegen/src/graphql_object/attr.rs b/juniper_codegen/src/graphql_object/attr.rs
index 054148ba8..c9854400a 100644
--- a/juniper_codegen/src/graphql_object/attr.rs
+++ b/juniper_codegen/src/graphql_object/attr.rs
@@ -121,7 +121,7 @@ where
         description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar,
-        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
+        behavior: attr.behavior.into(),
         fields,
         interfaces: attr
             .interfaces
@@ -229,7 +229,7 @@ fn parse_field(
         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(),
diff --git a/juniper_codegen/src/graphql_object/derive.rs b/juniper_codegen/src/graphql_object/derive.rs
index 76fa57d1f..283133d1e 100644
--- a/juniper_codegen/src/graphql_object/derive.rs
+++ b/juniper_codegen/src/graphql_object/derive.rs
@@ -98,7 +98,7 @@ fn expand_struct(ast: syn::DeriveInput) -> syn::Result<Definition<Query>> {
             .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<field::Defin
         description,
         deprecated,
         ident: field_ident.clone(),
-        behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
+        behavior: attr.behavior.into(),
         arguments: None,
         has_receiver: false,
         is_async: false,
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index ba4d72ad6..7e7249563 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -74,7 +74,7 @@ pub(crate) struct Attr {
     pub(crate) scalar: Option<SpanContainer<scalar::AttrValue>>,
 
     /// 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 01b34dd43..3139da74b 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 33c0db850..552c28ba7 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<TokenStream> {
         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 643707968..e4ebe8067 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<SpanContainer<scalar::AttrValue>>,
 
     /// 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.

From 7364187437740042365c0840fb57f1f6fa1d5154 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 27 Jun 2022 15:58:20 +0200
Subject: [PATCH 46/58] Impl `resolve::Value` and `resolve::ToInputValue`
 traits for enums [skip ci]

---
 juniper_codegen/src/graphql_enum/mod.rs   | 202 +++++++++++++++++++++-
 juniper_codegen/src/graphql_scalar/mod.rs |   3 +-
 2 files changed, 201 insertions(+), 4 deletions(-)

diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index bebe05c2e..2964b8738 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -439,6 +439,16 @@ impl ToTokens for Definition {
         self.impl_to_input_value_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
+        //self.impl_resolve_type().to_tokens(into);
+        //self.impl_resolve_type_name().to_tokens(into);
+        self.impl_resolve_value().to_tokens(into);
+        self.impl_resolve_value_async().to_tokens(into);
+        self.impl_resolve_to_input_value().to_tokens(into);
+        //self.impl_resolve_input_value().to_tokens(into);
+        //self.impl_resolve_scalar_token().to_tokens(into);
+        //self.impl_graphql_input_type().to_tokens(into);
+        //self.impl_graphql_output_type().to_tokens(into);
+        //self.impl_graphql_enum().to_tokens(into);
         self.impl_reflect().to_tokens(into);
     }
 }
@@ -602,6 +612,64 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::Value`] trait for this
+    /// [GraphQL enum][0].
+    ///
+    /// [`resolve::Value`]: juniper::resolve::Value
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    fn impl_resolve_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            #sv: From<String>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let variant_arms = self.values.iter().map(|v| {
+            let v_ident = &v.ident;
+            let v_name = &v.name;
+
+            quote! {
+                Self::#v_ident => ::std::result::Result::Ok(
+                    ::juniper::Value::<#sv>::scalar(
+                        ::std::string::String::from(#v_name),
+                    ),
+                ),
+            }
+        });
+        let ignored_arm = self.has_ignored_variants.then(|| {
+            let err_msg = format!("Cannot resolve ignored variant of `{}` enum", self.ident);
+
+            quote! {
+                _ => ::std::result::Result::Err(
+                    ::juniper::FieldError::<#sv>::from(#err_msg),
+                ),
+            }
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+                for #ty #where_clause
+            {
+                fn resolve_value(
+                    &self,
+                    _: Option<&[::juniper::Selection<'_, #sv>]>,
+                    _: &#inf,
+                    _: &::juniper::Executor<'_, '_, #cx, #sv>,
+                ) -> ::juniper::ExecutionResult<#sv> {
+                    match self {
+                        #( #variant_arms )*
+                        #ignored_arm
+                    }
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLValueAsync`] trait for this
     /// [GraphQL enum][0].
     ///
@@ -633,6 +701,48 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::ValueAsync`] trait for
+    /// this [GraphQL enum][0].
+    ///
+    /// [`resolve::ValueAsync`]: juniper::resolve::ValueAsync
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    fn impl_resolve_value_async(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let preds = &mut generics.make_where_clause().predicates;
+        preds.push(parse_quote! {
+            Self: ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+        });
+        preds.push(parse_quote! {
+            #sv: Send
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
+                for #ty #where_clause
+            {
+                fn resolve_value_async<'__r>(
+                    &'__r self,
+                    sel_set: Option<&'__r [::juniper::Selection<'_, #sv>]>,
+                    type_info: &'__r #inf,
+                    executor: &'__r ::juniper::Executor<'_, '_, #cx, #sv>,
+                ) -> ::juniper::BoxFuture<
+                    '__r, ::juniper::ExecutionResult<#sv>,
+                > {
+                    let v =
+                        <Self as ::juniper::resolve::Value<#inf, #cx, #sv, #bh>>
+                            ::resolve_value(self, sel_set, type_info, executor);
+                    ::std::boxed::Box::pin(::juniper::futures::future::ready(v))
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`FromInputValue`] trait for this
     /// [GraphQL enum][0].
     ///
@@ -717,6 +827,53 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::ToInputValue`] trait for
+    /// this [GraphQL enum][0].
+    ///
+    /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    fn impl_resolve_to_input_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            #sv: From<String>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let variant_arms = self.values.iter().map(|v| {
+            let v_ident = &v.ident;
+            let v_name = &v.name;
+
+            quote! {
+                Self::#v_ident => ::juniper::graphql::InputValue::<#sv>::scalar(
+                    ::std::string::String::from(#v_name),
+                ),
+            }
+        });
+        let ignored_arm = self.has_ignored_variants.then(|| {
+            let err_msg = format!("Cannot resolve ignored variant of `{}` enum", self.ident);
+
+            quote! {
+                _ => ::std::panic!(#err_msg),
+            }
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
+                #where_clause
+            {
+                fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
+                    match self {
+                        #( #variant_arms )*
+                        #ignored_arm
+                    }
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`BaseType`], [`BaseSubTypes`] and
     /// [`WrappedType`] traits for this [GraphQL enum][0].
     ///
@@ -860,16 +1017,57 @@ impl Definition {
 
     /// 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)
+    }
 
+    /// Mixes a type info [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`syn::Ident`].
+    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let ty = parse_quote! { __TypeInfo };
+        generics.params.push(parse_quote! { #ty: ?Sized });
         (ty, generics)
     }
+
+    /// Mixes a context [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`syn::Ident`].
+    fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let ty = parse_quote! { __Context };
+        generics.params.push(parse_quote! { #ty: ?Sized });
+        (ty, generics)
+    }
+
+    /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns it.
+    ///
+    /// [`ScalarValue`]: juniper::ScalarValue
+    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let sv = parse_quote! { __ScalarValue };
+        generics.params.push(parse_quote! { #sv });
+        (sv, generics)
+    }
+
+    /// Mixes an [`InputValue`]'s lifetime [`syn::GenericParam`] into the
+    /// provided [`syn::Generics`] and returns it.
+    ///
+    /// [`InputValue`]: juniper::resolve::InputValue
+    fn mix_input_lifetime(
+        &self,
+        mut generics: syn::Generics,
+        sv: &syn::Ident,
+    ) -> (syn::GenericParam, syn::Generics) {
+        let lt: syn::GenericParam = parse_quote! { '__inp };
+        generics.params.push(lt.clone());
+        generics
+            .make_where_clause()
+            .predicates
+            .push(parse_quote! { #sv: #lt });
+        (lt, generics)
+    }
 }
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index e4ebe8067..c29924c9f 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -1084,7 +1084,6 @@ impl Definition {
     #[must_use]
     fn ty_and_generics(&self) -> (syn::Type, syn::Generics) {
         let mut generics = self.generics.clone();
-
         let ty = {
             let ident = &self.ident;
             let (_, ty_gen, _) = generics.split_for_impl();
@@ -1248,7 +1247,7 @@ impl Methods {
                 let into = sv.custom.is_some().then(|| {
                     quote! { .map_scalar_value() }
                 });
-                quote! { Ok(#to_output(self)#into) }
+                quote! { ::std::result::Result::Ok(#to_output(self)#into) }
             }
 
             Self::Delegated { field, .. } => {

From 98b282d06d821751fbaf21e387526176a2aeb8fd Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 27 Jun 2022 16:17:50 +0200
Subject: [PATCH 47/58] Impl `resolve::InputValue` trait for enums

---
 juniper_codegen/src/graphql_enum/mod.rs | 46 +++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index 2964b8738..51aba54e7 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -444,8 +444,7 @@ impl ToTokens for Definition {
         self.impl_resolve_value().to_tokens(into);
         self.impl_resolve_value_async().to_tokens(into);
         self.impl_resolve_to_input_value().to_tokens(into);
-        //self.impl_resolve_input_value().to_tokens(into);
-        //self.impl_resolve_scalar_token().to_tokens(into);
+        self.impl_resolve_input_value().to_tokens(into);
         //self.impl_graphql_input_type().to_tokens(into);
         //self.impl_graphql_output_type().to_tokens(into);
         //self.impl_graphql_enum().to_tokens(into);
@@ -782,6 +781,49 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::InputValue`] trait for
+    /// this [GraphQL scalar][0].
+    ///
+    /// [`resolve::InputValue`]: juniper::resolve::InputValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    fn impl_resolve_input_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            #sv: ::juniper::ScalarValue
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let variant_arms = self.values.iter().map(|v| {
+            let v_ident = &v.ident;
+            let v_name = &v.name;
+
+            quote! {
+                Some(#v_name) => Ok(Self::#v_ident),
+            }
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh> for #ty
+                #where_clause
+            {
+                type Error = ::std::string::String;
+
+                fn try_from_input_value(
+                    input: &#lt ::juniper::graphql::InputValue<#sv>,
+                ) -> ::std::result::Result<Self, Self::Error> {
+                    match v.as_enum_value().or_else(|| v.as_string_value()) {
+                        #( #variant_arms )*
+                        _ => Err(::std::format!("Unknown enum value: {}", v)),
+                    }
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`ToInputValue`] trait for this
     /// [GraphQL enum][0].
     ///

From 4257e72c751e724d5b14d57124f13fed2fb02796 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 27 Jun 2022 16:57:54 +0200
Subject: [PATCH 48/58] Impl `resolve::Type` trait for enums

---
 juniper/src/executor/mod.rs               |  35 +++++++
 juniper/src/schema/meta.rs                |  18 ++++
 juniper_codegen/src/graphql_enum/mod.rs   | 114 ++++++++++++++++++++--
 juniper_codegen/src/graphql_scalar/mod.rs |   2 +-
 4 files changed, 160 insertions(+), 9 deletions(-)

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 73d8b6a48..b0b7b08c1 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -1456,6 +1456,41 @@ impl<'r, S: 'r> Registry<'r, S> {
         EnumMeta::new::<T>(Cow::Owned(name.to_string()), values)
     }
 
+    /// Builds an [`EnumMeta`] information for the specified [`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_enum_with<'ti, T, TI, F>(
+        &mut self,
+        values: &[EnumValue],
+        type_info: &'ti TI,
+        customize: F,
+    ) -> MetaType<'r, S>
+    where
+        T: resolve::TypeName<TI> + resolve::InputValueOwned<S>,
+        TI: ?Sized,
+        'ti: 'r,
+        F: FnOnce(EnumMeta<'r, S>) -> EnumMeta<'r, S>,
+        S: Clone,
+    {
+        self.entry_type::<T, _>(type_info)
+            .or_insert_with(move || {
+                customize(EnumMeta::new_reworked::<T, _>(
+                    T::type_name(type_info),
+                    values,
+                ))
+                .into_meta()
+            })
+            .clone()
+    }
+
     /// Creates an [`InterfaceMeta`] type with the given `fields`.
     pub fn build_interface_type<T>(
         &mut self,
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index d686a09ca..ce5b0874f 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -651,6 +651,24 @@ impl<'a, S> EnumMeta<'a, S> {
         }
     }
 
+    /// Builds a new [`EnumMeta`] information with the specified `name` and
+    /// possible `values`.
+    // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
+    //       `explicit_generic_args_with_impl_trait` hits stable:
+    //       https://github.com/rust-lang/rust/issues/83701
+    pub fn new_reworked<T, N>(name: N, values: &[EnumValue]) -> Self
+    where
+        T: resolve::InputValueOwned<S>,
+        Cow<'a, str>: From<N>,
+    {
+        Self {
+            name: name.into(),
+            description: None,
+            values: values.to_owned(),
+            try_parse_fn: try_parse_fn_reworked::<T, S>,
+        }
+    }
+
     /// Sets the `description` of this [`EnumMeta`] type.
     ///
     /// Overwrites any previously set description.
diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index 51aba54e7..7cb9a558a 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -439,8 +439,8 @@ impl ToTokens for Definition {
         self.impl_to_input_value_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        //self.impl_resolve_type().to_tokens(into);
-        //self.impl_resolve_type_name().to_tokens(into);
+        self.impl_resolve_type().to_tokens(into);
+        self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_value().to_tokens(into);
         self.impl_resolve_value_async().to_tokens(into);
         self.impl_resolve_to_input_value().to_tokens(into);
@@ -553,6 +553,98 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::Type`] trait for this
+    /// [GraphQL enum][0].
+    ///
+    /// [`resolve::Type`]: juniper::resolve::Type
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    fn impl_resolve_type(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let preds = &mut generics.make_where_clause().predicates;
+        preds.push(parse_quote! { #sv: Clone });
+        preds.push(parse_quote! {
+            ::juniper::behavior::Coerce<Self>:
+                ::juniper::resolve::TypeName<#inf>
+                + ::juniper::resolve::InputValueOwned<#sv>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let description = self
+            .description
+            .as_ref()
+            .map(|text| quote! { .description(#text) });
+
+        let values_meta = self.values.iter().map(|v| {
+            let v_name = &v.name;
+            let v_description = v
+                .description
+                .as_ref()
+                .map(|text| quote! { .description(#text) });
+            let v_deprecation = v.deprecated.as_ref().map(|depr| {
+                let reason = depr.as_ref().map_or_else(
+                    || quote! { ::std::option::Option::None },
+                    |text| quote! { ::std::option::Option::Some(#text) },
+                );
+                quote! { .deprecated(#reason) }
+            });
+
+            quote! {
+                ::juniper::meta::EnumValue::new(#v_name)
+                    #v_description
+                    #v_deprecation
+            }
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
+                #where_clause
+            {
+                fn meta<'__r, '__ti: '__r>(
+                    registry: &mut ::juniper::Registry<'__r, #sv>,
+                    type_info: &'__ti #inf,
+                ) -> ::juniper::meta::MetaType<'__r, #sv>
+                where
+                    #sv: '__r,
+                {
+                    let values = [#( #values_meta ),*];
+
+                    registry.register_enum_with::<
+                        ::juniper::behavior::Coerce<Self>, _, _,
+                    >(&values, type_info, |meta| {
+                        meta#description
+                    })
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`resolve::TypeName`] trait for this
+    /// [GraphQL enum][0].
+    ///
+    /// [`resolve::TypeName`]: juniper::resolve::TypeName
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    fn impl_resolve_type_name(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
+                #where_clause
+            {
+                fn type_name(_: &#inf) -> &'static str {
+                    <Self as ::juniper::reflect::BaseType<#bh>>::NAME
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLValue`] trait for this
     /// [GraphQL enum][0].
     ///
@@ -782,15 +874,15 @@ impl Definition {
     }
 
     /// Returns generated code implementing [`resolve::InputValue`] trait for
-    /// this [GraphQL scalar][0].
+    /// this [GraphQL enum][0].
     ///
     /// [`resolve::InputValue`]: juniper::resolve::InputValue
-    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
     fn impl_resolve_input_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             #sv: ::juniper::ScalarValue
         });
@@ -801,7 +893,8 @@ impl Definition {
             let v_name = &v.name;
 
             quote! {
-                Some(#v_name) => Ok(Self::#v_ident),
+                ::std::option::Option::Some(#v_name) =>
+                    ::std::result::Result::Ok(Self::#v_ident),
             }
         });
 
@@ -815,9 +908,14 @@ impl Definition {
                 fn try_from_input_value(
                     input: &#lt ::juniper::graphql::InputValue<#sv>,
                 ) -> ::std::result::Result<Self, Self::Error> {
-                    match v.as_enum_value().or_else(|| v.as_string_value()) {
+                    match input
+                        .as_enum_value()
+                        .or_else(|| input.as_string_value())
+                    {
                         #( #variant_arms )*
-                        _ => Err(::std::format!("Unknown enum value: {}", v)),
+                        _ => ::std::result::Result::Err(
+                            ::std::format!("Unknown enum value: {}", input),
+                        ),
                     }
                 }
             }
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index c29924c9f..21ad3b32b 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -575,7 +575,7 @@ impl Definition {
         let description = self
             .description
             .as_ref()
-            .map(|val| quote! { .description(#val) });
+            .map(|text| quote! { .description(#text) });
 
         let specified_by_url = self.specified_by_url.as_ref().map(|url| {
             let url_lit = url.as_str();

From fa03c7fa4d1884a700e17c13aa55cada2b0ad20e Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 27 Jun 2022 17:05:01 +0200
Subject: [PATCH 49/58] Impl `graphql::Enum` trait for enums [skip ci]

---
 juniper/src/graphql/mod.rs              | 15 +++-
 juniper_codegen/src/graphql_enum/mod.rs | 93 ++++++++++++++++++++++++-
 2 files changed, 104 insertions(+), 4 deletions(-)

diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index a88b154dc..097e775d5 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -6,9 +6,22 @@ pub use crate::{
     macros::{input_value, value, vars},
     resolve::Type,
     value::Value,
-    GraphQLScalar as Scalar,
+    GraphQLEnum as Enum, GraphQLScalar as Scalar,
 };
 
+pub trait Enum<
+    'inp,
+    TypeInfo: ?Sized,
+    Context: ?Sized,
+    ScalarValue: 'inp,
+    Behavior: ?Sized = behavior::Standard,
+>:
+    InputType<'inp, TypeInfo, ScalarValue, Behavior>
+    + OutputType<TypeInfo, Context, ScalarValue, Behavior>
+{
+    fn assert_enum();
+}
+
 /*
 pub trait Interface<S>: OutputType<S>
    + resolve::TypeName
diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index 7cb9a558a..ae1b23228 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -445,9 +445,9 @@ impl ToTokens for Definition {
         self.impl_resolve_value_async().to_tokens(into);
         self.impl_resolve_to_input_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
-        //self.impl_graphql_input_type().to_tokens(into);
-        //self.impl_graphql_output_type().to_tokens(into);
-        //self.impl_graphql_enum().to_tokens(into);
+        self.impl_graphql_input_type().to_tokens(into);
+        self.impl_graphql_output_type().to_tokens(into);
+        self.impl_graphql_enum().to_tokens(into);
         self.impl_reflect().to_tokens(into);
     }
 }
@@ -479,6 +479,93 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`graphql::InputType`] trait for
+    /// this [GraphQL enum][0].
+    ///
+    /// [`graphql::InputType`]: juniper::graphql::InputType
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    #[must_use]
+    fn impl_graphql_input_type(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::resolve::Type<#inf, #sv, #bh>
+                  + ::juniper::resolve::ToInputValue<#sv, #bh>
+                  + ::juniper::resolve::InputValue<#lt, #sv, #bh>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+                for #ty #where_clause
+            {
+                fn assert_input_type() {}
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`graphql::OutputType`] trait for
+    /// this [GraphQL enum][0].
+    ///
+    /// [`graphql::OutputType`]: juniper::graphql::OutputType
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    #[must_use]
+    fn impl_graphql_output_type(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::resolve::Type<#inf, #sv, #bh>
+                  + ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+                  + ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
+                for #ty #where_clause
+            {
+                fn assert_output_type() {}
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`graphql::Enum`] trait for this
+    /// [GraphQL enum][0].
+    ///
+    /// [`graphql::Enum`]: juniper::graphql::Enum
+    /// [0]: https://spec.graphql.org/October2021#sec-Enums
+    #[must_use]
+    fn impl_graphql_enum(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+                  + ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl#impl_gens ::juniper::graphql::Enum<#lt, #inf, #cx, #sv, #bh>
+                for #ty #where_clause
+            {
+                fn assert_enum() {}
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLType`] trait for this
     /// [GraphQL enum][0].
     ///

From 464ff10c14494bff238a57e1b070ae8ee36f7d82 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Wed, 10 Aug 2022 19:10:38 +0300
Subject: [PATCH 50/58] Impl input objects, vol.1 [skip ci]

---
 juniper/src/behavior.rs                       |  11 +
 .../src/graphql_input_object/derive.rs        |  12 +-
 .../src/graphql_input_object/mod.rs           | 232 ++++++++++++++++--
 3 files changed, 233 insertions(+), 22 deletions(-)

diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
index cb1976cd4..d8f8b4d21 100644
--- a/juniper/src/behavior.rs
+++ b/juniper/src/behavior.rs
@@ -64,6 +64,17 @@ where
     }
 }
 
+impl<T, SV, B1, B2> resolve::ToInputValue<SV, B1> for Coerce<T, B2>
+where
+    T: resolve::ToInputValue<SV, B2> + ?Sized,
+    B1: ?Sized,
+    B2: ?Sized,
+{
+    fn to_input_value(&self) -> graphql::InputValue<SV> {
+        self.1.to_input_value()
+    }
+}
+
 impl<'i, T, SV, B1, B2> resolve::InputValue<'i, SV, B1> for Coerce<T, B2>
 where
     T: resolve::InputValue<'i, SV, B2>,
diff --git a/juniper_codegen/src/graphql_input_object/derive.rs b/juniper_codegen/src/graphql_input_object/derive.rs
index 370fc2002..562343ea2 100644
--- a/juniper_codegen/src/graphql_input_object/derive.rs
+++ b/juniper_codegen/src/graphql_input_object/derive.rs
@@ -80,6 +80,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar,
+        behavior: attr.behavior.into(),
         fields,
     };
 
@@ -94,13 +95,13 @@ fn parse_field(
     renaming: rename::Policy,
     is_internal: bool,
 ) -> Option<FieldDefinition> {
-    let field_attr = FieldAttr::from_attrs("graphql", &f.attrs)
+    let attr = FieldAttr::from_attrs("graphql", &f.attrs)
         .map_err(|e| proc_macro_error::emit_error!(e))
         .ok()?;
 
     let ident = f.ident.as_ref().or_else(|| err_unnamed_field(f))?;
 
-    let name = field_attr
+    let name = attr
         .name
         .map_or_else(
             || renaming.apply(&ident.unraw().to_string()),
@@ -114,10 +115,11 @@ fn parse_field(
     Some(FieldDefinition {
         ident: ident.clone(),
         ty: f.ty.clone(),
-        default: field_attr.default.map(SpanContainer::into_inner),
+        default: attr.default.map(SpanContainer::into_inner),
+        behavior: attr.behavior.into(),
         name,
-        description: field_attr.description.map(SpanContainer::into_inner),
-        ignored: field_attr.ignore.is_some(),
+        description: attr.description.map(SpanContainer::into_inner),
+        ignored: attr.ignore.is_some(),
     })
 }
 
diff --git a/juniper_codegen/src/graphql_input_object/mod.rs b/juniper_codegen/src/graphql_input_object/mod.rs
index 93c21d6f8..9d37269f2 100644
--- a/juniper_codegen/src/graphql_input_object/mod.rs
+++ b/juniper_codegen/src/graphql_input_object/mod.rs
@@ -15,7 +15,7 @@ use syn::{
 };
 
 use crate::common::{
-    default, filter_attrs,
+    behavior, default, filter_attrs,
     parse::{
         attr::{err, OptionExt as _},
         ParseBufferExt as _,
@@ -66,6 +66,17 @@ struct ContainerAttr {
     /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
     scalar: Option<SpanContainer<scalar::AttrValue>>,
 
+    /// Explicitly specified type of the custom [`Behavior`] to parametrize this
+    /// [GraphQL input object][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-Input-Objects
+    behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified [`rename::Policy`] for all fields of this
     /// [GraphQL input object][0].
     ///
@@ -118,6 +129,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::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "rename_all" => {
                     input.parse::<token::Eq>()?;
                     let val = input.parse::<syn::LitStr>()?;
@@ -151,6 +169,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_fields: try_merge_opt!(rename_fields: self, another),
             is_internal: self.is_internal || another.is_internal,
         })
@@ -185,6 +204,16 @@ struct FieldAttr {
     /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
     name: Option<SpanContainer<String>>,
 
+    /// Explicitly specified [description][2] of this
+    /// [GraphQL input object field][1].
+    ///
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    description: Option<SpanContainer<Description>>,
+
     /// Explicitly specified [default value][2] of this
     /// [GraphQL input object field][1] to be used used in case a field value is
     /// not provided.
@@ -195,15 +224,18 @@ struct FieldAttr {
     /// [2]: https://spec.graphql.org/October2021#DefaultValue
     default: Option<SpanContainer<default::Value>>,
 
-    /// Explicitly specified [description][2] of this
-    /// [GraphQL input object field][1].
+    /// Explicitly specified type of the custom [`Behavior`] this
+    /// [GraphQL input object field][1] implementation is parametrized with, to
+    /// [coerce] in the generated code from.
     ///
-    /// If [`None`], then Rust doc comment will be used as the [description][2],
-    /// if any.
+    /// If [`None`], then [`behavior::Standard`] will be used for the generated
+    /// code.
     ///
+    /// [`Behavior`]: juniper::behavior
+    /// [`behavior::Standard`]: juniper::behavior::Standard
     /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
-    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
-    description: Option<SpanContainer<Description>>,
+    /// [coerce]: juniper::behavior::Coerce
+    behavior: Option<SpanContainer<behavior::Type>>,
 
     /// Explicitly specified marker for the Rust struct field to be ignored and
     /// not included into the code generated for a [GraphQL input object][0]
@@ -234,17 +266,24 @@ impl Parse for FieldAttr {
                         ))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
+                "desc" | "description" => {
+                    input.parse::<token::Eq>()?;
+                    let desc = input.parse::<Description>()?;
+                    out.description
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "default" => {
                     let val = input.parse::<default::Value>()?;
                     out.default
                         .replace(SpanContainer::new(ident.span(), Some(val.span()), val))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
-                "desc" | "description" => {
+                "behave" | "behavior" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<Description>()?;
-                    out.description
-                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "ignore" | "skip" => out
@@ -267,8 +306,9 @@ impl FieldAttr {
     fn try_merge(self, mut another: Self) -> syn::Result<Self> {
         Ok(Self {
             name: try_merge_opt!(name: self, another),
-            default: try_merge_opt!(default: self, another),
             description: try_merge_opt!(description: self, another),
+            default: try_merge_opt!(default: self, another),
+            behavior: try_merge_opt!(behavior: self, another),
             ignore: try_merge_opt!(ignore: self, another),
         })
     }
@@ -314,6 +354,14 @@ struct FieldDefinition {
     /// [2]: https://spec.graphql.org/October2021#DefaultValue
     default: Option<default::Value>,
 
+    /// [`Behavior`] parametrization of this [GraphQL input object field][1]
+    /// implementation to [coerce] from in the generated code.
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    /// [coerce]: juniper::behavior::Coerce
+    behavior: behavior::Type,
+
     /// Name of this [GraphQL input object field][1] in GraphQL schema.
     ///
     /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
@@ -383,6 +431,13 @@ struct Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
     scalar: scalar::Type,
 
+    /// [`Behavior`] parametrization to generate code with for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    behavior: behavior::Type,
+
     /// [Fields][1] of this [GraphQL input object][0].
     ///
     /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
@@ -399,6 +454,14 @@ 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_resolve_type().to_tokens(into);
+        self.impl_resolve_type_name().to_tokens(into);
+        self.impl_resolve_to_input_value().to_tokens(into);
+        //self.impl_resolve_input_value().to_tokens(into);
+        //self.impl_graphql_input_type().to_tokens(into);
+        //self.impl_graphql_input_object().to_tokens(into);
+        self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -500,6 +563,29 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::TypeName`] trait for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`resolve::TypeName`]: juniper::resolve::TypeName
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    fn impl_resolve_type_name(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::resolve::TypeName<#inf, #bh>
+             for #ty #where_clause
+            {
+                fn type_name(_: &#inf) -> &'static str {
+                    <Self as ::juniper::reflect::BaseType<#bh>>::NAME
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLValue`] trait for this
     /// [GraphQL input object][0].
     ///
@@ -663,11 +749,52 @@ impl Definition {
                 #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
-                    ::juniper::InputValue::object(
-                        #[allow(deprecated)]
-                        ::std::array::IntoIter::new([#( #fields ),*])
-                            .collect()
-                    )
+                    ::juniper::InputValue::object([#( #fields ),*])
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`resolve::ToInputValue`] trait for
+    /// this [GraphQL input object][0].
+    ///
+    /// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    fn impl_resolve_to_input_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        for f in &self.fields {
+            let field_ty = &f.ty;
+            let field_bh = &f.behavior;
+            generics.make_where_clause().predicates.push(parse_quote! {
+                #field_ty: ::juniper::resolve::ToInputValue<#sv, #field_bh>
+            });
+        }
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let fields = self.fields.iter().filter_map(|f| {
+            let field = &f.ident;
+            let field_ty = &f.ty;
+            let field_bh = &f.behavior;
+            let name = &f.name;
+
+            (!f.ignored).then(|| {
+                quote! {
+                    (#name, <#field_ty as
+                             ::juniper::resolve::ToInputValue<#sv, #field_bh>>
+                                ::to_input_value(&self.#field))
+                }
+            })
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::resolve::ToInputValue<#sv, #bh>
+             for #ty #where_clause
+            {
+                fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
+                    ::juniper::InputValue::object([#( #fields ),*])
                 }
             }
         }
@@ -716,6 +843,47 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`reflect::BaseType`],
+    /// [`reflect::BaseSubTypes`] and [`reflect::WrappedType`] traits for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`reflect::BaseSubTypes`]: juniper::reflect::BaseSubTypes
+    /// [`reflect::BaseType`]: juniper::reflect::BaseType
+    /// [`reflect::WrappedType`]: juniper::reflect::WrappedType
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    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 =
+                    &[<Self as ::juniper::reflect::BaseType<#bh>>::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 struct.
     ///
@@ -775,4 +943,34 @@ impl Definition {
 
         generics
     }
+
+    /// Returns prepared self [`syn::Type`] and [`syn::Generics`] for a trait
+    /// implementation.
+    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)
+    }
+
+    /// Mixes a type info [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`syn::Ident`].
+    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let ty = parse_quote! { __TypeInfo };
+        generics.params.push(parse_quote! { #ty: ?Sized });
+        (ty, generics)
+    }
+
+    /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns it.
+    ///
+    /// [`ScalarValue`]: juniper::ScalarValue
+    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let sv = parse_quote! { __ScalarValue };
+        generics.params.push(parse_quote! { #sv });
+        (sv, generics)
+    }
 }

From fea722b1961e0aa2d91aa764e5ab9294a12b4be4 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 11 Aug 2022 18:06:43 +0300
Subject: [PATCH 51/58] Impl input objects, vol.2 [skip ci]

---
 juniper/src/behavior.rs                       |  11 -
 juniper/src/executor/mod.rs                   |  45 +++
 juniper/src/graphql/mod.rs                    |  10 +
 juniper/src/schema/meta.rs                    |  19 ++
 juniper_codegen/src/graphql_enum/mod.rs       |   9 +-
 .../src/graphql_input_object/mod.rs           | 308 +++++++++++++++++-
 juniper_codegen/src/graphql_scalar/mod.rs     |   9 +-
 7 files changed, 386 insertions(+), 25 deletions(-)

diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
index d8f8b4d21..cb1976cd4 100644
--- a/juniper/src/behavior.rs
+++ b/juniper/src/behavior.rs
@@ -64,17 +64,6 @@ where
     }
 }
 
-impl<T, SV, B1, B2> resolve::ToInputValue<SV, B1> for Coerce<T, B2>
-where
-    T: resolve::ToInputValue<SV, B2> + ?Sized,
-    B1: ?Sized,
-    B2: ?Sized,
-{
-    fn to_input_value(&self) -> graphql::InputValue<SV> {
-        self.1.to_input_value()
-    }
-}
-
 impl<'i, T, SV, B1, B2> resolve::InputValue<'i, SV, B1> for Coerce<T, B2>
 where
     T: resolve::InputValue<'i, SV, B2>,
diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 4cd8bffa7..558d58508 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -1263,6 +1263,16 @@ impl<'r, S: 'r> Registry<'r, S> {
         Argument::new(name, self.get_type::<T>(info)).default_value(value.to_input_value())
     }
 
+    /// Creates an [`Argument`] with the provided `name`.
+    pub fn arg_reworked<'ti, T, TI>(&mut self, name: &str, type_info: &'ti TI) -> Argument<'r, S>
+    where
+        T: resolve::Type<TI, S> + resolve::InputValueOwned<S>,
+        TI: ?Sized,
+        'ti: 'r,
+    {
+        Argument::new(name, T::meta(self, type_info).as_type())
+    }
+
     fn insert_placeholder(&mut self, name: Name, of_type: Type<'r>) {
         self.types
             .entry(name)
@@ -1531,4 +1541,39 @@ impl<'r, S: 'r> Registry<'r, S> {
 
         InputObjectMeta::new::<T>(Cow::Owned(name.into()), args)
     }
+
+    /// Builds an [`InputObjectMeta`] information for the specified
+    /// [`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_input_object_with<'ti, T, TI, F>(
+        &mut self,
+        fields: &[Argument<'r, S>],
+        type_info: &'ti TI,
+        customize: F,
+    ) -> MetaType<'r, S>
+    where
+        T: resolve::TypeName<TI> + resolve::InputValueOwned<S>,
+        TI: ?Sized,
+        'ti: 'r,
+        F: FnOnce(InputObjectMeta<'r, S>) -> InputObjectMeta<'r, S>,
+        S: Clone,
+    {
+        self.entry_type::<T, _>(type_info)
+            .or_insert_with(move || {
+                customize(InputObjectMeta::new_reworked::<T, _>(
+                    T::type_name(type_info),
+                    fields,
+                ))
+                .into_meta()
+            })
+            .clone()
+    }
 }
diff --git a/juniper/src/graphql/mod.rs b/juniper/src/graphql/mod.rs
index 097e775d5..387690d16 100644
--- a/juniper/src/graphql/mod.rs
+++ b/juniper/src/graphql/mod.rs
@@ -47,6 +47,16 @@ pub trait Object<S>: OutputType<S>
     fn assert_object();
 }*/
 
+pub trait InputObject<
+    'inp,
+    TypeInfo: ?Sized,
+    ScalarValue: 'inp,
+    Behavior: ?Sized = behavior::Standard,
+>: InputType<'inp, TypeInfo, ScalarValue, Behavior>
+{
+    fn assert_input_object();
+}
+
 pub trait Scalar<
     'inp,
     TypeInfo: ?Sized,
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index 717a23834..13d526ebb 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -769,6 +769,25 @@ impl<'a, S> InputObjectMeta<'a, S> {
         }
     }
 
+    /// Builds a new [`InputObjectMeta`] information with the specified `name`
+    /// and its `fields`.
+    // TODO: Use `impl Into<Cow<'a, str>>` argument once feature
+    //       `explicit_generic_args_with_impl_trait` hits stable:
+    //       https://github.com/rust-lang/rust/issues/83701
+    pub fn new_reworked<T, N>(name: N, fields: &[Argument<'a, S>]) -> Self
+    where
+        T: resolve::InputValueOwned<S>,
+        Cow<'a, str>: From<N>,
+        S: Clone,
+    {
+        Self {
+            name: name.into(),
+            description: None,
+            input_fields: fields.to_vec(),
+            try_parse_fn: try_parse_fn_reworked::<T, S>,
+        }
+    }
+
     /// Set the `description` of this [`InputObjectMeta`] type.
     ///
     /// Overwrites any previously set description.
diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index 85e22be03..3f26625f0 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -533,9 +533,14 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::graphql::Enum<#lt, #inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
-                fn assert_enum() {}
+                fn assert_enum() {
+                    <Self as ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>>
+                        ::assert_input_type();
+                    <Self as ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>>
+                        ::assert_output_type();
+                }
             }
         }
     }
diff --git a/juniper_codegen/src/graphql_input_object/mod.rs b/juniper_codegen/src/graphql_input_object/mod.rs
index 9d37269f2..ec6ea64c5 100644
--- a/juniper_codegen/src/graphql_input_object/mod.rs
+++ b/juniper_codegen/src/graphql_input_object/mod.rs
@@ -386,6 +386,14 @@ struct FieldDefinition {
     ignored: bool,
 }
 
+impl FieldDefinition {
+    /// Indicates whether this [`FieldDefinition`] uses [`Default::default()`]
+    /// ans its [`FieldDefinition::default`] value.
+    fn needs_default_trait_bound(&self) -> bool {
+        matches!(self.default, Some(default::Value::Default))
+    }
+}
+
 /// Representation of [GraphQL input object][0] for code generation.
 ///
 /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
@@ -455,12 +463,12 @@ impl ToTokens for Definition {
         self.impl_to_input_value_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        //self.impl_resolve_type().to_tokens(into);
+        self.impl_resolve_type().to_tokens(into);
         self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_to_input_value().to_tokens(into);
-        //self.impl_resolve_input_value().to_tokens(into);
-        //self.impl_graphql_input_type().to_tokens(into);
-        //self.impl_graphql_input_object().to_tokens(into);
+        self.impl_resolve_input_value().to_tokens(into);
+        self.impl_graphql_input_type().to_tokens(into);
+        self.impl_graphql_input_object().to_tokens(into);
         self.impl_reflect().to_tokens(into);
     }
 }
@@ -503,6 +511,88 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`graphql::InputType`] trait for
+    /// [GraphQL input object][0].
+    ///
+    /// [`graphql::InputType`]: juniper::graphql::InputType
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    fn impl_graphql_input_type(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::resolve::Type<#inf, #sv, #bh>
+                  + ::juniper::resolve::ToInputValue<#sv, #bh>
+                  + ::juniper::resolve::InputValue<#lt, #sv, #bh>
+        });
+        for f in self.fields.iter().filter(|f| !f.ignored) {
+            let field_ty = &f.ty;
+            let field_bh = &f.behavior;
+            generics.make_where_clause().predicates.push(parse_quote! {
+                #field_ty:
+                    ::juniper::graphql::InputType<#lt, #inf, #sv, #field_bh>
+            });
+        }
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let fields_assertions = self.fields.iter().filter_map(|f| {
+            (!f.ignored).then(|| {
+                let field_ty = &f.ty;
+                let field_bh = &f.behavior;
+
+                quote! {
+                    <#field_ty as
+                     ::juniper::graphql::InputType<#lt, #inf, #sv, #field_bh>>
+                        ::assert_input_type();
+                }
+            })
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+             for #ty #where_clause
+            {
+                fn assert_input_type() {
+                    #( #fields_assertions )*
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`graphql::InputObject`] trait for
+    /// this [GraphQL input object][0].
+    ///
+    /// [`graphql::InputObject`]: juniper::graphql::InputObject
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    fn impl_graphql_input_object(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            Self: ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+        });
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::graphql::InputObject<#lt, #inf, #sv, #bh>
+             for #ty #where_clause
+            {
+                fn assert_input_object() {
+                    <Self as ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>>
+                        ::assert_input_type();
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLType`] trait for this
     /// [GraphQL input object][0].
     ///
@@ -563,6 +653,96 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::Type`] trait for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`resolve::Type`]: juniper::resolve::Type
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    fn impl_resolve_type(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let preds = &mut generics.make_where_clause().predicates;
+        preds.push(parse_quote! { #sv: Clone });
+        preds.push(parse_quote! {
+            ::juniper::behavior::Coerce<Self>:
+                ::juniper::resolve::TypeName<#inf>
+                + ::juniper::resolve::InputValueOwned<#sv>
+        });
+        for f in self.fields.iter().filter(|f| !f.ignored) {
+            let field_ty = &f.ty;
+            let field_bh = &f.behavior;
+            preds.push(parse_quote! {
+                ::juniper::behavior::Coerce<#field_ty>:
+                    ::juniper::resolve::Type<#inf, #sv>
+                    + ::juniper::resolve::InputValueOwned<#sv>
+            });
+            if f.default.is_some() {
+                preds.push(parse_quote! {
+                    #field_ty: ::juniper::resolve::ToInputValue<#sv, #field_bh>
+                });
+            }
+            if f.needs_default_trait_bound() {
+                preds.push(parse_quote! {
+                    #field_ty: ::std::default::Default
+                });
+            }
+        }
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let description = &self.description;
+
+        let fields_meta = self.fields.iter().filter_map(|f| {
+            (!f.ignored).then(|| {
+                let f_ty = &f.ty;
+                let f_bh = &f.behavior;
+                let f_name = &f.name;
+                let f_description = &f.description;
+                let f_default = f.default.as_ref().map(|expr| {
+                    quote! {
+                        .default_value(
+                            <#f_ty as
+                             ::juniper::resolve::ToInputValue<#sv, #f_bh>>
+                                ::to_input_value(&{ #expr }),
+                        )
+                    }
+                });
+
+                quote! {
+                    registry.arg_reworked::<
+                        ::juniper::behavior::Coerce<#f_ty>, _,
+                    >(#f_name, type_info)
+                        #f_description
+                        #f_default
+                }
+            })
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::resolve::Type<#inf, #sv, #bh>
+             for #ty #where_clause
+            {
+                fn meta<'__r, '__ti: '__r>(
+                    registry: &mut ::juniper::Registry<'__r, #sv>,
+                    type_info: &'__ti #inf,
+                ) -> ::juniper::meta::MetaType<'__r, #sv>
+                where
+                    #sv: '__r,
+                {
+                    let fields = [#( #fields_meta ),*];
+
+                    registry.register_input_object_with::<
+                        ::juniper::behavior::Coerce<Self>, _, _,
+                    >(&fields, type_info, |meta| {
+                        meta #description
+                    })
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`resolve::TypeName`] trait for this
     /// [GraphQL input object][0].
     ///
@@ -717,6 +897,96 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::InputValue`] trait for
+    /// this [GraphQL input object][0].
+    ///
+    /// [`resolve::InputValue`]: juniper::resolve::InputValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    fn impl_resolve_input_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (sv, generics) = self.mix_scalar_value(generics);
+        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        generics.make_where_clause().predicates.push(parse_quote! {
+            #sv: ::juniper::ScalarValue
+        });
+        for f in self.fields.iter().filter(|f| !f.ignored) {
+            let field_ty = &f.ty;
+            let field_bh = &f.behavior;
+            generics.make_where_clause().predicates.push(parse_quote! {
+                #field_ty: ::juniper::resolve::InputValue<#lt, #sv, #field_bh>
+            });
+        }
+        for f in self.fields.iter().filter(|f| f.needs_default_trait_bound()) {
+            let field_ty = &f.ty;
+            generics.make_where_clause().predicates.push(parse_quote! {
+                #field_ty: ::std::default::Default,
+            });
+        }
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        let fields = self.fields.iter().map(|f| {
+            let field = &f.ident;
+            let field_ty = &f.ty;
+            let field_bh = &f.behavior;
+
+            let constructor = if f.ignored {
+                let expr = f.default.clone().unwrap_or_default();
+
+                quote! { #expr }
+            } else {
+                let name = &f.name;
+
+                let fallback = f.default.as_ref().map_or_else(
+                    || {
+                        quote! {
+                            <#field_ty as ::juniper::resolve::InputValue<#lt, #sv, #field_bh>>
+                                ::try_from_implicit_null()
+                                .map_err(::juniper::IntoFieldError::<#sv>::into_field_error)?
+                        }
+                    },
+                    |expr| quote! { #expr },
+                );
+
+                quote! {
+                    match obj.get(#name) {
+                        ::std::option::Option::Some(v) => {
+                            <#field_ty as ::juniper::resolve::InputValue<#lt, #sv, #field_bh>>
+                                ::try_from_input_value(v)
+                                .map_err(::juniper::IntoFieldError::<#sv>::into_field_error)?
+                        }
+                        ::std::option::Option::None => { #fallback }
+                    }
+                }
+            };
+
+            quote! { #field: { #constructor }, }
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh>
+             for #ty #where_clause
+            {
+                type Error = ::juniper::FieldError<#sv>;
+
+                fn try_from_input_value(
+                    input: &#lt ::juniper::graphql::InputValue<#sv>,
+                ) -> ::std::result::Result<Self, Self::Error> {
+                    let obj = input
+                        .to_object_value()
+                        .ok_or_else(|| ::std::format!(
+                            "Expected input object, found: {}", input,
+                        ))?;
+
+                    ::std::result::Result::Ok(Self {
+                        #( #fields )*
+                    })
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`ToInputValue`] trait for this
     /// [GraphQL input object][0].
     ///
@@ -764,7 +1034,7 @@ impl Definition {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (sv, mut generics) = self.mix_scalar_value(generics);
-        for f in &self.fields {
+        for f in self.fields.iter().filter(|f| !f.ignored) {
             let field_ty = &f.ty;
             let field_bh = &f.behavior;
             generics.make_where_clause().predicates.push(parse_quote! {
@@ -774,12 +1044,12 @@ impl Definition {
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         let fields = self.fields.iter().filter_map(|f| {
-            let field = &f.ident;
-            let field_ty = &f.ty;
-            let field_bh = &f.behavior;
-            let name = &f.name;
-
             (!f.ignored).then(|| {
+                let field = &f.ident;
+                let field_ty = &f.ty;
+                let field_bh = &f.behavior;
+                let name = &f.name;
+
                 quote! {
                     (#name, <#field_ty as
                              ::juniper::resolve::ToInputValue<#sv, #field_bh>>
@@ -973,4 +1243,22 @@ impl Definition {
         generics.params.push(parse_quote! { #sv });
         (sv, generics)
     }
+
+    /// Mixes an [`InputValue`]'s lifetime [`syn::GenericParam`] into the
+    /// provided [`syn::Generics`] and returns it.
+    ///
+    /// [`InputValue`]: juniper::resolve::InputValue
+    fn mix_input_lifetime(
+        &self,
+        mut generics: syn::Generics,
+        sv: &syn::Ident,
+    ) -> (syn::GenericParam, syn::Generics) {
+        let lt: syn::GenericParam = parse_quote! { '__inp };
+        generics.params.push(lt.clone());
+        generics
+            .make_where_clause()
+            .predicates
+            .push(parse_quote! { #sv: #lt });
+        (lt, generics)
+    }
 }
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 316d79eda..2752c4eb2 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -467,9 +467,14 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::graphql::Scalar<#lt, #inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
-                fn assert_scalar() {}
+                fn assert_scalar() {
+                    <Self as ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>>
+                        ::assert_input_type();
+                    <Self as ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>>
+                        ::assert_output_type();
+                }
             }
         }
     }

From 37257934b71c64873c5115e576837f2eeba12f91 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 11 Aug 2022 18:23:46 +0300
Subject: [PATCH 52/58] Some code style corrections [skip ci]

---
 juniper_codegen/src/graphql_enum/mod.rs   | 34 ++++++++++----------
 juniper_codegen/src/graphql_scalar/mod.rs | 38 +++++++++++------------
 2 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index 3f26625f0..9f973edc7 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -475,7 +475,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn assert_input_type() {}
             }
@@ -504,7 +504,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn assert_output_type() {}
             }
@@ -634,8 +634,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::Type<#inf, #sv, #bh>
+             for #ty #where_clause
             {
                 fn meta<'__r, '__ti: '__r>(
                     registry: &mut ::juniper::Registry<'__r, #sv>,
@@ -669,8 +669,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::TypeName<#inf, #bh>
+             for #ty #where_clause
             {
                 fn type_name(_: &#inf) -> &'static str {
                     <Self as ::juniper::reflect::BaseType<#bh>>::NAME
@@ -778,7 +778,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn resolve_value(
                     &self,
@@ -849,7 +849,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn resolve_value_async<'__r>(
                     &'__r self,
@@ -935,7 +935,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 type Error = ::std::string::String;
 
@@ -1035,8 +1035,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::ToInputValue<#sv, #bh>
+             for #ty #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
                     match self {
@@ -1106,23 +1106,23 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
-                #where_clause
+            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
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
                     &[<Self as ::juniper::reflect::BaseType<#bh>>::NAME];
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh>
+             for #ty #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
                     ::juniper::reflect::wrap::SINGULAR;
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 2752c4eb2..568d1dd22 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -408,7 +408,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn assert_input_type() {}
             }
@@ -437,7 +437,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn assert_output_type() {}
             }
@@ -535,8 +535,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::TypeName<#inf, #bh>
+             for #ty #where_clause
             {
                 fn type_name(_: &#inf) -> &'static str {
                     <Self as ::juniper::reflect::BaseType<#bh>>::NAME
@@ -573,8 +573,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::Type<#inf, #sv, #bh>
+             for #ty #where_clause
             {
                 fn meta<'__r, '__ti: '__r>(
                     registry: &mut ::juniper::Registry<'__r, #sv>,
@@ -652,7 +652,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn resolve_value(
                     &self,
@@ -719,7 +719,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 fn resolve_value_async<'__r>(
                     &'__r self,
@@ -782,8 +782,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::ToInputValue<#sv, #bh>
+             for #ty #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
                     #body
@@ -842,7 +842,7 @@ impl Definition {
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh>
-                for #ty #where_clause
+             for #ty #where_clause
             {
                 type Error = #error_ty;
 
@@ -901,8 +901,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::ScalarToken<#sv, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::ScalarToken<#sv, #bh>
+             for #ty #where_clause
             {
                 fn parse_scalar_token(
                     token: ::juniper::parser::ScalarToken<'_>,
@@ -969,23 +969,23 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
-                #where_clause
+            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
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
                     &[<Self as ::juniper::reflect::BaseType<#bh>>::NAME];
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh>
+             for #ty #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
                     ::juniper::reflect::wrap::SINGULAR;

From b3659b88a4a5aef2b4b6a02b2d568709c57e9f6c Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Thu, 11 Aug 2022 19:06:10 +0300
Subject: [PATCH 53/58] Impl objects, vol.1 [skip ci]

---
 juniper_codegen/src/graphql_interface/mod.rs | 22 +++++-----
 juniper_codegen/src/graphql_object/mod.rs    | 33 +++++++-------
 juniper_codegen/src/graphql_union/mod.rs     | 45 +++++++++++++++++++-
 3 files changed, 70 insertions(+), 30 deletions(-)

diff --git a/juniper_codegen/src/graphql_interface/mod.rs b/juniper_codegen/src/graphql_interface/mod.rs
index 832531c2f..6893e9db7 100644
--- a/juniper_codegen/src/graphql_interface/mod.rs
+++ b/juniper_codegen/src/graphql_interface/mod.rs
@@ -395,7 +395,7 @@ impl ToTokens for Definition {
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        //self.impl_reflect().to_tokens(into);
+        self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -1002,15 +1002,15 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
-                #where_clause
+            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
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Types = &[
                     <Self as ::juniper::reflect::BaseType<#bh>>::NAME,
@@ -1019,8 +1019,8 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::Implements<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::Implements<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Types = &[#(
                     <#interfaces as ::juniper::reflect::BaseType<#bh>>::NAME
@@ -1028,16 +1028,16 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh>
+             for #ty #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
                     ::juniper::reflect::wrap::SINGULAR;
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::Fields<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::Fields<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Names = &[#( #fields ),*];
             }
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index de132f899..6a25090a8 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -474,23 +474,23 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
         quote! {
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
-                #where_clause
+            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
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
                     &[<Self as ::juniper::reflect::BaseType<#bh>>::NAME];
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::Implements<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::Implements<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Types = &[#(
                     <#interfaces as ::juniper::reflect::BaseType<#bh>>::NAME
@@ -498,16 +498,16 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh>
+             for #ty #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
                     ::juniper::reflect::wrap::SINGULAR;
             }
 
             #[automatically_derived]
-            impl #impl_gens ::juniper::reflect::Fields<#bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::reflect::Fields<#bh>
+             for #ty #where_clause
             {
                 const NAMES: ::juniper::reflect::Names = &[#( #fields ),*];
             }
@@ -531,9 +531,8 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             .map(|field| {
                 let (f_name, f_ty, f_bh) = (&field.name, &field.ty, &field.behavior);
 
-                let arguments = field
-                    .arguments
-                    .as_ref()
+                let arguments = field.arguments.as_ref();
+                let arguments = arguments
                     .iter()
                     .flat_map(|vec| vec.iter().filter_map(field::MethodArgument::as_regular))
                     .map(|arg| {
@@ -546,11 +545,9 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
                             <#a_ty as ::juniper::reflect::WrappedType<#a_bh>>
                                 ::VALUE,
                         )}
-                    })
-                    .collect::<Vec<_>>();
+                    });
 
                 quote! {
-                    #[allow(deprecated, non_snake_case)]
                     #[automatically_derived]
                     impl #impl_gens ::juniper::reflect::Field<
                         { ::juniper::reflect::fnv1a128(#f_name) }, #bh,
@@ -657,8 +654,8 @@ impl ToTokens for Definition<Query> {
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        //self.impl_reflect().to_tokens(into);
-        //self.impl_reflect_field().to_tokens(into);
+        self.impl_reflect().to_tokens(into);
+        self.impl_reflect_field().to_tokens(into);
         //self.impl_resolve_field_static().to_tokens(into);
     }
 }
diff --git a/juniper_codegen/src/graphql_union/mod.rs b/juniper_codegen/src/graphql_union/mod.rs
index fa585b004..14355511a 100644
--- a/juniper_codegen/src/graphql_union/mod.rs
+++ b/juniper_codegen/src/graphql_union/mod.rs
@@ -315,6 +315,8 @@ impl ToTokens for Definition {
         self.impl_graphql_value_tokens().to_tokens(into);
         self.impl_graphql_value_async_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
+        ////////////////////////////////////////////////////////////////////////
+        self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -610,7 +612,7 @@ impl Definition {
     /// [`WrappedType`]: juniper::macros::reflect::WrappedType
     /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
-    pub(crate) fn impl_reflection_traits_tokens(&self) -> TokenStream {
+    pub(crate)fn impl_reflection_traits_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
         let name = &self.name;
         let variants = self.variants.iter().map(|var| &var.ty);
@@ -645,6 +647,47 @@ impl Definition {
             }
         }
     }
+
+    /// Returns generated code implementing [`reflect::BaseType`],
+    /// [`reflect::BaseSubTypes`] and [`reflect::WrappedType`] traits for this
+    /// [GraphQL union][0].
+    ///
+    /// [`reflect::BaseSubTypes`]: juniper::reflect::BaseSubTypes
+    /// [`reflect::BaseType`]: juniper::reflect::BaseType
+    /// [`reflect::WrappedType`]: juniper::reflect::WrappedType
+    /// [0]: https://spec.graphql.org/October2021#sec-Unions
+    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 =
+                    &[<Self as ::juniper::reflect::BaseType<#bh>>::NAME];
+            }
+
+            #[automatically_derived]
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh>
+             for #ty #where_clause
+            {
+                const VALUE: ::juniper::reflect::WrappedValue =
+                    ::juniper::reflect::wrap::SINGULAR;
+            }
+        }
+    }
 }
 
 /// Definition of [GraphQL union][1] variant for code generation.

From c75d33ae0aea4011d760d8fe994c5bb2f7577e1f Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 29 Aug 2022 12:55:44 +0300
Subject: [PATCH 54/58] Impl field resolving, vol.1

---
 juniper/src/executor/mod.rs                   |  37 +++--
 juniper/src/executor_tests/executor.rs        |   4 +-
 .../src/executor_tests/interfaces_unions.rs   |  36 ++---
 juniper/src/extract.rs                        |   9 ++
 juniper/src/lib.rs                            |   2 +
 juniper/src/resolve/mod.rs                    |  80 ++++++++++-
 juniper/src/types/base.rs                     |  35 +++++
 juniper_codegen/src/graphql_object/mod.rs     | 132 +++++++++++++++++-
 juniper_codegen/src/graphql_union/attr.rs     |   2 +
 juniper_codegen/src/graphql_union/derive.rs   |   3 +
 juniper_codegen/src/graphql_union/mod.rs      |  91 +++++++++++-
 11 files changed, 384 insertions(+), 47 deletions(-)
 create mode 100644 juniper/src/extract.rs

diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 36076455e..cd550d7bb 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -89,6 +89,35 @@ impl<'r, 'a, CX: ?Sized, SV> Executor<'r, 'a, CX, SV> {
     pub(crate) fn current_type_reworked(&self) -> &TypeType<'a, SV> {
         &self.current_type
     }
+
+    /// Resolves the specified single arbitrary `Type` `value` as
+    /// [`graphql::Value`].
+    ///
+    /// # Errors
+    ///
+    /// Whenever [`Type::resolve_value()`] errors.
+    ///
+    /// [`graphql::Value`]: crate::graphql::Value
+    /// [`Type::resolve_value()`]: resolve::Value::resolve_value
+    pub fn resolve_value<BH, Type, TI>(&self, value: &Type, type_info: &TI) -> ExecutionResult<SV>
+    where
+        Type: resolve::Value<TI, CX, SV, BH> + ?Sized,
+        TI: ?Sized,
+        BH: ?Sized,
+    {
+        value.resolve_value(self.current_selection_set, type_info, self)
+    }
+
+    /// Returns the current context of this [`Executor`].
+    ///
+    /// Context is usually provided when the top-level [`execute()`] function is
+    /// called.
+    ///
+    /// [`execute()`]: crate::execute
+    #[must_use]
+    pub fn context(&self) -> &'r CX {
+        self.context
+    }
 }
 
 /// Error type for errors that occur during query execution
@@ -635,14 +664,6 @@ where
         self.current_selection_set
     }
 
-    /// Access the current context
-    ///
-    /// You usually provide the context when calling the top-level `execute`
-    /// function, or using the context factory in the Iron integration.
-    pub fn context(&self) -> &'r CtxT {
-        self.context
-    }
-
     /// The currently executing schema
     pub fn schema(&self) -> &'a SchemaType<S> {
         self.schema
diff --git a/juniper/src/executor_tests/executor.rs b/juniper/src/executor_tests/executor.rs
index 06d93fc0e..088974187 100644
--- a/juniper/src/executor_tests/executor.rs
+++ b/juniper/src/executor_tests/executor.rs
@@ -369,6 +369,8 @@ mod threads_context_correctly {
     }
 }
 
+// TODO: Remove as should be unnecessary with generic context.
+/*
 mod dynamic_context_switching {
     use indexmap::IndexMap;
 
@@ -672,7 +674,7 @@ mod dynamic_context_switching {
         assert_eq!(result, graphql_value!({"first": {"value": "First value"}}));
     }
 }
-
+*/
 mod propagates_errors_to_nullable_fields {
     use crate::{
         executor::{ExecutionError, FieldError, FieldResult, IntoFieldError},
diff --git a/juniper/src/executor_tests/interfaces_unions.rs b/juniper/src/executor_tests/interfaces_unions.rs
index 3e9fccf43..9b8ac7469 100644
--- a/juniper/src/executor_tests/interfaces_unions.rs
+++ b/juniper/src/executor_tests/interfaces_unions.rs
@@ -96,19 +96,15 @@ mod interface {
 
 mod union {
     use crate::{
-        graphql_object, graphql_union, graphql_value,
+        graphql_object, GraphQLUnion, graphql_value,
         schema::model::RootNode,
         types::scalars::{EmptyMutation, EmptySubscription},
     };
 
-    #[graphql_union]
-    trait Pet {
-        fn as_dog(&self) -> Option<&Dog> {
-            None
-        }
-        fn as_cat(&self) -> Option<&Cat> {
-            None
-        }
+    #[derive(GraphQLUnion)]
+    enum Pet {
+        Dog(Dog),
+        Cat(Cat),
     }
 
     struct Dog {
@@ -116,12 +112,6 @@ mod union {
         woofs: bool,
     }
 
-    impl Pet for Dog {
-        fn as_dog(&self) -> Option<&Dog> {
-            Some(self)
-        }
-    }
-
     #[graphql_object]
     impl Dog {
         fn name(&self) -> &str {
@@ -137,12 +127,6 @@ mod union {
         meows: bool,
     }
 
-    impl Pet for Cat {
-        fn as_cat(&self) -> Option<&Cat> {
-            Some(self)
-        }
-    }
-
     #[graphql_object]
     impl Cat {
         fn name(&self) -> &str {
@@ -154,13 +138,13 @@ mod union {
     }
 
     struct Schema {
-        pets: Vec<Box<dyn Pet + Send + Sync>>,
+        pets: Vec<Pet>,
     }
 
     #[graphql_object]
     impl Schema {
-        fn pets(&self) -> Vec<&(dyn Pet + Send + Sync)> {
-            self.pets.iter().map(|p| p.as_ref()).collect()
+        fn pets(&self) -> &[Pet] {
+            &self.pets
         }
     }
 
@@ -169,11 +153,11 @@ mod union {
         let schema = RootNode::new(
             Schema {
                 pets: vec![
-                    Box::new(Dog {
+                    Pet::Dog(Dog {
                         name: "Odie".into(),
                         woofs: true,
                     }),
-                    Box::new(Cat {
+                    Pet::Cat(Cat {
                         name: "Garfield".into(),
                         meows: false,
                     }),
diff --git a/juniper/src/extract.rs b/juniper/src/extract.rs
new file mode 100644
index 000000000..3b02845b5
--- /dev/null
+++ b/juniper/src/extract.rs
@@ -0,0 +1,9 @@
+pub trait Extract<T: ?Sized> {
+    fn extract(&self) -> &T;
+}
+
+impl<T: ?Sized> Extract<T> for T {
+    fn extract(&self) -> &Self {
+        self
+    }
+}
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index a40e1bf81..9271f8d47 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -33,6 +33,7 @@ pub mod macros;
 mod ast;
 pub mod behavior;
 pub mod executor;
+pub mod extract;
 pub mod graphql;
 pub mod http;
 pub mod integrations;
@@ -94,6 +95,7 @@ pub use crate::{
     },
     validation::RuleError,
     value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value},
+    extract::Extract,
 };
 
 /// An error that prevented query execution
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 7c7e5c191..cdab181c3 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -2,8 +2,10 @@ use crate::{
     behavior, graphql,
     meta::MetaType,
     parser::{self, ParseError},
-    reflect, Arguments, BoxFuture, ExecutionResult, Executor, IntoFieldError, Registry, Selection,
+    reflect, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, IntoFieldError,
+    Registry, Selection,
 };
+use juniper::resolve;
 
 pub trait Type<TypeInfo: ?Sized, ScalarValue, Behavior: ?Sized = behavior::Standard> {
     fn meta<'r, 'ti: 'r>(
@@ -110,9 +112,9 @@ pub trait StaticField<
 {
     fn resolve_static_field(
         &self,
-        arguments: &Arguments<ScalarValue>,
+        arguments: &Arguments<'_, ScalarValue>,
         type_info: &TypeInfo,
-        executor: &Executor<Context, ScalarValue>,
+        executor: &Executor<'_, '_, Context, ScalarValue>,
     ) -> ExecutionResult<ScalarValue>;
 }
 
@@ -202,3 +204,75 @@ pub trait InputValueAsRef<ScalarValue, Behavior: ?Sized = behavior::Standard> {
 pub trait ScalarToken<ScalarValue, Behavior: ?Sized = behavior::Standard> {
     fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<ScalarValue, ParseError>;
 }
+
+/*
+pub trait IntoResolvable<
+    ScalarValue,
+>
+{
+    type Type;
+
+    fn into_resolvable(self) -> FieldResult<Self::Type, ScalarValue>;
+}
+
+impl<T, SV> IntoResolvable<SV> for T
+where
+    T: crate::GraphQLValue<SV>,
+    SV: crate::ScalarValue,
+{
+    type Type = Self;
+
+    fn into_resolvable(self) -> FieldResult<Self, SV> {
+        Ok(self)
+    }
+}
+
+impl<T, E, SV> IntoResolvable<SV> for Result<T, E>
+where
+    T: crate::GraphQLValue<SV>,
+    SV: crate::ScalarValue,
+    E: IntoFieldError<SV>,
+{
+    type Type = T;
+
+    fn into_resolvable(self) -> FieldResult<Self::Type, SV> {
+        self.map_err(IntoFieldError::into_field_error)
+    }
+}
+*/
+
+#[doc(hidden)]
+pub trait IntoResolvable<S, T>
+where
+    T: crate::GraphQLValue<S>,
+    S: crate::ScalarValue,
+{
+    type Type;
+
+    #[doc(hidden)]
+    fn into_resolvable(self) -> FieldResult<T, S>;
+}
+
+impl<'a, S, T> IntoResolvable<S, T> for T
+where
+    T: crate::GraphQLValue<S>,
+    S: crate::ScalarValue,
+{
+    type Type = T;
+
+    fn into_resolvable(self) -> FieldResult<T, S> {
+        Ok(self)
+    }
+}
+
+impl<'a, S, T, E: IntoFieldError<S>> IntoResolvable<S, T> for Result<T, E>
+where
+    S: crate::ScalarValue,
+    T: crate::GraphQLValue<S>,
+{
+    type Type = T;
+
+    fn into_resolvable(self) -> FieldResult<T, S> {
+        self.map_err(IntoFieldError::into_field_error)
+    }
+}
diff --git a/juniper/src/types/base.rs b/juniper/src/types/base.rs
index 9d54fee08..aab0c6df4 100644
--- a/juniper/src/types/base.rs
+++ b/juniper/src/types/base.rs
@@ -4,6 +4,7 @@ use crate::{
     ast::{Directive, FromInputValue, InputValue, Selection},
     executor::{ExecutionResult, Executor, Registry, Variables},
     parser::Spanning,
+    resolve,
     schema::meta::{Argument, MetaType},
     value::{DefaultScalarValue, Object, ScalarValue, Value},
     FieldResult, GraphQLEnum, IntoFieldError,
@@ -98,6 +99,8 @@ impl<'a, S> Arguments<'a, S> {
         Self { args }
     }
 
+    /// TODO: DEPRECATED!
+    ///
     /// Gets an argument by the given `name` and converts it into the desired
     /// type.
     ///
@@ -121,6 +124,38 @@ impl<'a, S> Arguments<'a, S> {
             .transpose()
             .map_err(IntoFieldError::into_field_error)
     }
+
+    /// Resolves an argument with the provided `name` as the specified type `T`.
+    ///
+    /// If [`None`] argument is found, then `T` is
+    /// [tried to be resolved from implicit `null`][0].
+    ///
+    /// # Errors
+    ///
+    /// If the [`resolve::InputValue`] conversion fails.
+    ///
+    /// [0]: resolve::InputValue::try_from_implicit_null
+    pub fn resolve<'s, T, BH>(&'s self, name: &str) -> FieldResult<T, S>
+    where
+        T: resolve::InputValue<'s, S, BH>,
+        BH: ?Sized,
+    {
+        self.args
+            .as_ref()
+            .and_then(|args| args.get(name))
+            .map(<T as resolve::InputValue<'s, S, BH>>::try_from_input_value)
+            .transpose()
+            .map_err(IntoFieldError::into_field_error)?
+            .map_or_else(
+                || {
+                    <T as resolve::InputValue<'s, S, BH>>::try_from_implicit_null().map_err(|e| {
+                        IntoFieldError::into_field_error(e)
+                            .map_message(|m| format!("Missing argument `{name}`: {m}"))
+                    })
+                },
+                Ok,
+            )
+    }
 }
 
 /// Primary trait used to resolve GraphQL values.
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index 125bc5e24..5e01d322c 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -352,11 +352,36 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
     /// Returns prepared self [`syn::Type`] and [`syn::Generics`] for a trait
     /// implementation.
-    #[must_use]
     fn ty_and_generics(&self) -> (&syn::Type, syn::Generics) {
         (&self.ty, self.generics.clone())
     }
 
+    /// Mixes a type info [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`syn::Ident`].
+    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let ty = parse_quote! { __TypeInfo };
+        generics.params.push(parse_quote! { #ty: ?Sized });
+        (ty, generics)
+    }
+
+    /// Mixes a context [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns its [`syn::Ident`].
+    fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let ty = parse_quote! { __Context };
+        generics.params.push(parse_quote! { #ty: ?Sized });
+        (ty, generics)
+    }
+
+    /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
+    /// [`syn::Generics`] and returns it.
+    ///
+    /// [`ScalarValue`]: juniper::ScalarValue
+    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+        let sv = parse_quote! { __ScalarValue };
+        generics.params.push(parse_quote! { #sv });
+        (sv, generics)
+    }
+
     /// Returns generated code implementing [`marker::IsOutputType`] trait for
     /// this [GraphQL object][1].
     ///
@@ -574,7 +599,108 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             })
             .collect()
     }
+/*
+    /// Returns generated code implementing [`resolve::StaticField`] trait for
+    /// each [field][1] of this [GraphQL object][0].
+    ///
+    /// [`resolve::StaticField`]: juniper::resolve::StaticField
+    /// [0]: https://spec.graphql.org/October2021#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    #[must_use]
+    pub(crate) fn impl_resolve_static_field(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = self.mix_type_info(generics);
+        let (cx, generics) = self.mix_context(generics);
+        let (sv, generics) = self.mix_scalar_value(generics);
+
+        self.fields
+            .iter()
+            .map(|field| {
+                let mut generics = generics.clone();
+                let (f_name, f_bh) = (&field.name, &field.behavior);
+                let (f_ident, f_ty) = (&field.ident, &field.ty);
+
+                let body = if !field.is_async {
+                    generics.make_where_clause().predicates.push(parse_quote! {
+                        #f_ty: ::juniper::resolve::Value<#inf, #cx, #sv, #f_bh>
+                    });
+
+                    let res = if field.is_method() {
+                        let args = field.arguments.as_ref().unwrap().iter().map(|arg| {
+                            match arg {
+                                field::MethodArgument::Regular(arg) => {
+                                    let (a_ty, a_bh) = (&arg.ty, &arg.behavior);
+                                    generics.make_where_clause().predicates.push(parse_quote! {
+                                        #a_ty: ::juniper::resolve::InputValueOwned<#sv, #a_bh>
+                                    });
+                                    quote! {
+                                        args.resolve::<#a_ty, #a_bh>(#name)?
+                                    }
+                                }
+                                field::MethodArgument::Context(cx_ty) => {
+                                    generics.make_where_clause().predicates.push(parse_quote! {
+                                        #cx: ::juniper::Extract<#cx_ty>
+                                    });
+                                    quote! {
+                                        <#cx as ::juniper::Extract<#cx_ty>>
+                                            ::extract(executor.context())
+                                    }
+                                }
+                                field::MethodArgument::Executor => {
+                                    quote! {
+                                        executor
+                                    }
+                                }
+                            }
+                        });
+
+                        let rcv = field.has_receiver.then(|| {
+                            quote! { self, }
+                        });
 
+                        quote! { Self::#ident(#rcv #( #args ),*) }
+                    } else {
+                        quote! {
+                            &self.#f_ident
+                        }
+                    };
+
+                    quote! {
+                        executor.resolve_value::<#f_bh, _, _>(#res, type_info)
+                    }
+                } else {
+                    quote! {
+                        ::std::panic!(
+                             "Tried to resolve async field `{}` on type `{}` with a sync resolver",
+                             #f_name,
+                             <Self as ::juniper::reflect::BaseType<#bh>>::NAME,
+                         );
+                    }
+                };
+
+                let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+                quote! {
+                    #[automatically_derived]
+                    impl #impl_gens ::juniper::resolve::StaticField<
+                        { ::juniper::reflect::fnv1a128(#f_name) },
+                        #inf, #cx, #sv, #bh,
+                    > for #ty #where_clause {
+                        fn resolve_static_field(
+                            &self,
+                            args: &::juniper::Arguments<'_, #sv>,
+                            type_info: &#inf,
+                            executor: &::juniper::Executor<'_, '_, #cx, #sv>,
+                        ) -> ::juniper::ExecutionResult<#sv> {
+                            #body
+                        }
+                    }
+                }
+            })
+            .collect()
+    }
+*/
     /// Returns generated code implementing [`GraphQLType`] trait for this
     /// [GraphQL object][1].
     ///
@@ -655,8 +781,8 @@ impl ToTokens for Definition<Query> {
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
         self.impl_reflect().to_tokens(into);
-        //self.impl_reflect_field().to_tokens(into);
-        //self.impl_resolve_field_static().to_tokens(into);
+        self.impl_reflect_field().to_tokens(into);
+        //self.impl_resolve_static_field().to_tokens(into);
     }
 }
 
diff --git a/juniper_codegen/src/graphql_union/attr.rs b/juniper_codegen/src/graphql_union/attr.rs
index 006ad2263..a07ac78ee 100644
--- a/juniper_codegen/src/graphql_union/attr.rs
+++ b/juniper_codegen/src/graphql_union/attr.rs
@@ -93,6 +93,7 @@ fn expand_on_trait(
         description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar: scalar::Type::parse(attr.scalar.as_deref(), &ast.generics),
+        behavior: attr.behavior.into(),
         generics: ast.generics.clone(),
         variants,
     };
@@ -210,6 +211,7 @@ fn parse_variant_from_trait_method(
         ty,
         resolver_code,
         resolver_check,
+        behavior: attr.behavior.into(),
         context: method_context_ty,
     })
 }
diff --git a/juniper_codegen/src/graphql_union/derive.rs b/juniper_codegen/src/graphql_union/derive.rs
index a10be60cc..0a2818c2b 100644
--- a/juniper_codegen/src/graphql_union/derive.rs
+++ b/juniper_codegen/src/graphql_union/derive.rs
@@ -84,6 +84,7 @@ fn expand_enum(ast: syn::DeriveInput) -> syn::Result<Definition> {
             .map(SpanContainer::into_inner)
             .unwrap_or_else(|| parse_quote! { () }),
         scalar: scalar::Type::parse(attr.scalar.as_deref(), &ast.generics),
+        behavior: attr.behavior.into(),
         generics: ast.generics,
         variants,
     })
@@ -163,6 +164,7 @@ fn parse_variant_from_enum_variant(
         ty,
         resolver_code,
         resolver_check,
+        behavior: attr.behavior.into(),
         context: None,
     })
 }
@@ -214,6 +216,7 @@ fn expand_struct(ast: syn::DeriveInput) -> syn::Result<Definition> {
             .map(SpanContainer::into_inner)
             .unwrap_or_else(|| parse_quote! { () }),
         scalar: scalar::Type::parse(attr.scalar.as_deref(), &ast.generics),
+        behavior: attr.behavior.into(),
         generics: ast.generics,
         variants,
     })
diff --git a/juniper_codegen/src/graphql_union/mod.rs b/juniper_codegen/src/graphql_union/mod.rs
index df162fdd0..ff21e3c6d 100644
--- a/juniper_codegen/src/graphql_union/mod.rs
+++ b/juniper_codegen/src/graphql_union/mod.rs
@@ -18,7 +18,7 @@ use syn::{
 };
 
 use crate::common::{
-    filter_attrs, gen,
+    filter_attrs, gen, behavior,
     parse::{
         attr::{err, OptionExt as _},
         ParseBufferExt as _,
@@ -74,6 +74,17 @@ struct Attr {
     /// [1]: https://spec.graphql.org/October2021#sec-Unions
     scalar: Option<SpanContainer<scalar::AttrValue>>,
 
+    /// Explicitly specified type of the custom [`Behavior`] to parametrize this
+    /// [GraphQL union][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-Unions
+    behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified external resolver functions for [GraphQL union][1]
     /// variants.
     ///
@@ -128,6 +139,13 @@ impl Parse for Attr {
                         .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "on" => {
                     let ty = input.parse::<syn::Type>()?;
                     input.parse::<token::Eq>()?;
@@ -160,6 +178,7 @@ impl Attr {
             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),
             external_resolvers: try_merge_hashmap!(
                 external_resolvers: self, another => span_joined
             ),
@@ -188,6 +207,19 @@ impl Attr {
 /// [1]: https://spec.graphql.org/October2021#sec-Unions
 #[derive(Debug, Default)]
 struct VariantAttr {
+    /// Explicitly specified type of the custom [`Behavior`] this
+    /// [GraphQL union][0] member implementation is parametrized with, to
+    /// [coerce] in the generated code from.
+    ///
+    /// 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-Unions
+    /// [coerce]: juniper::behavior::Coerce
+    behavior: Option<SpanContainer<behavior::Type>>,
+
     /// Explicitly specified marker for the variant/field being ignored and not
     /// included into [GraphQL union][1].
     ///
@@ -210,6 +242,13 @@ impl Parse for VariantAttr {
         while !input.is_empty() {
             let ident = input.parse::<syn::Ident>()?;
             match ident.to_string().as_str() {
+                "behave" | "behavior" => {
+                    input.parse::<token::Eq>()?;
+                    let bh = input.parse::<behavior::Type>()?;
+                    out.behavior
+                        .replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
                 "ignore" | "skip" => out
                     .ignore
                     .replace(SpanContainer::new(ident.span(), None, ident.clone()))
@@ -236,6 +275,7 @@ impl VariantAttr {
     /// duplicates, if any.
     fn try_merge(self, mut another: Self) -> syn::Result<Self> {
         Ok(Self {
+            behavior: try_merge_opt!(behavior: self, another),
             ignore: try_merge_opt!(ignore: self, another),
             external_resolver: try_merge_opt!(external_resolver: self, another),
         })
@@ -301,6 +341,13 @@ struct Definition {
     /// [1]: https://spec.graphql.org/October2021#sec-Unions
     scalar: scalar::Type,
 
+    /// [`Behavior`] parametrization to generate code with for this
+    /// [GraphQL union][0].
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Unions
+    behavior: behavior::Type,
+
     /// Variants definitions of this [GraphQL union][1].
     ///
     /// [1]: https://spec.graphql.org/October2021#sec-Unions
@@ -316,7 +363,7 @@ impl ToTokens for Definition {
         self.impl_graphql_value_async_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        //self.impl_reflect().to_tokens(into);
+        self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -647,7 +694,7 @@ impl Definition {
             }
         }
     }
-    /*
+
     /// Returns generated code implementing [`reflect::BaseType`],
     /// [`reflect::BaseSubTypes`] and [`reflect::WrappedType`] traits for this
     /// [GraphQL union][0].
@@ -663,6 +710,15 @@ impl Definition {
 
         let name = &self.name;
 
+        let member_names = self.variants.iter().map(|m| {
+            let m_ty = &m.ty;
+            let m_bh = &m.behavior;
+
+            quote! {
+                <#m_ty as ::juniper::reflect::BaseType<#m_bh>>::NAME
+            }
+        });
+
         quote! {
             #[automatically_derived]
             impl #impl_gens ::juniper::reflect::BaseType<#bh>
@@ -675,8 +731,10 @@ impl Definition {
             impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh>
              for #ty #where_clause
             {
-                const NAMES: ::juniper::reflect::Types =
-                    &[<Self as ::juniper::reflect::BaseType<#bh>>::NAME];
+                const NAMES: ::juniper::reflect::Types = &[
+                    <Self as ::juniper::reflect::BaseType<#bh>>::NAME,
+                    #( #member_names ),*
+                ];
             }
 
             #[automatically_derived]
@@ -687,7 +745,19 @@ impl Definition {
                     ::juniper::reflect::wrap::SINGULAR;
             }
         }
-    }*/
+    }
+
+    /// Returns prepared self [`syn::Type`] and [`syn::Generics`] for a trait
+    /// implementation.
+    fn ty_and_generics(&self) -> (syn::Type, syn::Generics) {
+        let generics = self.generics.clone();
+        let ty = {
+            let ident = &self.ty;
+            let (_, ty_gen, _) = generics.split_for_impl();
+            parse_quote! { #ident #ty_gen }
+        };
+        (ty, generics)
+    }
 }
 
 /// Definition of [GraphQL union][1] variant for code generation.
@@ -710,6 +780,14 @@ struct VariantDefinition {
     /// [1]: https://spec.graphql.org/October2021#sec-Unions
     resolver_check: syn::Expr,
 
+    /// [`Behavior`] parametrization of this [GraphQL union][0] member
+    /// implementation to [coerce] from in the generated code.
+    ///
+    /// [`Behavior`]: juniper::behavior
+    /// [0]: https://spec.graphql.org/October2021#sec-Unions
+    /// [coerce]: juniper::behavior::Coerce
+    behavior: behavior::Type,
+
     /// Rust type of [`Context`] that this [GraphQL union][1] variant requires
     /// for resolution.
     ///
@@ -826,6 +904,7 @@ fn emerge_union_variants_from_attr(
                 ty,
                 resolver_code,
                 resolver_check,
+                behavior: behavior::Type::default(), // TODO: remove at all
                 context: None,
             })
         }

From 129ff559d19bb05be903f002b7f884d0655727b3 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Fri, 9 Sep 2022 14:39:32 +0300
Subject: [PATCH 55/58] Impl fields resolving, vol.3 [skip ci]

---
 juniper_codegen/src/common/gen.rs             |  76 +++++-
 juniper_codegen/src/graphql_enum/mod.rs       | 117 ++-------
 .../src/graphql_input_object/mod.rs           |  62 +----
 juniper_codegen/src/graphql_interface/mod.rs  |  32 +++
 juniper_codegen/src/graphql_object/mod.rs     | 243 ++++++++++--------
 juniper_codegen/src/graphql_scalar/mod.rs     | 100 ++-----
 juniper_codegen/src/graphql_union/mod.rs      |  32 +++
 7 files changed, 325 insertions(+), 337 deletions(-)

diff --git a/juniper_codegen/src/common/gen.rs b/juniper_codegen/src/common/gen.rs
index a0b5e7315..57bf3f993 100644
--- a/juniper_codegen/src/common/gen.rs
+++ b/juniper_codegen/src/common/gen.rs
@@ -1,7 +1,81 @@
 //! Common code generated parts, used by this crate.
 
 use proc_macro2::TokenStream;
-use quote::quote;
+use quote::{quote, ToTokens};
+use syn::parse_quote;
+
+use crate::common::{behavior};
+
+/// Returns generated code implementing [`resolve::Resolvable`] trait for the
+/// provided [`syn::Type`] with its [`syn::Generics`].
+///
+/// [`resolve::Resolvable`]: juniper::resolve::Resolvable
+/// [0]: https://spec.graphql.org/October2021#sec-Interfaces
+pub(crate) fn impl_resolvable(
+    bh: &behavior::Type,
+    (ty, generics): (syn::Type, syn::Generics),
+) -> TokenStream {
+    let (sv, generics) = mix_scalar_value(generics);
+    let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+    quote! {
+        #[automatically_derived]
+        impl #impl_gens ::juniper::resolve::Resolvable<#sv, #bh>
+         for #ty #where_clause
+        {
+            type Value = Self;
+
+            fn into_value(self) -> ::juniper::FieldResult<Self, #sv> {
+                ::juniper::FieldResult::Ok(self)
+            }
+        }
+    }
+}
+
+/// Mixes a type info [`syn::GenericParam`] into the provided [`syn::Generics`]
+/// and returns its [`syn::Ident`].
+#[must_use]
+pub(crate) fn mix_type_info(mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+    let ty = parse_quote! { __TypeInfo };
+    generics.params.push(parse_quote! { #ty: ?Sized });
+    (ty, generics)
+}
+
+/// Mixes a context [`syn::GenericParam`] into the provided [`syn::Generics`]
+/// and returns its [`syn::Ident`].
+pub(crate) fn mix_context(mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+    let ty = parse_quote! { __Context };
+    generics.params.push(parse_quote! { #ty: ?Sized });
+    (ty, generics)
+}
+
+/// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
+/// [`syn::Generics`] and returns it.
+///
+/// [`ScalarValue`]: juniper::ScalarValue
+pub(crate) fn mix_scalar_value(mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
+    let sv = parse_quote! { __ScalarValue };
+    generics.params.push(parse_quote! { #sv });
+    (sv, generics)
+}
+
+/// Mixes an [`InputValue`]'s lifetime [`syn::GenericParam`] into the provided
+/// [`syn::Generics`] and returns it.
+///
+/// [`InputValue`]: juniper::resolve::InputValue
+#[must_use]
+pub(crate) fn mix_input_lifetime(
+    mut generics: syn::Generics,
+    sv: impl ToTokens,
+) -> (syn::GenericParam, syn::Generics) {
+    let lt: syn::GenericParam = parse_quote! { '__inp };
+    generics.params.push(lt.clone());
+    generics
+        .make_where_clause()
+        .predicates
+        .push(parse_quote! { #sv: #lt });
+    (lt, generics)
+}
 
 /// Generate the code resolving some [GraphQL type][1] in a synchronous manner.
 ///
diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index 2fe21f7cd..4718cd87d 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -15,7 +15,7 @@ use syn::{
 };
 
 use crate::common::{
-    behavior, deprecation, filter_attrs,
+    behavior, deprecation, filter_attrs, gen,
     parse::{
         attr::{err, OptionExt as _},
         ParseBufferExt as _,
@@ -417,7 +417,7 @@ impl ToTokens for Definition {
         self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_value().to_tokens(into);
         self.impl_resolve_value_async().to_tokens(into);
-        self.impl_resolvable().to_tokens(into);
+        gen::impl_resolvable(&self.behavior, self.ty_and_generics()).to_tokens(into);
         self.impl_resolve_to_input_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_graphql_input_type().to_tokens(into);
@@ -463,9 +463,9 @@ impl Definition {
     fn impl_graphql_input_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, &sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::resolve::Type<#inf, #sv, #bh>
                   + ::juniper::resolve::ToInputValue<#sv, #bh>
@@ -492,9 +492,9 @@ impl Definition {
     fn impl_graphql_output_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
-        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, mut generics) = gen::mix_scalar_value(generics);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::resolve::Type<#inf, #sv, #bh>
                   + ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
@@ -521,10 +521,10 @@ impl Definition {
     fn impl_graphql_enum(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, &sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
                   + ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
@@ -608,8 +608,8 @@ impl Definition {
     fn impl_resolve_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (sv, mut generics) = gen::mix_scalar_value(generics);
         let preds = &mut generics.make_where_clause().predicates;
         preds.push(parse_quote! { #sv: Clone });
         preds.push(parse_quote! {
@@ -665,7 +665,7 @@ impl Definition {
     fn impl_resolve_type_name(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
@@ -746,9 +746,9 @@ impl Definition {
     fn impl_resolve_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
-        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, mut generics) = gen::mix_scalar_value(generics);
         generics.make_where_clause().predicates.push(parse_quote! {
             #sv: From<String>
         });
@@ -835,9 +835,9 @@ impl Definition {
     fn impl_resolve_value_async(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
-        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, mut generics) = gen::mix_scalar_value(generics);
         let preds = &mut generics.make_where_clause().predicates;
         preds.push(parse_quote! {
             Self: ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
@@ -869,31 +869,6 @@ impl Definition {
         }
     }
 
-    /// Returns generated code implementing [`resolve::Resolvable`] trait for
-    /// this [GraphQL enum][0].
-    ///
-    /// [`resolve::Resolvable`]: juniper::resolve::Resolvable
-    /// [0]: https://spec.graphql.org/October2021#sec-Enums
-    fn impl_resolvable(&self) -> TokenStream {
-        let bh = &self.behavior;
-        let (ty, generics) = self.ty_and_generics();
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (impl_gens, _, where_clause) = generics.split_for_impl();
-
-        quote! {
-            #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::Resolvable<#sv, #bh>
-             for #ty #where_clause
-            {
-                type Value = Self;
-
-                fn into_value(self) -> ::juniper::FieldResult<Self, #sv> {
-                    ::juniper::FieldResult::Ok(self)
-                }
-            }
-        }
-    }
-
     /// Returns generated code implementing [`FromInputValue`] trait for this
     /// [GraphQL enum][0].
     ///
@@ -941,8 +916,8 @@ impl Definition {
     fn impl_resolve_input_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, &sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             #sv: ::juniper::ScalarValue
         });
@@ -1035,7 +1010,7 @@ impl Definition {
     fn impl_resolve_to_input_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let (sv, mut generics) = gen::mix_scalar_value(generics);
         generics.make_where_clause().predicates.push(parse_quote! {
             #sv: From<String>
         });
@@ -1226,48 +1201,4 @@ impl Definition {
         };
         (ty, generics)
     }
-
-    /// Mixes a type info [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`syn::Ident`].
-    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __TypeInfo };
-        generics.params.push(parse_quote! { #ty: ?Sized });
-        (ty, generics)
-    }
-
-    /// Mixes a context [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`syn::Ident`].
-    fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __Context };
-        generics.params.push(parse_quote! { #ty: ?Sized });
-        (ty, generics)
-    }
-
-    /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns it.
-    ///
-    /// [`ScalarValue`]: juniper::ScalarValue
-    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let sv = parse_quote! { __ScalarValue };
-        generics.params.push(parse_quote! { #sv });
-        (sv, generics)
-    }
-
-    /// Mixes an [`InputValue`]'s lifetime [`syn::GenericParam`] into the
-    /// provided [`syn::Generics`] and returns it.
-    ///
-    /// [`InputValue`]: juniper::resolve::InputValue
-    fn mix_input_lifetime(
-        &self,
-        mut generics: syn::Generics,
-        sv: &syn::Ident,
-    ) -> (syn::GenericParam, syn::Generics) {
-        let lt: syn::GenericParam = parse_quote! { '__inp };
-        generics.params.push(lt.clone());
-        generics
-            .make_where_clause()
-            .predicates
-            .push(parse_quote! { #sv: #lt });
-        (lt, generics)
-    }
 }
diff --git a/juniper_codegen/src/graphql_input_object/mod.rs b/juniper_codegen/src/graphql_input_object/mod.rs
index 0d72a0ddd..c339b4346 100644
--- a/juniper_codegen/src/graphql_input_object/mod.rs
+++ b/juniper_codegen/src/graphql_input_object/mod.rs
@@ -15,7 +15,7 @@ use syn::{
 };
 
 use crate::common::{
-    behavior, default, filter_attrs,
+    behavior, default, filter_attrs, gen,
     parse::{
         attr::{err, OptionExt as _},
         ParseBufferExt as _,
@@ -520,9 +520,9 @@ impl Definition {
     fn impl_graphql_input_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, &sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::resolve::Type<#inf, #sv, #bh>
                   + ::juniper::resolve::ToInputValue<#sv, #bh>
@@ -572,9 +572,9 @@ impl Definition {
     fn impl_graphql_input_object(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, &sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
         });
@@ -661,8 +661,8 @@ impl Definition {
     fn impl_resolve_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (sv, mut generics) = gen::mix_scalar_value(generics);
         let preds = &mut generics.make_where_clause().predicates;
         preds.push(parse_quote! { #sv: Clone });
         preds.push(parse_quote! {
@@ -751,7 +751,7 @@ impl Definition {
     fn impl_resolve_type_name(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
@@ -905,8 +905,8 @@ impl Definition {
     fn impl_resolve_input_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, &sv);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, &sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             #sv: ::juniper::ScalarValue
         });
@@ -1033,7 +1033,7 @@ impl Definition {
     fn impl_resolve_to_input_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (sv, mut generics) = self.mix_scalar_value(generics);
+        let (sv, mut generics) = gen::mix_scalar_value(generics);
         for f in self.fields.iter().filter(|f| !f.ignored) {
             let field_ty = &f.ty;
             let field_bh = &f.behavior;
@@ -1225,40 +1225,4 @@ impl Definition {
         };
         (ty, generics)
     }
-
-    /// Mixes a type info [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`syn::Ident`].
-    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __TypeInfo };
-        generics.params.push(parse_quote! { #ty: ?Sized });
-        (ty, generics)
-    }
-
-    /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns it.
-    ///
-    /// [`ScalarValue`]: juniper::ScalarValue
-    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let sv = parse_quote! { __ScalarValue };
-        generics.params.push(parse_quote! { #sv });
-        (sv, generics)
-    }
-
-    /// Mixes an [`InputValue`]'s lifetime [`syn::GenericParam`] into the
-    /// provided [`syn::Generics`] and returns it.
-    ///
-    /// [`InputValue`]: juniper::resolve::InputValue
-    fn mix_input_lifetime(
-        &self,
-        mut generics: syn::Generics,
-        sv: &syn::Ident,
-    ) -> (syn::GenericParam, syn::Generics) {
-        let lt: syn::GenericParam = parse_quote! { '__inp };
-        generics.params.push(lt.clone());
-        generics
-            .make_where_clause()
-            .predicates
-            .push(parse_quote! { #sv: #lt });
-        (lt, generics)
-    }
 }
diff --git a/juniper_codegen/src/graphql_interface/mod.rs b/juniper_codegen/src/graphql_interface/mod.rs
index 6893e9db7..0c5fcf0ee 100644
--- a/juniper_codegen/src/graphql_interface/mod.rs
+++ b/juniper_codegen/src/graphql_interface/mod.rs
@@ -395,6 +395,8 @@ impl ToTokens for Definition {
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
+        self.impl_resolve_value().to_tokens(into);
+        gen::impl_resolvable(&self.behavior, self.ty_and_generics()).to_tokens(into);
         self.impl_reflect().to_tokens(into);
     }
 }
@@ -850,6 +852,36 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::Value`] trait for this
+    /// [GraphQL interface][0].
+    ///
+    /// [`resolve::Value`]: juniper::resolve::Value
+    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
+    fn impl_resolve_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+             for #ty #where_clause
+            {
+                fn resolve_value(
+                    &self,
+                    _: Option<&[::juniper::Selection<'_, #sv>]>,
+                    _: &#inf,
+                    _: &::juniper::Executor<'_, '_, #cx, #sv>,
+                ) -> ::juniper::ExecutionResult<#sv> {
+                    todo!()
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLValueAsync`] trait for this
     /// [GraphQL interface][1].
     ///
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index 0017a0e69..df3f195e4 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -352,34 +352,8 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
     /// Returns prepared self [`syn::Type`] and [`syn::Generics`] for a trait
     /// implementation.
-    fn ty_and_generics(&self) -> (&syn::Type, syn::Generics) {
-        (&self.ty, self.generics.clone())
-    }
-
-    /// Mixes a type info [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`syn::Ident`].
-    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __TypeInfo };
-        generics.params.push(parse_quote! { #ty: ?Sized });
-        (ty, generics)
-    }
-
-    /// Mixes a context [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`syn::Ident`].
-    fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __Context };
-        generics.params.push(parse_quote! { #ty: ?Sized });
-        (ty, generics)
-    }
-
-    /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns it.
-    ///
-    /// [`ScalarValue`]: juniper::ScalarValue
-    fn mix_scalar_value(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let sv = parse_quote! { __ScalarValue };
-        generics.params.push(parse_quote! { #sv });
-        (sv, generics)
+    fn ty_and_generics(&self) -> (syn::Type, syn::Generics) {
+        (self.ty.clone(), self.generics.clone())
     }
 
     /// Returns generated code implementing [`marker::IsOutputType`] trait for
@@ -599,108 +573,149 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             })
             .collect()
     }
-    /*
-        /// Returns generated code implementing [`resolve::StaticField`] trait for
-        /// each [field][1] of this [GraphQL object][0].
-        ///
-        /// [`resolve::StaticField`]: juniper::resolve::StaticField
-        /// [0]: https://spec.graphql.org/October2021#sec-Objects
-        /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
-        #[must_use]
-        pub(crate) fn impl_resolve_static_field(&self) -> TokenStream {
-            let bh = &self.behavior;
-            let (ty, generics) = self.ty_and_generics();
-            let (inf, generics) = self.mix_type_info(generics);
-            let (cx, generics) = self.mix_context(generics);
-            let (sv, generics) = self.mix_scalar_value(generics);
-
-            self.fields
-                .iter()
-                .map(|field| {
-                    let mut generics = generics.clone();
-                    let (f_name, f_bh) = (&field.name, &field.behavior);
-                    let (f_ident, f_ty) = (&field.ident, &field.ty);
-
-                    let body = if !field.is_async {
-                        generics.make_where_clause().predicates.push(parse_quote! {
-                            #f_ty: ::juniper::resolve::Value<#inf, #cx, #sv, #f_bh>
-                        });
 
-                        let res = if field.is_method() {
-                            let args = field.arguments.as_ref().unwrap().iter().map(|arg| {
-                                match arg {
-                                    field::MethodArgument::Regular(arg) => {
-                                        let (a_ty, a_bh) = (&arg.ty, &arg.behavior);
-                                        generics.make_where_clause().predicates.push(parse_quote! {
-                                            #a_ty: ::juniper::resolve::InputValueOwned<#sv, #a_bh>
-                                        });
-                                        quote! {
-                                            args.resolve::<#a_ty, #a_bh>(#name)?
-                                        }
+    /// Returns generated code implementing [`resolve::Value`] trait for this
+    /// [GraphQL object][0].
+    ///
+    /// [`resolve::Value`]: juniper::resolve::Value
+    /// [0]: https://spec.graphql.org/October2021#sec-Objects
+    pub(crate) fn impl_resolve_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+             for #ty #where_clause
+            {
+                fn resolve_value(
+                    &self,
+                    _: Option<&[::juniper::Selection<'_, #sv>]>,
+                    _: &#inf,
+                    _: &::juniper::Executor<'_, '_, #cx, #sv>,
+                ) -> ::juniper::ExecutionResult<#sv> {
+                    todo!()
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`resolve::StaticField`] trait for
+    /// each [field][1] of this [GraphQL object][0].
+    ///
+    /// [`resolve::StaticField`]: juniper::resolve::StaticField
+    /// [0]: https://spec.graphql.org/October2021#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    #[must_use]
+    pub(crate) fn impl_resolve_static_field(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+
+        self.fields
+            .iter()
+            .map(|field| {
+                let mut generics = generics.clone();
+                let (f_name, f_bh) = (&field.name, &field.behavior);
+                let (f_ident, f_ty) = (&field.ident, &field.ty);
+
+                let body = if !field.is_async {
+                    generics.make_where_clause().predicates.push(parse_quote! {
+                        #f_ty: ::juniper::resolve::Resolvable<#sv, #f_bh>
+                    });
+                    generics.make_where_clause().predicates.push(parse_quote! {
+                        <#f_ty as ::juniper::resolve::Resolvable<#sv, #f_bh>>::Value:
+                            ::juniper::resolve::Value<#inf, #cx, #sv, #f_bh>
+                    });
+
+                    let res = if field.is_method() {
+                        let args = field
+                            .arguments
+                            .as_ref()
+                            .unwrap()
+                            .iter()
+                            .map(|arg| match arg {
+                                field::MethodArgument::Regular(arg) => {
+                                    let a_name = &arg.name;
+                                    let (a_ty, a_bh) = (&arg.ty, &arg.behavior);
+                                    generics.make_where_clause().predicates.push(parse_quote! {
+                                        #a_ty: ::juniper::resolve::InputValueOwned<#sv, #a_bh>
+                                    });
+                                    quote! {
+                                        args.resolve::<#a_ty, #a_bh>(#a_name)?
                                     }
-                                    field::MethodArgument::Context(cx_ty) => {
-                                        generics.make_where_clause().predicates.push(parse_quote! {
-                                            #cx: ::juniper::Extract<#cx_ty>
-                                        });
-                                        quote! {
-                                            <#cx as ::juniper::Extract<#cx_ty>>
-                                                ::extract(executor.context())
-                                        }
+                                }
+                                field::MethodArgument::Context(cx_ty) => {
+                                    generics.make_where_clause().predicates.push(parse_quote! {
+                                        #cx: ::juniper::Extract<#cx_ty>
+                                    });
+                                    quote! {
+                                        <#cx as ::juniper::Extract<#cx_ty>>
+                                            ::extract(executor.context())
                                     }
-                                    field::MethodArgument::Executor => {
-                                        quote! {
-                                            executor
-                                        }
+                                }
+                                field::MethodArgument::Executor => {
+                                    quote! {
+                                        executor
                                     }
                                 }
                             });
 
-                            let rcv = field.has_receiver.then(|| {
-                                quote! { self, }
-                            });
-
-                            quote! { Self::#ident(#rcv #( #args ),*) }
-                        } else {
-                            quote! {
-                                &self.#f_ident
-                            }
-                        };
+                        let rcv = field.has_receiver.then(|| {
+                            quote! { self, }
+                        });
 
                         quote! {
-                            executor.resolve_value::<#f_bh, _, _>(#res, type_info)
+                            <#f_ty as ::juniper::resolve::Resolvable<#sv, #f_bh>>
+                                ::into_value(Self::#f_ident(#rcv #( #args ),*))?
                         }
                     } else {
                         quote! {
-                            ::std::panic!(
-                                 "Tried to resolve async field `{}` on type `{}` with a sync resolver",
-                                 #f_name,
-                                 <Self as ::juniper::reflect::BaseType<#bh>>::NAME,
-                             );
+                            &self.#f_ident
                         }
                     };
 
-                    let (impl_gens, _, where_clause) = generics.split_for_impl();
-
                     quote! {
-                        #[automatically_derived]
-                        impl #impl_gens ::juniper::resolve::StaticField<
-                            { ::juniper::reflect::fnv1a128(#f_name) },
-                            #inf, #cx, #sv, #bh,
-                        > for #ty #where_clause {
-                            fn resolve_static_field(
-                                &self,
-                                args: &::juniper::Arguments<'_, #sv>,
-                                type_info: &#inf,
-                                executor: &::juniper::Executor<'_, '_, #cx, #sv>,
-                            ) -> ::juniper::ExecutionResult<#sv> {
-                                #body
-                            }
+                        executor.resolve_value::<#f_bh, _, _>(#res, type_info)
+                    }
+                } else {
+                    quote! {
+                        ::std::panic!(
+                             "Tried to resolve async field `{}` on type `{}` with a sync resolver",
+                             #f_name,
+                             <Self as ::juniper::reflect::BaseType<#bh>>::NAME,
+                         );
+                    }
+                };
+
+                let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+                quote! {
+                    #[automatically_derived]
+                    impl #impl_gens ::juniper::resolve::StaticField<
+                        { ::juniper::reflect::fnv1a128(#f_name) },
+                        #inf, #cx, #sv, #bh,
+                    > for #ty #where_clause {
+                        fn resolve_static_field(
+                            &self,
+                            args: &::juniper::Arguments<'_, #sv>,
+                            type_info: &#inf,
+                            executor: &::juniper::Executor<'_, '_, #cx, #sv>,
+                        ) -> ::juniper::ExecutionResult<#sv> {
+                            #body
                         }
                     }
-                })
-                .collect()
-        }
-    */
+                }
+            })
+            .collect()
+    }
+
     /// Returns generated code implementing [`GraphQLType`] trait for this
     /// [GraphQL object][1].
     ///
@@ -780,9 +795,11 @@ impl ToTokens for Definition<Query> {
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
+        self.impl_resolve_value().to_tokens(into);
+        gen::impl_resolvable(&self.behavior, self.ty_and_generics()).to_tokens(into);
+        self.impl_resolve_static_field().to_tokens(into);
         self.impl_reflect().to_tokens(into);
         self.impl_reflect_field().to_tokens(into);
-        //self.impl_resolve_static_field().to_tokens(into);
     }
 }
 
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 80ebefaa0..eba30018c 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -2,6 +2,9 @@
 //!
 //! [1]: https://spec.graphql.org/October2021#sec-Scalars
 
+pub mod attr;
+pub mod derive;
+
 use proc_macro2::{Literal, TokenStream};
 use quote::{format_ident, quote, ToTokens, TokenStreamExt};
 use syn::{
@@ -15,7 +18,7 @@ use syn::{
 use url::Url;
 
 use crate::common::{
-    behavior, filter_attrs,
+    behavior, filter_attrs, gen,
     parse::{
         attr::{err, OptionExt as _},
         ParseBufferExt as _,
@@ -23,9 +26,6 @@ use crate::common::{
     scalar, Description, SpanContainer,
 };
 
-pub mod attr;
-pub mod derive;
-
 /// Available arguments behind `#[graphql]`/`#[graphql_scalar]` attributes when
 /// generating code for [GraphQL scalar][1].
 ///
@@ -351,7 +351,7 @@ impl ToTokens for Definition {
         self.impl_resolve_type_name().to_tokens(into);
         self.impl_resolve_value().to_tokens(into);
         self.impl_resolve_value_async().to_tokens(into);
-        self.impl_resolvable().to_tokens(into);
+        gen::impl_resolvable(&self.behavior, self.ty_and_generics()).to_tokens(into);
         self.impl_resolve_to_input_value().to_tokens(into);
         self.impl_resolve_input_value().to_tokens(into);
         self.impl_resolve_scalar_token().to_tokens(into);
@@ -396,9 +396,9 @@ impl Definition {
     fn impl_graphql_input_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
         let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::resolve::Type<#inf, #sv, #bh>
                   + ::juniper::resolve::ToInputValue<#sv, #bh>
@@ -425,8 +425,8 @@ impl Definition {
     fn impl_graphql_output_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
         let (sv, mut generics) = self.mix_scalar_value(generics);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::resolve::Type<#inf, #sv, #bh>
@@ -454,10 +454,10 @@ impl Definition {
     fn impl_graphql_scalar(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
         let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, sv);
         generics.make_where_clause().predicates.push(parse_quote! {
             Self: ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
                   + ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
@@ -531,7 +531,7 @@ impl Definition {
     fn impl_resolve_type_name(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
         quote! {
@@ -554,7 +554,7 @@ impl Definition {
     fn impl_resolve_type(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
         let (sv, mut generics) = self.mix_scalar_value(generics);
         let preds = &mut generics.make_where_clause().predicates;
         preds.push(parse_quote! { #sv: Clone });
@@ -639,8 +639,8 @@ impl Definition {
     fn impl_resolve_value(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
         let (sv, mut generics) = self.mix_scalar_value(generics);
         generics
             .make_where_clause()
@@ -705,8 +705,8 @@ impl Definition {
     fn impl_resolve_value_async(&self) -> TokenStream {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
-        let (inf, generics) = self.mix_type_info(generics);
-        let (cx, generics) = self.mix_context(generics);
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
         let (sv, mut generics) = self.mix_scalar_value(generics);
         let preds = &mut generics.make_where_clause().predicates;
         preds.push(parse_quote! {
@@ -739,31 +739,6 @@ impl Definition {
         }
     }
 
-    /// Returns generated code implementing [`resolve::Resolvable`] trait for
-    /// this [GraphQL scalar][0].
-    ///
-    /// [`resolve::Resolvable`]: juniper::resolve::Resolvable
-    /// [0]: https://spec.graphql.org/October2021#sec-Scalars
-    fn impl_resolvable(&self) -> TokenStream {
-        let bh = &self.behavior;
-        let (ty, generics) = self.ty_and_generics();
-        let (sv, generics) = self.mix_scalar_value(generics);
-        let (impl_gens, _, where_clause) = generics.split_for_impl();
-
-        quote! {
-            #[automatically_derived]
-            impl #impl_gens ::juniper::resolve::Resolvable<#sv, #bh>
-             for #ty #where_clause
-            {
-                type Value = Self;
-
-                fn into_value(self) -> ::juniper::FieldResult<Self, #sv> {
-                    ::juniper::FieldResult::Ok(self)
-                }
-            }
-        }
-    }
-
     /// Returns generated code implementing [`InputValue`] trait for this
     /// [GraphQL scalar][1].
     ///
@@ -855,7 +830,7 @@ impl Definition {
         let bh = &self.behavior;
         let (ty, generics) = self.ty_and_generics();
         let (sv, generics) = self.mix_scalar_value(generics);
-        let (lt, mut generics) = self.mix_input_lifetime(generics, sv);
+        let (lt, mut generics) = gen::mix_input_lifetime(generics, sv);
         generics
             .make_where_clause()
             .predicates
@@ -1111,24 +1086,6 @@ impl Definition {
         (ty, generics)
     }
 
-    /// Mixes a type info [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`syn::Ident`].
-    #[must_use]
-    fn mix_type_info(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __TypeInfo };
-        generics.params.push(parse_quote! { #ty: ?Sized });
-        (ty, generics)
-    }
-
-    /// Mixes a context [`syn::GenericParam`] into the provided
-    /// [`syn::Generics`] and returns its [`syn::Ident`].
-    #[must_use]
-    fn mix_context(&self, mut generics: syn::Generics) -> (syn::Ident, syn::Generics) {
-        let ty = parse_quote! { __Context };
-        generics.params.push(parse_quote! { #ty: ?Sized });
-        (ty, generics)
-    }
-
     /// Mixes a [`ScalarValue`] [`syn::GenericParam`] into the provided
     /// [`syn::Generics`] and returns it.
     ///
@@ -1143,25 +1100,6 @@ impl Definition {
         generics.params.push(parse_quote! { #sv });
         (sv, generics)
     }
-
-    /// Mixes an [`InputValue`]'s lifetime [`syn::GenericParam`] into the
-    /// provided [`syn::Generics`] and returns it.
-    ///
-    /// [`InputValue`]: juniper::resolve::InputValue
-    #[must_use]
-    fn mix_input_lifetime(
-        &self,
-        mut generics: syn::Generics,
-        sv: &ScalarValue,
-    ) -> (syn::GenericParam, syn::Generics) {
-        let lt: syn::GenericParam = parse_quote! { '__inp };
-        generics.params.push(lt.clone());
-        generics
-            .make_where_clause()
-            .predicates
-            .push(parse_quote! { #sv: #lt });
-        (lt, generics)
-    }
 }
 
 /// Adds `__fa__` prefix to all lifetimes to avoid "lifetime name `'a` shadows a
diff --git a/juniper_codegen/src/graphql_union/mod.rs b/juniper_codegen/src/graphql_union/mod.rs
index 5b86cbe25..7931fccee 100644
--- a/juniper_codegen/src/graphql_union/mod.rs
+++ b/juniper_codegen/src/graphql_union/mod.rs
@@ -363,6 +363,8 @@ impl ToTokens for Definition {
         self.impl_graphql_value_async_tokens().to_tokens(into);
         self.impl_reflection_traits_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
+        self.impl_resolve_value().to_tokens(into);
+        gen::impl_resolvable(&self.behavior, self.ty_and_generics()).to_tokens(into);
         self.impl_reflect().to_tokens(into);
     }
 }
@@ -609,6 +611,36 @@ impl Definition {
         }
     }
 
+    /// Returns generated code implementing [`resolve::Value`] trait for this
+    /// [GraphQL union][0].
+    ///
+    /// [`resolve::Value`]: juniper::resolve::Value
+    /// [0]: https://spec.graphql.org/October2021#sec-Unions
+    fn impl_resolve_value(&self) -> TokenStream {
+        let bh = &self.behavior;
+        let (ty, generics) = self.ty_and_generics();
+        let (inf, generics) = gen::mix_type_info(generics);
+        let (cx, generics) = gen::mix_context(generics);
+        let (sv, generics) = gen::mix_scalar_value(generics);
+        let (impl_gens, _, where_clause) = generics.split_for_impl();
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+             for #ty #where_clause
+            {
+                fn resolve_value(
+                    &self,
+                    _: Option<&[::juniper::Selection<'_, #sv>]>,
+                    _: &#inf,
+                    _: &::juniper::Executor<'_, '_, #cx, #sv>,
+                ) -> ::juniper::ExecutionResult<#sv> {
+                    todo!()
+                }
+            }
+        }
+    }
+
     /// Returns generated code implementing [`GraphQLValueAsync`] trait for this
     /// [GraphQL union][1].
     ///

From bf219867b6b55f8ac07188d9ffa891a3d48ba8d5 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Mon, 12 Sep 2022 17:54:57 +0300
Subject: [PATCH 56/58] Impl fields resolving, vol.4 [skip ci]

---
 juniper_codegen/src/common/parse/mod.rs   | 49 ++++++++++++++++++++---
 juniper_codegen/src/graphql_object/mod.rs |  2 +-
 2 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/juniper_codegen/src/common/parse/mod.rs b/juniper_codegen/src/common/parse/mod.rs
index 53781675e..40eae7bd4 100644
--- a/juniper_codegen/src/common/parse/mod.rs
+++ b/juniper_codegen/src/common/parse/mod.rs
@@ -7,7 +7,7 @@ pub(crate) mod downcaster;
 use std::{any::TypeId, iter, mem};
 
 use proc_macro2::Span;
-use quote::quote;
+use quote::{quote, format_ident};
 use syn::{
     ext::IdentExt as _,
     parse::{Parse, ParseBuffer},
@@ -105,15 +105,29 @@ pub(crate) trait TypeExt {
     #[must_use]
     fn unreferenced(&self) -> &Self;
 
-    /// Iterates mutably over all the lifetime parameters of this [`syn::Type`]
-    /// with the given `func`tion.
-    fn lifetimes_iter_mut<F: FnMut(&mut syn::Lifetime)>(&mut self, func: &mut F);
+    /// Iterates mutably over all the lifetime parameters (even implicit) of
+    /// this [`syn::Type`] with the given `func`tion.
+    fn lifetimes_iter_mut<F: FnMut(&mut Option<syn::Lifetime>)>(&mut self, func: &mut F);
+
+    /// Iterates mutably over all the named lifetime parameters (explicit only)
+    /// of this [`syn::Type`] with the given `func`tion.
+    fn named_lifetimes_iter_mut<F: FnMut(&mut syn::Lifetime)>(&mut self, func: &mut F) {
+        self.lifetimes_iter_mut(&mut |lt| {
+            if let Some(lt) = lt {
+                func(lt);
+            }
+        })
+    }
 
     /// Anonymizes all the lifetime parameters of this [`syn::Type`] (except
     /// the `'static` ones), making it suitable for using in contexts with
     /// inferring.
     fn lifetimes_anonymized(&mut self);
 
+    /// Lifts all the lifetimes of this [`syn::Type`] (except `'static`) to a
+    /// `for<>` quantifier, preserving the type speciality as much as possible.
+    fn to_hrtb_lifetimes(&self) -> (Option<syn::BoundLifetimes>, syn::Type);
+
     /// Returns the topmost [`syn::Ident`] of this [`syn::TypePath`], if any.
     #[must_use]
     fn topmost_ident(&self) -> Option<&syn::Ident>;
@@ -135,7 +149,7 @@ impl TypeExt for syn::Type {
         }
     }
 
-    fn lifetimes_iter_mut<F: FnMut(&mut syn::Lifetime)>(&mut self, func: &mut F) {
+    fn lifetimes_iter_mut<F: FnMut(&mut Option<syn::Lifetime>)>(&mut self, func: &mut F) {
         use syn::{GenericArgument as GA, Type as T};
 
         fn iter_path<F: FnMut(&mut syn::Lifetime)>(path: &mut syn::Path, func: &mut F) {
@@ -213,13 +227,36 @@ impl TypeExt for syn::Type {
     }
 
     fn lifetimes_anonymized(&mut self) {
-        self.lifetimes_iter_mut(&mut |lt| {
+        self.named_lifetimes_iter_mut(&mut |lt| {
             if lt.ident != "_" && lt.ident != "static" {
                 lt.ident = syn::Ident::new("_", Span::call_site());
             }
         });
     }
 
+    fn to_hrtb_lifetimes(&self) -> (Option<syn::BoundLifetimes>, syn::Type) {
+        let mut ty = self.clone();
+        let mut lts = vec![];
+
+        let anon_ident = &syn::Ident::new("_", Span::call_site());
+
+        ty.lifetimes_iter_mut(&mut |lt| {
+            let ident = lt.map(|l| l.ident).unwrap_or(anon_ident);
+            if ident != "static" {
+                let ident = format_ident!("__fa_f_{ident}");
+                if !lts.contains(&ident) {
+                    lts.push(ident);
+                }
+                *lt = Some(parse_quote! { '#ident })
+            }
+        });
+
+        let for_ = (!lts.is_empty()).then(|| parse_quote! {
+            for< #( #lts ),* >}
+        );
+        (for_, ty)
+    }
+
     fn topmost_ident(&self) -> Option<&syn::Ident> {
         match self.unparenthesized() {
             syn::Type::Path(p) => Some(&p.path),
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index df3f195e4..496294b35 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -323,7 +323,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
                 // Modify lifetime names to omit "lifetime name `'a` shadows a
                 // lifetime name that is already in scope" error.
                 let mut ty = self.ty.clone();
-                ty.lifetimes_iter_mut(&mut |lt| {
+                ty.named_lifetimes_iter_mut(&mut |lt| {
                     let ident = lt.ident.unraw();
                     lt.ident = format_ident!("__fa__{ident}");
                     lifetimes.push(lt.clone());

From 1ddf0bd611256775ce5d702956dea3144d2e96c3 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 20 Sep 2022 15:45:26 +0300
Subject: [PATCH 57/58] Impl hrtbifying

---
 juniper_codegen/Cargo.toml              |   2 +-
 juniper_codegen/src/common/gen.rs       |   2 +-
 juniper_codegen/src/common/parse/mod.rs | 125 +++++++++++++++++++-----
 3 files changed, 103 insertions(+), 26 deletions(-)

diff --git a/juniper_codegen/Cargo.toml b/juniper_codegen/Cargo.toml
index b22916581..9d696a7a1 100644
--- a/juniper_codegen/Cargo.toml
+++ b/juniper_codegen/Cargo.toml
@@ -31,5 +31,5 @@ url = "2.0"
 [dev-dependencies]
 derive_more = "0.99.7"
 futures = "0.3.22"
-juniper = { path = "../juniper" }
+#juniper = { path = "../juniper" }
 serde = "1.0"
diff --git a/juniper_codegen/src/common/gen.rs b/juniper_codegen/src/common/gen.rs
index 57bf3f993..846ed25e1 100644
--- a/juniper_codegen/src/common/gen.rs
+++ b/juniper_codegen/src/common/gen.rs
@@ -4,7 +4,7 @@ use proc_macro2::TokenStream;
 use quote::{quote, ToTokens};
 use syn::parse_quote;
 
-use crate::common::{behavior};
+use crate::common::behavior;
 
 /// Returns generated code implementing [`resolve::Resolvable`] trait for the
 /// provided [`syn::Type`] with its [`syn::Generics`].
diff --git a/juniper_codegen/src/common/parse/mod.rs b/juniper_codegen/src/common/parse/mod.rs
index 40eae7bd4..5789f6e38 100644
--- a/juniper_codegen/src/common/parse/mod.rs
+++ b/juniper_codegen/src/common/parse/mod.rs
@@ -7,7 +7,7 @@ pub(crate) mod downcaster;
 use std::{any::TypeId, iter, mem};
 
 use proc_macro2::Span;
-use quote::{quote, format_ident};
+use quote::quote;
 use syn::{
     ext::IdentExt as _,
     parse::{Parse, ParseBuffer},
@@ -105,15 +105,15 @@ pub(crate) trait TypeExt {
     #[must_use]
     fn unreferenced(&self) -> &Self;
 
-    /// Iterates mutably over all the lifetime parameters (even implicit) of
-    /// this [`syn::Type`] with the given `func`tion.
-    fn lifetimes_iter_mut<F: FnMut(&mut Option<syn::Lifetime>)>(&mut self, func: &mut F);
+    /// Iterates mutably over all the lifetime parameters (even elided) of this
+    /// [`syn::Type`] with the given `func`tion.
+    fn lifetimes_iter_mut<F: FnMut(MaybeElidedLifetimeMut<'_>)>(&mut self, func: &mut F);
 
-    /// Iterates mutably over all the named lifetime parameters (explicit only)
-    /// of this [`syn::Type`] with the given `func`tion.
+    /// Iterates mutably over all the named lifetime parameters (no elided) of
+    /// this [`syn::Type`] with the given `func`tion.
     fn named_lifetimes_iter_mut<F: FnMut(&mut syn::Lifetime)>(&mut self, func: &mut F) {
         self.lifetimes_iter_mut(&mut |lt| {
-            if let Some(lt) = lt {
+            if let MaybeElidedLifetimeMut::Named(lt) = lt {
                 func(lt);
             }
         })
@@ -124,8 +124,9 @@ pub(crate) trait TypeExt {
     /// inferring.
     fn lifetimes_anonymized(&mut self);
 
-    /// Lifts all the lifetimes of this [`syn::Type`] (except `'static`) to a
-    /// `for<>` quantifier, preserving the type speciality as much as possible.
+    /// Lifts all the lifetimes of this [`syn::Type`] (even elided, but except
+    /// `'static`) to a `for<>` quantifier, preserving the type speciality as
+    /// much as possible.
     fn to_hrtb_lifetimes(&self) -> (Option<syn::BoundLifetimes>, syn::Type);
 
     /// Returns the topmost [`syn::Ident`] of this [`syn::TypePath`], if any.
@@ -149,16 +150,16 @@ impl TypeExt for syn::Type {
         }
     }
 
-    fn lifetimes_iter_mut<F: FnMut(&mut Option<syn::Lifetime>)>(&mut self, func: &mut F) {
+    fn lifetimes_iter_mut<F: FnMut(MaybeElidedLifetimeMut<'_>)>(&mut self, func: &mut F) {
         use syn::{GenericArgument as GA, Type as T};
 
-        fn iter_path<F: FnMut(&mut syn::Lifetime)>(path: &mut syn::Path, func: &mut F) {
+        fn iter_path<F: FnMut(MaybeElidedLifetimeMut<'_>)>(path: &mut syn::Path, func: &mut F) {
             for seg in path.segments.iter_mut() {
                 match &mut seg.arguments {
                     syn::PathArguments::AngleBracketed(angle) => {
                         for arg in angle.args.iter_mut() {
                             match arg {
-                                GA::Lifetime(lt) => func(lt),
+                                GA::Lifetime(lt) => func(lt.into()),
                                 GA::Type(ty) => ty.lifetimes_iter_mut(func),
                                 GA::Binding(b) => b.ty.lifetimes_iter_mut(func),
                                 GA::Constraint(_) | GA::Const(_) => {}
@@ -195,7 +196,7 @@ impl TypeExt for syn::Type {
             | T::TraitObject(syn::TypeTraitObject { bounds, .. }) => {
                 for bound in bounds.iter_mut() {
                     match bound {
-                        syn::TypeParamBound::Lifetime(lt) => func(lt),
+                        syn::TypeParamBound::Lifetime(lt) => func(lt.into()),
                         syn::TypeParamBound::Trait(bound) => {
                             if bound.lifetimes.is_some() {
                                 todo!("Iterating over HRTB lifetimes in trait is not yet supported")
@@ -207,9 +208,7 @@ impl TypeExt for syn::Type {
             }
 
             T::Reference(ref_ty) => {
-                if let Some(lt) = ref_ty.lifetime.as_mut() {
-                    func(lt)
-                }
+                func((&mut ref_ty.lifetime).into());
                 (*ref_ty.elem).lifetimes_iter_mut(func)
             }
 
@@ -240,20 +239,26 @@ impl TypeExt for syn::Type {
 
         let anon_ident = &syn::Ident::new("_", Span::call_site());
 
-        ty.lifetimes_iter_mut(&mut |lt| {
-            let ident = lt.map(|l| l.ident).unwrap_or(anon_ident);
+        ty.lifetimes_iter_mut(&mut |mut lt_mut| {
+            let ident = match &lt_mut {
+                MaybeElidedLifetimeMut::Elided(v) => {
+                    v.as_ref().map(|l| &l.ident).unwrap_or(anon_ident)
+                }
+                MaybeElidedLifetimeMut::Named(l) => &l.ident,
+            };
             if ident != "static" {
-                let ident = format_ident!("__fa_f_{ident}");
-                if !lts.contains(&ident) {
-                    lts.push(ident);
+                let new_lt = syn::Lifetime::new(&format!("'__fa_f_{ident}"), Span::call_site());
+                if !lts.contains(&new_lt) {
+                    lts.push(new_lt.clone());
                 }
-                *lt = Some(parse_quote! { '#ident })
+                lt_mut.set(new_lt);
             }
         });
 
-        let for_ = (!lts.is_empty()).then(|| parse_quote! {
+        let for_ = (!lts.is_empty()).then(|| {
+            parse_quote! {
             for< #( #lts ),* >}
-        );
+        });
         (for_, ty)
     }
 
@@ -276,6 +281,38 @@ impl TypeExt for syn::Type {
     }
 }
 
+/// Mutable reference to a place that may containing a [`syn::Lifetime`].
+pub(crate) enum MaybeElidedLifetimeMut<'a> {
+    /// [`syn::Lifetime`] may be elided.
+    Elided(&'a mut Option<syn::Lifetime>),
+
+    /// [`syn::Lifetime`] is always present.
+    Named(&'a mut syn::Lifetime),
+}
+
+impl<'a> MaybeElidedLifetimeMut<'a> {
+    /// Assigns the provided [`syn::Lifetime`] to the place pointed by this
+    /// [`MaybeElidedLifetimeMut`] reference.
+    fn set(&mut self, lt: syn::Lifetime) {
+        match self {
+            Self::Elided(v) => **v = Some(lt),
+            Self::Named(l) => **l = lt,
+        }
+    }
+}
+
+impl<'a> From<&'a mut Option<syn::Lifetime>> for MaybeElidedLifetimeMut<'a> {
+    fn from(lt: &'a mut Option<syn::Lifetime>) -> Self {
+        Self::Elided(lt)
+    }
+}
+
+impl<'a> From<&'a mut syn::Lifetime> for MaybeElidedLifetimeMut<'a> {
+    fn from(lt: &'a mut syn::Lifetime) -> Self {
+        Self::Named(lt)
+    }
+}
+
 /// Extension of [`syn::Generics`] providing common function widely used by this crate for parsing.
 pub(crate) trait GenericsExt {
     /// Removes all default types out of type parameters and const parameters in these
@@ -391,3 +428,43 @@ impl<'a> VisitMut for ReplaceWithDefaults<'a> {
         }
     }
 }
+
+#[cfg(test)]
+mod test_type_ext_to_hrtb_lifetimes {
+    use quote::quote;
+    use syn::parse_quote;
+
+    use super::TypeExt as _;
+
+    #[test]
+    fn test() {
+        for (input, expected) in [
+            (parse_quote! { &'static T }, quote! { &'static T }),
+            (parse_quote! { &T }, quote! { for<'__fa_f__>: &'__fa_f__ T }),
+            (
+                parse_quote! { &'a mut T },
+                quote! { for<'__fa_f_a>: &'__fa_f_a mut T },
+            ),
+            (
+                parse_quote! { &str },
+                quote! { for<'__fa_f__>: &'__fa_f__ str },
+            ),
+            (
+                parse_quote! { &Cow<'static, str> },
+                quote! { for<'__fa_f__>: &'__fa_f__ Cow<'static, str> },
+            ),
+            (
+                parse_quote! { &Cow<'a, str> },
+                quote! { for<'__fa_f__, '__fa_f_a>: &'__fa_f__ Cow<'__fa_f_a, str> },
+            ),
+        ] {
+            let (actual_for, actual_ty) = syn::Type::to_hrtb_lifetimes(&input);
+            let actual_for = actual_for.map(|for_| quote! { #for_: });
+
+            assert_eq!(
+                quote! { #actual_for #actual_ty }.to_string(),
+                expected.to_string(),
+            );
+        }
+    }
+}

From 2d01486ee9e1e03de2bd93b953cf9d5a35099133 Mon Sep 17 00:00:00 2001
From: tyranron <tyranron@gmail.com>
Date: Tue, 20 Sep 2022 18:06:07 +0300
Subject: [PATCH 58/58] Yay! Static fields, finally, minimally resolving [skip
 ci]

---
 juniper/src/schema/schema.rs              | 20 ++++++++++----------
 juniper_codegen/src/common/parse/mod.rs   | 15 ++++++++++++++-
 juniper_codegen/src/graphql_object/mod.rs | 18 ++++++++++--------
 3 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/juniper/src/schema/schema.rs b/juniper/src/schema/schema.rs
index 618227462..311bcab26 100644
--- a/juniper/src/schema/schema.rs
+++ b/juniper/src/schema/schema.rs
@@ -141,7 +141,7 @@ impl<'a, S: ScalarValue + 'a> SchemaType<'a, S> {
         self.description.as_deref()
     }
 
-    fn types(&self) -> Vec<TypeType<S>> {
+    fn types(&self) -> Vec<TypeType<'_, S>> {
         self.type_list()
             .into_iter()
             .filter(|t| {
@@ -156,21 +156,21 @@ impl<'a, S: ScalarValue + 'a> SchemaType<'a, S> {
     }
 
     #[graphql(name = "queryType")]
-    fn query_type_(&self) -> TypeType<S> {
+    fn query_type_(&self) -> TypeType<'_, S> {
         self.query_type()
     }
 
     #[graphql(name = "mutationType")]
-    fn mutation_type_(&self) -> Option<TypeType<S>> {
+    fn mutation_type_(&self) -> Option<TypeType<'_, S>> {
         self.mutation_type()
     }
 
     #[graphql(name = "subscriptionType")]
-    fn subscription_type_(&self) -> Option<TypeType<S>> {
+    fn subscription_type_(&self) -> Option<TypeType<'_, S>> {
         self.subscription_type()
     }
 
-    fn directives(&self) -> Vec<&DirectiveType<S>> {
+    fn directives(&self) -> Vec<&DirectiveType<'_, S>> {
         self.directive_list()
     }
 }
@@ -214,7 +214,7 @@ impl<'a, S: ScalarValue + 'a> TypeType<'a, S> {
     fn fields(
         &self,
         #[graphql(default = false)] include_deprecated: Option<bool>,
-    ) -> Option<Vec<&Field<S>>> {
+    ) -> Option<Vec<&Field<'_, S>>> {
         match self {
             TypeType::Concrete(&MetaType::Interface(InterfaceMeta { ref fields, .. }))
             | TypeType::Concrete(&MetaType::Object(ObjectMeta { ref fields, .. })) => Some(
@@ -231,14 +231,14 @@ impl<'a, S: ScalarValue + 'a> TypeType<'a, S> {
         }
     }
 
-    fn of_type(&self) -> Option<&TypeType<S>> {
+    fn of_type(&self) -> Option<&TypeType<'_, S>> {
         match self {
             TypeType::Concrete(_) => None,
             TypeType::List(l, _) | TypeType::NonNull(l) => Some(&**l),
         }
     }
 
-    fn input_fields(&self) -> Option<&[Argument<S>]> {
+    fn input_fields(&self) -> Option<&[Argument<'_, S>]> {
         match self {
             TypeType::Concrete(&MetaType::InputObject(InputObjectMeta {
                 ref input_fields,
@@ -343,7 +343,7 @@ impl<'a, S: ScalarValue + 'a> Field<'a, S> {
         self.description.as_deref()
     }
 
-    fn args(&self) -> Vec<&Argument<S>> {
+    fn args(&self) -> Vec<&Argument<'_, S>> {
         self.arguments
             .as_ref()
             .map_or_else(Vec::new, |v| v.iter().collect())
@@ -434,7 +434,7 @@ impl<'a, S: ScalarValue + 'a> DirectiveType<'a, S> {
         self.is_repeatable
     }
 
-    fn args(&self) -> &[Argument<S>] {
+    fn args(&self) -> &[Argument<'_, S>] {
         &self.arguments
     }
 
diff --git a/juniper_codegen/src/common/parse/mod.rs b/juniper_codegen/src/common/parse/mod.rs
index 5789f6e38..ba4e87181 100644
--- a/juniper_codegen/src/common/parse/mod.rs
+++ b/juniper_codegen/src/common/parse/mod.rs
@@ -124,9 +124,16 @@ pub(crate) trait TypeExt {
     /// inferring.
     fn lifetimes_anonymized(&mut self);
 
+    /// Anonymizes all the lifetime parameters of this [`syn::Type`] (except
+    /// the `'static` ones), making it suitable for using in contexts with
+    /// inferring, and returns it as a new type, leaving the original one
+    /// unchanged.
+    fn to_anonymized_lifetimes(&self) -> syn::Type;
+
     /// Lifts all the lifetimes of this [`syn::Type`] (even elided, but except
     /// `'static`) to a `for<>` quantifier, preserving the type speciality as
-    /// much as possible.
+    /// much as possible, and returns it as a new type, leaving the original one
+    /// unchanged.
     fn to_hrtb_lifetimes(&self) -> (Option<syn::BoundLifetimes>, syn::Type);
 
     /// Returns the topmost [`syn::Ident`] of this [`syn::TypePath`], if any.
@@ -233,6 +240,12 @@ impl TypeExt for syn::Type {
         });
     }
 
+    fn to_anonymized_lifetimes(&self) -> syn::Type {
+        let mut ty = self.clone();
+        ty.lifetimes_anonymized();
+        ty
+    }
+
     fn to_hrtb_lifetimes(&self) -> (Option<syn::BoundLifetimes>, syn::Type) {
         let mut ty = self.clone();
         let mut lts = vec![];
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index 496294b35..a0cef4cb2 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -21,7 +21,7 @@ use crate::common::{
     behavior, field, filter_attrs, gen,
     parse::{
         attr::{err, OptionExt as _},
-        GenericsExt as _, ParseBufferExt as _, TypeExt,
+        GenericsExt as _, ParseBufferExt as _, TypeExt as _,
     },
     rename, scalar, Description, SpanContainer,
 };
@@ -626,15 +626,18 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
                 let (f_ident, f_ty) = (&field.ident, &field.ty);
 
                 let body = if !field.is_async {
+                    let (f_for_ty, f_hrtb_ty) = f_ty.to_hrtb_lifetimes();
                     generics.make_where_clause().predicates.push(parse_quote! {
-                        #f_ty: ::juniper::resolve::Resolvable<#sv, #f_bh>
+                        #f_for_ty #f_hrtb_ty:
+                            ::juniper::resolve::Resolvable<#sv, #f_bh>
                     });
                     generics.make_where_clause().predicates.push(parse_quote! {
-                        <#f_ty as ::juniper::resolve::Resolvable<#sv, #f_bh>>::Value:
+                        #f_for_ty <#f_hrtb_ty as ::juniper::resolve::Resolvable<#sv, #f_bh>>::Value:
                             ::juniper::resolve::Value<#inf, #cx, #sv, #f_bh>
                     });
 
-                    let res = if field.is_method() {
+                    let val = if field.is_method() {
+                        let f_anon_ty = f_ty.to_anonymized_lifetimes();
                         let args = field
                             .arguments
                             .as_ref()
@@ -666,23 +669,22 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
                                     }
                                 }
                             });
-
                         let rcv = field.has_receiver.then(|| {
                             quote! { self, }
                         });
 
                         quote! {
-                            <#f_ty as ::juniper::resolve::Resolvable<#sv, #f_bh>>
+                            <#f_anon_ty as ::juniper::resolve::Resolvable<#sv, #f_bh>>
                                 ::into_value(Self::#f_ident(#rcv #( #args ),*))?
                         }
                     } else {
                         quote! {
-                            &self.#f_ident
+                            self.#f_ident
                         }
                     };
 
                     quote! {
-                        executor.resolve_value::<#f_bh, _, _>(#res, type_info)
+                        executor.resolve_value::<#f_bh, _, _>(&#val, type_info)
                     }
                 } else {
                     quote! {