bluejay_validator/executable/document/
rule.rs1use crate::executable::{
2 document::{Path, Visitor},
3 Cache,
4};
5use bluejay_core::definition::{DirectiveLocation, SchemaDefinition, TypeDefinitionReference};
6use bluejay_core::executable::ExecutableDocument;
7use std::marker::PhantomData;
8
9pub trait Rule<'a, E: ExecutableDocument, S: SchemaDefinition>: Visitor<'a, E, S> {
10 type Error;
11 type Errors: Iterator<Item = Self::Error>;
12
13 fn into_errors(self) -> Self::Errors;
14}
15
16macro_rules! impl_rule {
17 ($n:literal) => {
18 seq_macro::seq!(N in 0..$n {
19 #[warn(clippy::missing_trait_methods)]
20 impl<'a, E: ExecutableDocument, S: SchemaDefinition, ER, #(T~N: Rule<'a, E, S, Error = ER>,)*> Rule<'a, E, S> for (#(T~N,)*) {
21 type Error = ER;
22 type Errors = #(std::iter::Chain<)* std::iter::Empty<ER> #(, <T~N as Rule<'a, E, S>>::Errors>)*;
23
24 fn into_errors(self) -> Self::Errors {
25 std::iter::empty() #(.chain(self.N.into_errors()))*
26 }
27 }
28 });
29 }
30}
31
32seq_macro::seq!(N in 2..=10 {
33 impl_rule!(N);
34});
35
36impl_rule!(26);
37
38pub struct RuleErrorAdapter<R, ER> {
39 rule: R,
40 error: PhantomData<ER>,
41}
42
43#[warn(clippy::missing_trait_methods)]
44impl<'a, E: ExecutableDocument, S: SchemaDefinition, R: Rule<'a, E, S>, ER> Visitor<'a, E, S>
45 for RuleErrorAdapter<R, ER>
46{
47 fn new(
48 executable_document: &'a E,
49 schema_definition: &'a S,
50 cache: &'a Cache<'a, E, S>,
51 ) -> Self {
52 Self {
53 rule: R::new(executable_document, schema_definition, cache),
54 error: PhantomData,
55 }
56 }
57
58 fn visit_operation_definition(&mut self, operation_definition: &'a E::OperationDefinition) {
59 self.rule.visit_operation_definition(operation_definition);
60 }
61
62 fn visit_selection_set(
63 &mut self,
64 selection_set: &'a E::SelectionSet,
65 r#type: TypeDefinitionReference<'a, S::TypeDefinition>,
66 ) {
67 self.rule.visit_selection_set(selection_set, r#type);
68 }
69
70 fn visit_field(
71 &mut self,
72 field: &'a E::Field,
73 field_definition: &'a S::FieldDefinition,
74 path: &Path<'a, E>,
75 ) {
76 self.rule.visit_field(field, field_definition, path);
77 }
78
79 fn visit_const_directive(
80 &mut self,
81 directive: &'a E::Directive<true>,
82 location: DirectiveLocation,
83 ) {
84 self.rule.visit_const_directive(directive, location);
85 }
86
87 fn visit_variable_directive(
88 &mut self,
89 directive: &'a E::Directive<false>,
90 location: DirectiveLocation,
91 ) {
92 self.rule.visit_variable_directive(directive, location);
93 }
94
95 fn visit_const_directives(
96 &mut self,
97 directives: &'a E::Directives<true>,
98 location: DirectiveLocation,
99 ) {
100 self.rule.visit_const_directives(directives, location);
101 }
102
103 fn visit_variable_directives(
104 &mut self,
105 directives: &'a E::Directives<false>,
106 location: DirectiveLocation,
107 ) {
108 self.rule.visit_variable_directives(directives, location);
109 }
110
111 fn visit_fragment_definition(&mut self, fragment_definition: &'a E::FragmentDefinition) {
112 self.rule.visit_fragment_definition(fragment_definition);
113 }
114
115 fn visit_inline_fragment(
116 &mut self,
117 inline_fragment: &'a E::InlineFragment,
118 scoped_type: TypeDefinitionReference<'a, S::TypeDefinition>,
119 ) {
120 self.rule
121 .visit_inline_fragment(inline_fragment, scoped_type);
122 }
123
124 fn visit_fragment_spread(
125 &mut self,
126 fragment_spread: &'a E::FragmentSpread,
127 scoped_type: TypeDefinitionReference<'a, S::TypeDefinition>,
128 path: &Path<'a, E>,
129 ) {
130 self.rule
131 .visit_fragment_spread(fragment_spread, scoped_type, path);
132 }
133
134 fn visit_const_argument(
135 &mut self,
136 argument: &'a E::Argument<true>,
137 input_value_definition: &'a S::InputValueDefinition,
138 ) {
139 self.rule
140 .visit_const_argument(argument, input_value_definition);
141 }
142
143 fn visit_variable_argument(
144 &mut self,
145 argument: &'a E::Argument<false>,
146 input_value_definition: &'a S::InputValueDefinition,
147 path: &Path<'a, E>,
148 ) {
149 self.rule
150 .visit_variable_argument(argument, input_value_definition, path)
151 }
152
153 fn visit_variable_definition(&mut self, variable_definition: &'a E::VariableDefinition) {
154 self.rule.visit_variable_definition(variable_definition);
155 }
156
157 fn visit_variable_definitions(&mut self, variable_definitions: &'a E::VariableDefinitions) {
158 self.rule.visit_variable_definitions(variable_definitions);
159 }
160}
161
162#[warn(clippy::missing_trait_methods)]
163impl<
164 'a,
165 E: ExecutableDocument,
166 S: SchemaDefinition,
167 R: Rule<'a, E, S>,
168 ER: From<<R as Rule<'a, E, S>>::Error>,
169 > Rule<'a, E, S> for RuleErrorAdapter<R, ER>
170{
171 type Error = ER;
172 type Errors =
173 std::iter::Map<<R as Rule<'a, E, S>>::Errors, fn(<R as Rule<'a, E, S>>::Error) -> ER>;
174
175 fn into_errors(self) -> Self::Errors {
176 self.rule.into_errors().map(ER::from)
177 }
178}