From 13903d7628b5146f4bb8bccd96ce2153e1229880 Mon Sep 17 00:00:00 2001 From: Magnus Hallin Date: Wed, 28 Dec 2016 11:28:48 +0100 Subject: [PATCH] Don't clone selection sets during execution --- src/executor.rs | 13 ++++------- src/macros/enums.rs | 2 +- src/macros/interface.rs | 2 +- src/macros/scalar.rs | 2 +- src/macros/union.rs | 2 +- src/types/base.rs | 50 ++++++++++++++++++++--------------------- src/types/containers.rs | 6 ++--- src/types/pointers.rs | 8 +++---- src/types/scalars.rs | 2 +- 9 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/executor.rs b/src/executor.rs index 7431dfc4..be5f49f8 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -37,7 +37,7 @@ pub enum FieldPath<'a> { pub struct Executor<'a, CtxT> where CtxT: 'a { fragments: &'a HashMap<&'a str, &'a Fragment>, variables: &'a HashMap, - current_selection_set: Option>, + current_selection_set: Option<&'a [Selection]>, schema: &'a SchemaType, context: &'a CtxT, errors: &'a RwLock>, @@ -151,12 +151,7 @@ impl<'a, CtxT> Executor<'a, CtxT> { /// Resolve a single arbitrary value into an `ExecutionResult` pub fn resolve>(&self, value: &T) -> ExecutionResult { - Ok(value.resolve( - match self.current_selection_set { - Some(ref sel) => Some(sel.clone()), - None => None, - }, - self)) + Ok(value.resolve(self.current_selection_set, self)) } /// Resolve a single arbitrary value into a return value @@ -194,7 +189,7 @@ impl<'a, CtxT> Executor<'a, CtxT> { &self, field_name: Option, location: SourcePosition, - selection_set: Option>, + selection_set: Option<&'a [Selection]>, ) -> Executor { @@ -339,7 +334,7 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>( let executor = Executor { fragments: &fragments.iter().map(|f| (f.item.name.item.as_str(), &f.item)).collect(), variables: variables, - current_selection_set: Some(op.item.selection_set), + current_selection_set: Some(&op.item.selection_set[..]), schema: &root_node.schema, context: context, errors: &errors, diff --git a/src/macros/enums.rs b/src/macros/enums.rs index 838079be..82d7863b 100644 --- a/src/macros/enums.rs +++ b/src/macros/enums.rs @@ -83,7 +83,7 @@ macro_rules! graphql_enum { .into_meta() } - fn resolve(&self, _: Option>, _: &$crate::Executor) -> $crate::Value { + fn resolve(&self, _: Option<&[$crate::Selection]>, _: &$crate::Executor) -> $crate::Value { match self { $( &graphql_enum!(@as_pattern, $eval) => diff --git a/src/macros/interface.rs b/src/macros/interface.rs index b5bebabc..d31b79fb 100644 --- a/src/macros/interface.rs +++ b/src/macros/interface.rs @@ -268,7 +268,7 @@ macro_rules! graphql_interface { fn resolve_into_type( &$mainself, type_name: &str, - _: Option>, + _: Option<&[$crate::Selection]>, executor: &$crate::Executor, ) -> $crate::ExecutionResult diff --git a/src/macros/scalar.rs b/src/macros/scalar.rs index d2045012..62bc4a6d 100644 --- a/src/macros/scalar.rs +++ b/src/macros/scalar.rs @@ -77,7 +77,7 @@ macro_rules! graphql_scalar { fn resolve( &$resolve_selfvar, - _: Option>, + _: Option<&[$crate::Selection]>, _: &$crate::Executor) -> $crate::Value { $resolve_body } diff --git a/src/macros/union.rs b/src/macros/union.rs index 2bb2f79b..182a464a 100644 --- a/src/macros/union.rs +++ b/src/macros/union.rs @@ -137,7 +137,7 @@ macro_rules! graphql_union { fn resolve_into_type( &$mainself, type_name: &str, - _: Option>, + _: Option<&[$crate::Selection]>, executor: &$crate::Executor, ) -> $crate::ExecutionResult diff --git a/src/types/base.rs b/src/types/base.rs index d972a237..92cff735 100644 --- a/src/types/base.rs +++ b/src/types/base.rs @@ -248,7 +248,7 @@ pub trait GraphQLType: Sized { /// /// The default implementation panics. #[allow(unused_variables)] - fn resolve_into_type(&self, type_name: &str, selection_set: Option>, executor: &Executor) -> ExecutionResult { + fn resolve_into_type(&self, type_name: &str, selection_set: Option<&[Selection]>, executor: &Executor) -> ExecutionResult { if Self::name().unwrap() == type_name { Ok(self.resolve(selection_set, executor)) } else { @@ -274,7 +274,7 @@ pub trait GraphQLType: Sized { /// The default implementation uses `resolve_field` to resolve all fields, /// including those through fragment expansion, for object types. For /// non-object types, this method panics. - fn resolve(&self, selection_set: Option>, executor: &Executor) -> Value { + fn resolve(&self, selection_set: Option<&[Selection]>, executor: &Executor) -> Value { if let Some(selection_set) = selection_set { let mut result = HashMap::new(); resolve_selection_set_into(self, selection_set, executor, &mut result); @@ -288,7 +288,7 @@ pub trait GraphQLType: Sized { fn resolve_selection_set_into( instance: &T, - selection_set: Vec, + selection_set: &[Selection], executor: &Executor, result: &mut HashMap) where T: GraphQLType @@ -299,11 +299,11 @@ fn resolve_selection_set_into( for selection in selection_set { match selection { - Selection::Field(Spanning { item: f, start: start_pos, .. }) => { + &Selection::Field(Spanning { item: ref f, start: ref start_pos, .. }) => { if is_excluded( - &match f.directives { - Some(sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), - None => None, + &match &f.directives { + &Some(ref sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), + &None => None, }, executor.variables()) { continue; @@ -327,13 +327,13 @@ fn resolve_selection_set_into( let mut sub_exec = executor.sub_executor( Some(response_name.clone()), start_pos.clone(), - f.selection_set); + f.selection_set.as_ref().map(|v| &v[..])); let field_result = instance.resolve_field( &f.name.item, &Arguments::new( - f.arguments.map(|m| - m.item.into_iter().map(|(k, v)| + f.arguments.as_ref().map(|m| + m.item.iter().cloned().map(|(k, v)| (k.item, v.item.into_const(exec_vars))).collect()), &meta_field.arguments), &mut sub_exec); @@ -341,16 +341,16 @@ fn resolve_selection_set_into( match field_result { Ok(v) => merge_key_into(result, response_name.clone(), v), Err(e) => { - sub_exec.push_error(e, start_pos); + sub_exec.push_error(e, start_pos.clone()); result.insert(response_name.clone(), Value::null()); } } }, - Selection::FragmentSpread(Spanning { item: spread, .. }) => { + &Selection::FragmentSpread(Spanning { item: ref spread, .. }) => { if is_excluded( - &match spread.directives { - Some(sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), - None => None, + &match &spread.directives { + &Some(ref sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), + &None => None, }, executor.variables()) { continue; @@ -360,13 +360,13 @@ fn resolve_selection_set_into( .expect("Fragment could not be found"); resolve_selection_set_into( - instance, fragment.selection_set.clone(), executor, result); + instance, &fragment.selection_set[..], executor, result); }, - Selection::InlineFragment(Spanning { item: fragment, start: start_pos, .. }) => { + &Selection::InlineFragment(Spanning { item: ref fragment, start: ref start_pos, .. }) => { if is_excluded( - &match fragment.directives { - Some(sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), - None => None + &match &fragment.directives { + &Some(ref sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), + &None => None }, executor.variables()) { continue; @@ -375,12 +375,12 @@ fn resolve_selection_set_into( let mut sub_exec = executor.sub_executor( None, start_pos.clone(), - Some(fragment.selection_set.clone())); + Some(&fragment.selection_set[..])); - if let Some(type_condition) = fragment.type_condition { + if let &Some(ref type_condition) = &fragment.type_condition { let sub_result = instance.resolve_into_type( &type_condition.item, - Some(fragment.selection_set.clone()), + Some(&fragment.selection_set[..]), &mut sub_exec); if let Ok(Value::Object(mut hash_map)) = sub_result { @@ -389,13 +389,13 @@ fn resolve_selection_set_into( } } else if let Err(e) = sub_result { - sub_exec.push_error(e, start_pos); + sub_exec.push_error(e, start_pos.clone()); } } else { resolve_selection_set_into( instance, - fragment.selection_set.clone(), + &fragment.selection_set[..], &mut sub_exec, result); } diff --git a/src/types/containers.rs b/src/types/containers.rs index 4a4a6710..f7f1ef84 100644 --- a/src/types/containers.rs +++ b/src/types/containers.rs @@ -16,7 +16,7 @@ impl GraphQLType for Option where T: GraphQLType { registry.build_nullable_type::().into_meta() } - fn resolve(&self, _: Option>, executor: &Executor) -> Value { + fn resolve(&self, _: Option<&[Selection]>, executor: &Executor) -> Value { match *self { Some(ref obj) => executor.resolve_into_value(obj), None => Value::null(), @@ -56,7 +56,7 @@ impl GraphQLType for Vec where T: GraphQLType { registry.build_list_type::().into_meta() } - fn resolve(&self, _: Option>, executor: &Executor) -> Value { + fn resolve(&self, _: Option<&[Selection]>, executor: &Executor) -> Value { Value::list( self.iter().map(|e| executor.resolve_into_value(e)).collect() ) @@ -103,7 +103,7 @@ impl<'a, T, CtxT> GraphQLType for &'a [T] where T: GraphQLType { registry.build_list_type::().into_meta() } - fn resolve(&self, _: Option>, executor: &Executor) -> Value { + fn resolve(&self, _: Option<&[Selection]>, executor: &Executor) -> Value { Value::list( self.iter().map(|e| executor.resolve_into_value(e)).collect() ) diff --git a/src/types/pointers.rs b/src/types/pointers.rs index 595f9db6..8b3962f2 100644 --- a/src/types/pointers.rs +++ b/src/types/pointers.rs @@ -16,7 +16,7 @@ impl GraphQLType for Box where T: GraphQLType { T::meta(registry) } - fn resolve_into_type(&self, name: &str, selection_set: Option>, executor: &Executor) -> ExecutionResult { + fn resolve_into_type(&self, name: &str, selection_set: Option<&[Selection]>, executor: &Executor) -> ExecutionResult { (**self).resolve_into_type(name, selection_set, executor) } @@ -25,7 +25,7 @@ impl GraphQLType for Box where T: GraphQLType { (**self).resolve_field(field, args, executor) } - fn resolve(&self, selection_set: Option>, executor: &Executor) -> Value { + fn resolve(&self, selection_set: Option<&[Selection]>, executor: &Executor) -> Value { (**self).resolve(selection_set, executor) } } @@ -56,7 +56,7 @@ impl<'a, T, CtxT> GraphQLType for &'a T where T: GraphQLType { T::meta(registry) } - fn resolve_into_type(&self, name: &str, selection_set: Option>, executor: &Executor) -> ExecutionResult { + fn resolve_into_type(&self, name: &str, selection_set: Option<&[Selection]>, executor: &Executor) -> ExecutionResult { (**self).resolve_into_type(name, selection_set, executor) } @@ -65,7 +65,7 @@ impl<'a, T, CtxT> GraphQLType for &'a T where T: GraphQLType { (**self).resolve_field(field, args, executor) } - fn resolve(&self, selection_set: Option>, executor: &Executor) -> Value { + fn resolve(&self, selection_set: Option<&[Selection]>, executor: &Executor) -> Value { (**self).resolve(selection_set, executor) } } diff --git a/src/types/scalars.rs b/src/types/scalars.rs index f08b7adf..4687803c 100644 --- a/src/types/scalars.rs +++ b/src/types/scalars.rs @@ -53,7 +53,7 @@ impl<'a> GraphQLType for &'a str { registry.build_scalar_type::().into_meta() } - fn resolve(&self, _: Option>, _: &Executor) -> Value { + fn resolve(&self, _: Option<&[Selection]>, _: &Executor) -> Value { Value::string(self) } }