diff --git a/Cargo.lock b/Cargo.lock index 2d6f210e..c75af68d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,7 +180,6 @@ dependencies = [ "insta", "itertools 0.15.0", "once_cell", - "paste", "seq-macro", "serde_json", ] @@ -736,12 +735,6 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "plotters" version = "0.3.7" diff --git a/bluejay-validator/Cargo.toml b/bluejay-validator/Cargo.toml index e99f2609..37861ecc 100644 --- a/bluejay-validator/Cargo.toml +++ b/bluejay-validator/Cargo.toml @@ -13,7 +13,6 @@ description = "A GraphQL validator" [dependencies] bluejay-core = { workspace = true } bluejay-parser = { workspace = true, optional = true, features = ["format-errors"] } -paste = "1.0" itertools = "0.15.0" serde_json = { version = "1.0", optional = true } seq-macro = "0.3.5" diff --git a/bluejay-validator/src/chain_iters.rs b/bluejay-validator/src/chain_iters.rs deleted file mode 100644 index 68c0a681..00000000 --- a/bluejay-validator/src/chain_iters.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[macro_export] -macro_rules! chain_types { - ( $first:ty, $( $rest:ty ),+ $(,)? ) => { - std::iter::Chain<$crate::chain_types!($($rest),+), $first> - }; - ( $t:ty ) => { $t }; -} - -#[macro_export] -macro_rules! chain_iters { - ( $first:expr, $( $rest:expr ),+ $(,)? ) => { - $crate::chain_iters!($($rest),+).chain($first) - }; - ( $iter:expr ) => { $iter }; -} diff --git a/bluejay-validator/src/definition/rule.rs b/bluejay-validator/src/definition/rule.rs index 17183e05..0d5e6826 100644 --- a/bluejay-validator/src/definition/rule.rs +++ b/bluejay-validator/src/definition/rule.rs @@ -1,8 +1,28 @@ use crate::definition::Visitor; use bluejay_core::definition::SchemaDefinition; -pub trait Rule<'a, S: SchemaDefinition>: Visitor<'a, S> + IntoIterator { +pub trait Rule<'a, S: SchemaDefinition>: Visitor<'a, S> { type Error; + type Errors: Iterator; - fn new(schema_definition: &'a S) -> Self; + fn into_errors(self) -> Self::Errors; } + +macro_rules! impl_rule { + ($n:literal) => { + seq_macro::seq!(N in 0..$n { + impl<'a, S: SchemaDefinition, ER, #(T~N: Rule<'a, S, Error = ER>,)*> Rule<'a, S> for (#(T~N,)*) { + type Error = ER; + type Errors = #(std::iter::Chain<)* std::iter::Empty #(, >::Errors>)*; + + fn into_errors(self) -> Self::Errors { + std::iter::empty() #(.chain(self.N.into_errors()))* + } + } + }); + } +} + +seq_macro::seq!(N in 2..=10 { + impl_rule!(N); +}); diff --git a/bluejay-validator/src/definition/rules.rs b/bluejay-validator/src/definition/rules.rs index 6ad03f35..faabe11b 100644 --- a/bluejay-validator/src/definition/rules.rs +++ b/bluejay-validator/src/definition/rules.rs @@ -6,52 +6,8 @@ pub use enum_value_definition_uniqueness::EnumValueDefinitionUniqueness; pub use input_field_definition_uniqueness::InputFieldDefinitionUniqueness; pub use input_object_circular_references::InputObjectCircularReferences; -#[macro_export] -macro_rules! combine_definition_rules { - ( $name:ty, $err:ty, [$( $rule:ty ),* $(,)?] $(,)? ) => { - paste::paste! { - pub struct $name<'a, S: bluejay_core::definition::SchemaDefinition> { - $([<$rule:snake>]: $rule<'a, S>,)* - } - - impl<'a, S: bluejay_core::definition::SchemaDefinition + 'a> $crate::definition::Rule<'a, S> for $name<'a, S> { - type Error = $err<'a, S>; - - fn new(schema_definition: &'a S) -> Self { - Self { - $([<$rule:snake>]: $rule::new(schema_definition),)* - } - } - } - - impl<'a, S: bluejay_core::definition::SchemaDefinition + 'a> IntoIterator for $name<'a, S> { - type Item = $err<'a, S>; - type IntoIter = $crate::chain_types!($(std::iter::Map<<$rule<'a, S> as IntoIterator>::IntoIter, fn(<$rule<'a, S> as $crate::definition::Rule<'a, S>>::Error) -> $err<'a, S>>),*); - - fn into_iter(self) -> Self::IntoIter { - $crate::chain_iters!($(self.[<$rule:snake>].into_iter().map(Into::into as fn(<$rule<'a, S> as $crate::definition::Rule<'a, S>>::Error) -> $err<'a, S>)),*) - } - } - - impl<'a, S: bluejay_core::definition::SchemaDefinition> $crate::definition::Visitor<'a, S> for $name<'a, S> { - fn visit_input_object_type_definition(&mut self, input_object_type_definition: &'a S::InputObjectTypeDefinition) { - $(self.[<$rule:snake>].visit_input_object_type_definition(input_object_type_definition);)* - } - - fn visit_enum_type_definition(&mut self, enum_type_definition: &'a S::EnumTypeDefinition) { - $(self.[<$rule:snake>].visit_enum_type_definition(enum_type_definition);)* - } - } - } - }; -} - -combine_definition_rules!( - BuiltinRules, - crate::definition::Error, - [ - EnumValueDefinitionUniqueness, - InputFieldDefinitionUniqueness, - InputObjectCircularReferences, - ], +pub type BuiltinRules<'a, S> = ( + EnumValueDefinitionUniqueness<'a, S>, + InputFieldDefinitionUniqueness<'a, S>, + InputObjectCircularReferences<'a, S>, ); diff --git a/bluejay-validator/src/definition/rules/enum_value_definition_uniqueness.rs b/bluejay-validator/src/definition/rules/enum_value_definition_uniqueness.rs index 0c2db99e..6431c3ef 100644 --- a/bluejay-validator/src/definition/rules/enum_value_definition_uniqueness.rs +++ b/bluejay-validator/src/definition/rules/enum_value_definition_uniqueness.rs @@ -8,6 +8,10 @@ pub struct EnumValueDefinitionUniqueness<'a, S: SchemaDefinition + 'a> { } impl<'a, S: SchemaDefinition> Visitor<'a, S> for EnumValueDefinitionUniqueness<'a, S> { + fn new(_: &'a S) -> Self { + Self { errors: Vec::new() } + } + fn visit_enum_type_definition( &mut self, enum_type_definition: &'a ::EnumTypeDefinition, @@ -27,19 +31,11 @@ impl<'a, S: SchemaDefinition> Visitor<'a, S> for EnumValueDefinitionUniqueness<' } } -impl<'a, S: SchemaDefinition> IntoIterator for EnumValueDefinitionUniqueness<'a, S> { - type Item = Error<'a, S>; - type IntoIter = std::vec::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { - self.errors.into_iter() - } -} - impl<'a, S: SchemaDefinition> Rule<'a, S> for EnumValueDefinitionUniqueness<'a, S> { type Error = Error<'a, S>; + type Errors = std::vec::IntoIter>; - fn new(_: &'a S) -> Self { - Self { errors: Vec::new() } + fn into_errors(self) -> Self::Errors { + self.errors.into_iter() } } diff --git a/bluejay-validator/src/definition/rules/input_field_definition_uniqueness.rs b/bluejay-validator/src/definition/rules/input_field_definition_uniqueness.rs index 9d77e705..614b9534 100644 --- a/bluejay-validator/src/definition/rules/input_field_definition_uniqueness.rs +++ b/bluejay-validator/src/definition/rules/input_field_definition_uniqueness.rs @@ -8,6 +8,10 @@ pub struct InputFieldDefinitionUniqueness<'a, S: SchemaDefinition + 'a> { } impl<'a, S: SchemaDefinition> Visitor<'a, S> for InputFieldDefinitionUniqueness<'a, S> { + fn new(_: &'a S) -> Self { + Self { errors: Vec::new() } + } + fn visit_input_object_type_definition( &mut self, input_object_type_definition: &'a ::InputObjectTypeDefinition, @@ -29,19 +33,11 @@ impl<'a, S: SchemaDefinition> Visitor<'a, S> for InputFieldDefinitionUniqueness< } } -impl<'a, S: SchemaDefinition> IntoIterator for InputFieldDefinitionUniqueness<'a, S> { - type Item = Error<'a, S>; - type IntoIter = std::vec::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { - self.errors.into_iter() - } -} - impl<'a, S: SchemaDefinition> Rule<'a, S> for InputFieldDefinitionUniqueness<'a, S> { type Error = Error<'a, S>; + type Errors = std::vec::IntoIter>; - fn new(_: &'a S) -> Self { - Self { errors: Vec::new() } + fn into_errors(self) -> Self::Errors { + self.errors.into_iter() } } diff --git a/bluejay-validator/src/definition/rules/input_object_circular_references.rs b/bluejay-validator/src/definition/rules/input_object_circular_references.rs index 6c0deb96..2be5a090 100644 --- a/bluejay-validator/src/definition/rules/input_object_circular_references.rs +++ b/bluejay-validator/src/definition/rules/input_object_circular_references.rs @@ -12,6 +12,13 @@ pub struct InputObjectCircularReferences<'a, S: SchemaDefinition + 'a> { } impl<'a, S: SchemaDefinition> Visitor<'a, S> for InputObjectCircularReferences<'a, S> { + fn new(schema_definition: &'a S) -> Self { + Self { + schema_definition, + errors: Vec::new(), + } + } + fn visit_input_object_type_definition( &mut self, input_object_type_definition: &'a ::InputObjectTypeDefinition, @@ -66,22 +73,11 @@ impl<'a, S: SchemaDefinition + 'a> InputObjectCircularReferences<'a, S> { } } -impl<'a, S: SchemaDefinition> IntoIterator for InputObjectCircularReferences<'a, S> { - type Item = Error<'a, S>; - type IntoIter = std::vec::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { - self.errors.into_iter() - } -} - impl<'a, S: SchemaDefinition> Rule<'a, S> for InputObjectCircularReferences<'a, S> { type Error = Error<'a, S>; + type Errors = std::vec::IntoIter>; - fn new(schema_definition: &'a S) -> Self { - Self { - schema_definition, - errors: Vec::new(), - } + fn into_errors(self) -> Self::Errors { + self.errors.into_iter() } } diff --git a/bluejay-validator/src/definition/validator.rs b/bluejay-validator/src/definition/validator.rs index 1e653b09..fc712004 100644 --- a/bluejay-validator/src/definition/validator.rs +++ b/bluejay-validator/src/definition/validator.rs @@ -1,4 +1,4 @@ -use crate::definition::{BuiltinRules, Rule}; +use crate::definition::{BuiltinRules, Rule, Visitor}; use bluejay_core::definition::{SchemaDefinition, TypeDefinitionReference}; pub struct Validator<'a, S: SchemaDefinition, R: Rule<'a, S>> { @@ -12,7 +12,7 @@ impl<'a, S: SchemaDefinition, R: Rule<'a, S>> Validator<'a, S, R> { fn new(schema_definition: &'a S) -> Self { Self { schema_definition, - rule: Rule::new(schema_definition), + rule: Visitor::new(schema_definition), } } @@ -49,9 +49,9 @@ impl<'a, S: SchemaDefinition, R: Rule<'a, S>> Validator<'a, S, R> { impl<'a, S: SchemaDefinition, R: Rule<'a, S>> IntoIterator for Validator<'a, S, R> { type Item = R::Error; - type IntoIter = ::IntoIter; + type IntoIter = R::Errors; fn into_iter(self) -> Self::IntoIter { - self.rule.into_iter() + self.rule.into_errors() } } diff --git a/bluejay-validator/src/definition/visitor.rs b/bluejay-validator/src/definition/visitor.rs index 96c5f709..c935abef 100644 --- a/bluejay-validator/src/definition/visitor.rs +++ b/bluejay-validator/src/definition/visitor.rs @@ -1,6 +1,8 @@ use bluejay_core::definition::SchemaDefinition; pub trait Visitor<'a, S: SchemaDefinition> { + fn new(schema_definition: &'a S) -> Self; + fn visit_input_object_type_definition( &mut self, _input_object_type_definition: &'a S::InputObjectTypeDefinition, @@ -9,3 +11,34 @@ pub trait Visitor<'a, S: SchemaDefinition> { fn visit_enum_type_definition(&mut self, _enum_type_definition: &'a S::EnumTypeDefinition) {} } + +macro_rules! impl_visitor { + ($n:literal) => { + seq_macro::seq!(N in 0..$n { + #[warn(clippy::missing_trait_methods)] + impl<'a, S: SchemaDefinition, #(T~N: Visitor<'a, S>,)*> Visitor<'a, S> for (#(T~N,)*) { + fn new(schema_definition: &'a S) -> Self { + (#(T~N::new(schema_definition),)*) + } + + fn visit_input_object_type_definition( + &mut self, + input_object_type_definition: &'a S::InputObjectTypeDefinition, + ) { + #(self.N.visit_input_object_type_definition(input_object_type_definition);)* + } + + fn visit_enum_type_definition( + &mut self, + enum_type_definition: &'a S::EnumTypeDefinition, + ) { + #(self.N.visit_enum_type_definition(enum_type_definition);)* + } + } + }); + } +} + +seq_macro::seq!(N in 2..=10 { + impl_visitor!(N); +}); diff --git a/bluejay-validator/src/lib.rs b/bluejay-validator/src/lib.rs index 46e6aa62..76c78e24 100644 --- a/bluejay-validator/src/lib.rs +++ b/bluejay-validator/src/lib.rs @@ -1,4 +1,3 @@ -mod chain_iters; pub mod definition; pub mod executable; mod path;