Avoid boxing in MultiVisitor

This commit is contained in:
Sam Rijs 2017-07-03 08:38:14 +02:00 committed by Magnus Hallin
parent d15f9bd162
commit dc140a1ea0
4 changed files with 51 additions and 46 deletions

View file

@ -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)]

View file

@ -4,26 +4,32 @@ use parser::Spanning;
use validation::{ValidatorContext, Visitor};
#[doc(hidden)]
pub struct MultiVisitor<'a> {
visitors: Vec<Box<Visitor<'a> + 'a>>
}
pub trait MultiVisitor<'a> {
fn visit_all<F: FnMut(&mut Visitor<'a>) -> ()>(&mut self, f: F);
impl<'a> MultiVisitor<'a> {
#[doc(hidden)]
pub fn new(visitors: Vec<Box<Visitor<'a> + 'a>>) -> MultiVisitor<'a> {
MultiVisitor {
visitors: visitors
}
}
fn visit_all<F: FnMut(&mut Box<Visitor<'a> + 'a>) -> ()>(&mut self, mut f: F) {
for mut v in &mut self.visitors {
f(v);
}
fn with<V: Visitor<'a>>(self, visitor: V) -> MultiVisitorCons<V, Self> 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<F: FnMut(&mut Visitor<'a>) -> ()>(&mut self, _: F) {}
}
#[doc(hidden)]
pub struct MultiVisitorCons<A, B>(A, B);
impl<'a, A: Visitor<'a>, B: MultiVisitor<'a>> MultiVisitor<'a> for MultiVisitorCons<A, B> {
fn visit_all<F: FnMut(&mut Visitor<'a>) -> ()>(&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));
}

View file

@ -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);
}

View file

@ -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()