diff --git a/src/validation/mod.rs b/src/validation/mod.rs index ea2c98f3..80b30de2 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -14,7 +14,7 @@ pub use self::traits::Visitor; pub use self::visitor::visit; pub use self::context::{RuleError, ValidatorContext}; pub use self::rules::visit_all_rules; -pub use self::multi_visitor::MultiVisitor; +pub use self::multi_visitor::{MultiVisitor, MultiVisitorNil}; pub use self::input_value::validate_input_values; #[cfg(test)] diff --git a/src/validation/multi_visitor.rs b/src/validation/multi_visitor.rs index 8fdd8618..c5ba9df7 100644 --- a/src/validation/multi_visitor.rs +++ b/src/validation/multi_visitor.rs @@ -4,26 +4,32 @@ use parser::Spanning; use validation::{ValidatorContext, Visitor}; #[doc(hidden)] -pub struct MultiVisitor<'a> { - visitors: Vec + 'a>> -} +pub trait MultiVisitor<'a> { + fn visit_all) -> ()>(&mut self, f: F); -impl<'a> MultiVisitor<'a> { - #[doc(hidden)] - pub fn new(visitors: Vec + 'a>>) -> MultiVisitor<'a> { - MultiVisitor { - visitors: visitors - } - } - - fn visit_all + 'a>) -> ()>(&mut self, mut f: F) { - for mut v in &mut self.visitors { - f(v); - } + fn with>(self, visitor: V) -> MultiVisitorCons where Self: Sized { + MultiVisitorCons(visitor, self) } } -impl<'a> Visitor<'a> for MultiVisitor<'a> { +#[doc(hidden)] +pub struct MultiVisitorNil; + +impl<'a> MultiVisitor<'a> for MultiVisitorNil { + fn visit_all) -> ()>(&mut self, _: F) {} +} + +#[doc(hidden)] +pub struct MultiVisitorCons(A, B); + +impl<'a, A: Visitor<'a>, B: MultiVisitor<'a>> MultiVisitor<'a> for MultiVisitorCons { + fn visit_all) -> ()>(&mut self, mut f: F) { + f(&mut self.0); + self.1.visit_all(f); + } +} + +impl<'a, M> Visitor<'a> for M where M: MultiVisitor<'a> { fn enter_document(&mut self, ctx: &mut ValidatorContext<'a>, doc: &'a Document) { self.visit_all(|v| v.enter_document(ctx, doc)); } diff --git a/src/validation/rules/mod.rs b/src/validation/rules/mod.rs index f5aa96b2..44404d88 100644 --- a/src/validation/rules/mod.rs +++ b/src/validation/rules/mod.rs @@ -24,36 +24,35 @@ mod variables_are_input_types; mod variables_in_allowed_position; use ast::Document; -use validation::{ValidatorContext, MultiVisitor, visit}; +use validation::{ValidatorContext, MultiVisitor, MultiVisitorNil, visit}; #[doc(hidden)] pub fn visit_all_rules<'a>(ctx: &mut ValidatorContext<'a>, doc: &'a Document) { - let mut mv = MultiVisitor::new(vec![ - Box::new(self::arguments_of_correct_type::factory()), - Box::new(self::default_values_of_correct_type::factory()), - Box::new(self::fields_on_correct_type::factory()), - Box::new(self::fragments_on_composite_types::factory()), - Box::new(self::known_argument_names::factory()), - Box::new(self::known_directives::factory()), - Box::new(self::known_fragment_names::factory()), - Box::new(self::known_type_names::factory()), - Box::new(self::lone_anonymous_operation::factory()), - Box::new(self::no_fragment_cycles::factory()), - Box::new(self::no_undefined_variables::factory()), - Box::new(self::no_unused_fragments::factory()), - Box::new(self::no_unused_variables::factory()), - Box::new(self::overlapping_fields_can_be_merged::factory()), - Box::new(self::possible_fragment_spreads::factory()), - Box::new(self::provided_non_null_arguments::factory()), - Box::new(self::scalar_leafs::factory()), - Box::new(self::unique_argument_names::factory()), - Box::new(self::unique_fragment_names::factory()), - Box::new(self::unique_input_field_names::factory()), - Box::new(self::unique_operation_names::factory()), - Box::new(self::unique_variable_names::factory()), - Box::new(self::variables_are_input_types::factory()), - Box::new(self::variables_in_allowed_position::factory()), - ]); + let mut mv = MultiVisitorNil + .with(self::arguments_of_correct_type::factory()) + .with(self::default_values_of_correct_type::factory()) + .with(self::fields_on_correct_type::factory()) + .with(self::fragments_on_composite_types::factory()) + .with(self::known_argument_names::factory()) + .with(self::known_directives::factory()) + .with(self::known_fragment_names::factory()) + .with(self::known_type_names::factory()) + .with(self::lone_anonymous_operation::factory()) + .with(self::no_fragment_cycles::factory()) + .with(self::no_undefined_variables::factory()) + .with(self::no_unused_fragments::factory()) + .with(self::no_unused_variables::factory()) + .with(self::overlapping_fields_can_be_merged::factory()) + .with(self::possible_fragment_spreads::factory()) + .with(self::provided_non_null_arguments::factory()) + .with(self::scalar_leafs::factory()) + .with(self::unique_argument_names::factory()) + .with(self::unique_fragment_names::factory()) + .with(self::unique_input_field_names::factory()) + .with(self::unique_operation_names::factory()) + .with(self::unique_variable_names::factory()) + .with(self::variables_are_input_types::factory()) + .with(self::variables_in_allowed_position::factory()); visit(&mut mv, ctx, doc); } diff --git a/src/validation/test_harness.rs b/src/validation/test_harness.rs index aa07488e..04b23c76 100644 --- a/src/validation/test_harness.rs +++ b/src/validation/test_harness.rs @@ -5,7 +5,7 @@ use executor::Registry; use types::scalars::{EmptyMutation, ID}; use schema::model::{DirectiveType, DirectiveLocation, RootNode}; use schema::meta::{EnumValue, MetaType}; -use validation::{Visitor, RuleError, ValidatorContext, MultiVisitor, visit}; +use validation::{Visitor, RuleError, ValidatorContext, MultiVisitor, MultiVisitorNil, visit}; struct Being; struct Pet; @@ -473,7 +473,7 @@ pub fn validate<'a, R, V, F>(r: R, q: &'a str, factory: F) unsafe { ::std::mem::transmute(&root.schema) }, &doc); - let mut mv = MultiVisitor::new(vec![ Box::new(factory()) ]); + let mut mv = MultiVisitorNil.with(factory()); visit(&mut mv, &mut ctx, unsafe { ::std::mem::transmute(&doc) }); ctx.into_errors()