Skip to main content

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        match &mut f.output_type {
86            crate::OutputType::Complete { output_type } => {
87                if let Some(output_type) = output_type {
88                    acc = acc.combine(self.visit_type_ref(output_type)?);
89                }
90            }
91            crate::OutputType::Stream { item_type } => {
92                acc = acc.combine(self.visit_type_ref(item_type)?);
93            }
94        }
95
96        if let Some(output_headers) = &mut f.error_type {
97            acc = acc.combine(self.visit_type_ref(output_headers)?);
98        }
99
100        ControlFlow::Continue(acc)
101    }
102
103    fn visit_type(&mut self, t: &mut Type) -> ControlFlow<Self::Output, Self::Output> {
104        t.visit_mut(self)
105    }
106
107    fn visit_enum(&mut self, e: &mut Enum) -> ControlFlow<Self::Output, Self::Output> {
108        e.visit_mut(self)
109    }
110
111    fn visit_variant(&mut self, v: &mut Variant) -> ControlFlow<Self::Output, Self::Output> {
112        v.visit_mut(self)
113    }
114
115    fn visit_struct(&mut self, s: &mut Struct) -> ControlFlow<Self::Output, Self::Output> {
116        s.visit_mut(self)
117    }
118
119    fn visit_primitive(&mut self, p: &mut Primitive) -> ControlFlow<Self::Output, Self::Output> {
120        p.visit_mut(self)
121    }
122
123    fn visit_type_parameter(
124        &mut self,
125        _p: &mut TypeParameter,
126    ) -> ControlFlow<Self::Output, Self::Output> {
127        ControlFlow::Continue(Self::Output::ZERO)
128    }
129
130    fn visit_field(&mut self, f: &mut Field) -> ControlFlow<Self::Output, Self::Output> {
131        f.visit_mut(self)
132    }
133
134    fn visit_type_ref(
135        &mut self,
136        type_ref: &mut TypeReference,
137    ) -> ControlFlow<Self::Output, Self::Output> {
138        type_ref.visit_mut(self)
139    }
140
141    // Only called for `Struct`, `Enum`, `Primitive`, and `TypeReference` names
142    fn visit_top_level_name(
143        &mut self,
144        _name: &mut String,
145    ) -> ControlFlow<Self::Output, Self::Output> {
146        ControlFlow::Continue(Self::Output::ZERO)
147    }
148}
149
150pub trait VisitMut {
151    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output>;
152}
153
154impl VisitMut for Typespace {
155    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
156        self.invalidate_types_map();
157        self.types.iter_mut().try_fold(V::Output::ZERO, |acc, t| {
158            ControlFlow::Continue(acc.combine(visitor.visit_type(t)?))
159        })
160    }
161}
162
163impl VisitMut for Type {
164    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
165        match self {
166            Type::Struct(s) => visitor.visit_struct(s),
167            Type::Enum(e) => visitor.visit_enum(e),
168            Type::Primitive(p) => visitor.visit_primitive(p),
169        }
170    }
171}
172
173impl VisitMut for Struct {
174    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
175        let ps = self
176            .parameters
177            .iter_mut()
178            .try_fold(V::Output::ZERO, |acc, p| {
179                ControlFlow::Continue(acc.combine(visitor.visit_type_parameter(p)?))
180            })?;
181
182        let fs = self.fields.iter_mut().try_fold(V::Output::ZERO, |acc, f| {
183            ControlFlow::Continue(acc.combine(visitor.visit_field(f)?))
184        })?;
185
186        ControlFlow::Continue(
187            ps.combine(fs)
188                .combine(visitor.visit_top_level_name(&mut self.name)?),
189        )
190    }
191}
192
193impl VisitMut for Enum {
194    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
195        let ps = self
196            .parameters
197            .iter_mut()
198            .try_fold(V::Output::ZERO, |acc, p| {
199                ControlFlow::Continue(acc.combine(visitor.visit_type_parameter(p)?))
200            })?;
201
202        let vs = self
203            .variants
204            .iter_mut()
205            .try_fold(V::Output::ZERO, |acc, v| {
206                ControlFlow::Continue(acc.combine(visitor.visit_variant(v)?))
207            })?;
208
209        ControlFlow::Continue(
210            ps.combine(vs)
211                .combine(visitor.visit_top_level_name(&mut self.name)?),
212        )
213    }
214}
215
216impl VisitMut for Variant {
217    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
218        self.fields.iter_mut().try_fold(V::Output::ZERO, |acc, f| {
219            ControlFlow::Continue(acc.combine(visitor.visit_field(f)?))
220        })
221    }
222}
223
224impl VisitMut for Primitive {
225    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
226        ControlFlow::Continue(
227            self.parameters
228                .iter_mut()
229                .try_fold(V::Output::ZERO, |acc, p| {
230                    ControlFlow::Continue(acc.combine(visitor.visit_type_parameter(p)?))
231                })?
232                .combine(visitor.visit_top_level_name(&mut self.name)?),
233        )
234    }
235}
236
237impl VisitMut for Field {
238    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
239        visitor.visit_type_ref(&mut self.type_ref)
240    }
241}
242
243impl VisitMut for TypeReference {
244    fn visit_mut<V: Visitor>(&mut self, visitor: &mut V) -> ControlFlow<V::Output, V::Output> {
245        ControlFlow::Continue(
246            self.arguments
247                .iter_mut()
248                .try_fold(V::Output::ZERO, |acc, a| {
249                    ControlFlow::Continue(acc.combine(visitor.visit_type_ref(a)?))
250                })?
251                .combine(visitor.visit_top_level_name(&mut self.name)?),
252        )
253    }
254}