reflectapi_schema/
visit.rs

1use std::ops::ControlFlow;
2
3use crate::{
4    Enum, Field, Function, Primitive, Schema, Struct, Type, TypeParameter, TypeReference,
5    Typespace, Variant,
6};
7
8pub trait Zero {
9    const ZERO: Self;
10}
11
12impl Zero for usize {
13    const ZERO: Self = 0;
14}
15
16impl Combine for usize {
17    fn combine(self, other: Self) -> Self {
18        self + other
19    }
20}
21
22impl Zero for () {
23    const ZERO: Self = ();
24}
25
26impl Combine for () {
27    fn combine(self, _other: Self) -> Self {}
28}
29
30/// Associative operation for combining two values.
31pub trait Combine: Zero {
32    fn combine(self, other: Self) -> Self;
33}
34
35/// A trait for traversing a `Schema` and its children.
36pub trait Visitor: Sized {
37    // Would be nice to just use `std::ops::Add` but not implemented on `()`
38    type Output: Combine;
39
40    fn visit_schema_inputs(&mut self, s: &mut Schema) -> ControlFlow<Self::Output, Self::Output> {
41        ControlFlow::Continue(
42            s.input_types.visit_mut(self)?.combine(
43                s.functions
44                    .iter_mut()
45                    .try_fold(Self::Output::ZERO, |acc, f| {
46                        ControlFlow::Continue(acc.combine(self.visit_function_inputs(f)?))
47                    })?,
48            ),
49        )
50    }
51
52    fn visit_schema_outputs(&mut self, s: &mut Schema) -> ControlFlow<Self::Output, Self::Output> {
53        ControlFlow::Continue(
54            s.output_types.visit_mut(self)?.combine(
55                s.functions
56                    .iter_mut()
57                    .try_fold(Self::Output::ZERO, |acc, f| {
58                        ControlFlow::Continue(acc.combine(self.visit_function_outputs(f)?))
59                    })?,
60            ),
61        )
62    }
63
64    fn visit_function_inputs(
65        &mut self,
66        f: &mut Function,
67    ) -> ControlFlow<Self::Output, Self::Output> {
68        let mut acc = Self::Output::ZERO;
69        if let Some(input_type) = &mut f.input_type {
70            acc = acc.combine(self.visit_type_ref(input_type)?);
71        }
72
73        if let Some(input_headers) = &mut f.input_headers {
74            acc = acc.combine(self.visit_type_ref(input_headers)?);
75        }
76
77        ControlFlow::Continue(acc)
78    }
79
80    fn visit_function_outputs(
81        &mut self,
82        f: &mut Function,
83    ) -> ControlFlow<Self::Output, Self::Output> {
84        let mut acc = Self::Output::ZERO;
85        if let Some(output_type) = &mut f.output_type {
86            acc = acc.combine(self.visit_type_ref(output_type)?);
87        }
88
89        if let Some(output_headers) = &mut f.error_type {
90            acc = acc.combine(self.visit_type_ref(output_headers)?);
91        }
92
93        ControlFlow::Continue(acc)
94    }
95
96    fn visit_type(&mut self, t: &mut Type) -> ControlFlow<Self::Output, Self::Output> {
97        t.visit_mut(self)
98    }
99
100    fn visit_enum(&mut self, e: &mut Enum) -> ControlFlow<Self::Output, Self::Output> {
101        e.visit_mut(self)
102    }
103
104    fn visit_variant(&mut self, v: &mut Variant) -> ControlFlow<Self::Output, Self::Output> {
105        v.visit_mut(self)
106    }
107
108    fn visit_struct(&mut self, s: &mut Struct) -> ControlFlow<Self::Output, Self::Output> {
109        s.visit_mut(self)
110    }
111
112    fn visit_primitive(&mut self, p: &mut Primitive) -> ControlFlow<Self::Output, Self::Output> {
113        p.visit_mut(self)
114    }
115
116    fn visit_type_parameter(
117        &mut self,
118        _p: &mut TypeParameter,
119    ) -> ControlFlow<Self::Output, Self::Output> {
120        ControlFlow::Continue(Self::Output::ZERO)
121    }
122
123    fn visit_field(&mut self, f: &mut Field) -> ControlFlow<Self::Output, Self::Output> {
124        f.visit_mut(self)
125    }
126
127    fn visit_type_ref(
128        &mut self,
129        type_ref: &mut TypeReference,
130    ) -> ControlFlow<Self::Output, Self::Output> {
131        type_ref.visit_mut(self)
132    }
133
134    // Only called for `Struct`, `Enum`, `Primitive`, and `TypeReference` names
135    fn visit_top_level_name(
136        &mut self,
137        _name: &mut String,
138    ) -> ControlFlow<Self::Output, Self::Output> {
139        ControlFlow::Continue(Self::Output::ZERO)
140    }
141}
142
143pub trait VisitMut {
144    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output>;
145}
146
147impl VisitMut for Typespace {
148    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
149        self.invalidate_types_map();
150        self.types.iter_mut().try_fold(V::Output::ZERO, |acc, t| {
151            ControlFlow::Continue(acc.combine(visitor.visit_type(t)?))
152        })
153    }
154}
155
156impl VisitMut for Type {
157    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
158        match self {
159            Type::Struct(s) => visitor.visit_struct(s),
160            Type::Enum(e) => visitor.visit_enum(e),
161            Type::Primitive(p) => visitor.visit_primitive(p),
162        }
163    }
164}
165
166impl VisitMut for Struct {
167    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
168        let ps = self
169            .parameters
170            .iter_mut()
171            .try_fold(V::Output::ZERO, |acc, p| {
172                ControlFlow::Continue(acc.combine(visitor.visit_type_parameter(p)?))
173            })?;
174
175        let fs = self.fields.iter_mut().try_fold(V::Output::ZERO, |acc, f| {
176            ControlFlow::Continue(acc.combine(visitor.visit_field(f)?))
177        })?;
178
179        ControlFlow::Continue(
180            ps.combine(fs)
181                .combine(visitor.visit_top_level_name(&mut self.name)?),
182        )
183    }
184}
185
186impl VisitMut for Enum {
187    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
188        let ps = self
189            .parameters
190            .iter_mut()
191            .try_fold(V::Output::ZERO, |acc, p| {
192                ControlFlow::Continue(acc.combine(visitor.visit_type_parameter(p)?))
193            })?;
194
195        let vs = self
196            .variants
197            .iter_mut()
198            .try_fold(V::Output::ZERO, |acc, v| {
199                ControlFlow::Continue(acc.combine(visitor.visit_variant(v)?))
200            })?;
201
202        ControlFlow::Continue(
203            ps.combine(vs)
204                .combine(visitor.visit_top_level_name(&mut self.name)?),
205        )
206    }
207}
208
209impl VisitMut for Variant {
210    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
211        self.fields.iter_mut().try_fold(V::Output::ZERO, |acc, f| {
212            ControlFlow::Continue(acc.combine(visitor.visit_field(f)?))
213        })
214    }
215}
216
217impl VisitMut for Primitive {
218    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
219        ControlFlow::Continue(
220            self.parameters
221                .iter_mut()
222                .try_fold(V::Output::ZERO, |acc, p| {
223                    ControlFlow::Continue(acc.combine(visitor.visit_type_parameter(p)?))
224                })?
225                .combine(visitor.visit_top_level_name(&mut self.name)?),
226        )
227    }
228}
229
230impl VisitMut for Field {
231    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
232        visitor.visit_type_ref(&mut self.type_ref)
233    }
234}
235
236impl VisitMut for TypeReference {
237    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
238        ControlFlow::Continue(
239            self.arguments
240                .iter_mut()
241                .try_fold(V::Output::ZERO, |acc, a| {
242                    ControlFlow::Continue(acc.combine(visitor.visit_type_ref(a)?))
243                })?
244                .combine(visitor.visit_top_level_name(&mut self.name)?),
245        )
246    }
247}