shape/
visitor.rs

1use indexmap::IndexMap;
2
3use crate::case_enum::all::All;
4use crate::case_enum::one::One;
5use crate::name::Name;
6use crate::name::WeakScope;
7use crate::Error;
8use crate::Shape;
9use crate::ShapeCase;
10
11#[expect(unused_variables, clippy::missing_errors_doc)]
12pub trait ShapeVisitor<Output = ()> {
13    type Error: std::error::Error;
14    type Output;
15
16    fn default(&mut self, shape: &Shape) -> Result<Self::Output, Self::Error>;
17
18    fn visit_bool(
19        &mut self,
20        shape: &Shape,
21        value: &Option<bool>,
22    ) -> Result<Self::Output, Self::Error> {
23        self.default(shape)
24    }
25
26    fn visit_string(
27        &mut self,
28        shape: &Shape,
29        value: &Option<String>,
30    ) -> Result<Self::Output, Self::Error> {
31        self.default(shape)
32    }
33
34    fn visit_int(
35        &mut self,
36        shape: &Shape,
37        value: &Option<i64>,
38    ) -> Result<Self::Output, Self::Error> {
39        self.default(shape)
40    }
41
42    fn visit_float(&mut self, shape: &Shape) -> Result<Self::Output, Self::Error> {
43        self.default(shape)
44    }
45
46    fn visit_null(&mut self, shape: &Shape) -> Result<Self::Output, Self::Error> {
47        self.default(shape)
48    }
49
50    fn visit_array(
51        &mut self,
52        shape: &Shape,
53        prefix: &[Shape],
54        tail: &Shape,
55    ) -> Result<Self::Output, Self::Error> {
56        self.default(shape)
57    }
58
59    fn visit_object(
60        &mut self,
61        shape: &Shape,
62        fields: &IndexMap<String, Shape>,
63        rest: &Shape,
64    ) -> Result<Self::Output, Self::Error> {
65        self.default(shape)
66    }
67
68    fn visit_one(&mut self, shape: &Shape, one: &One) -> Result<Self::Output, Self::Error> {
69        self.default(shape)
70    }
71
72    fn visit_name(
73        &mut self,
74        shape: &Shape,
75        name: &Name,
76        weak: &WeakScope,
77    ) -> Result<Self::Output, Self::Error> {
78        self.default(shape)
79    }
80
81    fn visit_unknown(&mut self, shape: &Shape) -> Result<Self::Output, Self::Error> {
82        self.default(shape)
83    }
84
85    fn visit_none(&mut self, shape: &Shape) -> Result<Self::Output, Self::Error> {
86        self.default(shape)
87    }
88
89    fn visit_error(&mut self, shape: &Shape, err: &Error) -> Result<Self::Output, Self::Error> {
90        self.default(shape)
91    }
92
93    fn visit_all(&mut self, shape: &Shape, all: &All) -> Result<Self::Output, Self::Error> {
94        self.default(shape)
95    }
96}
97
98impl Shape {
99    #[expect(clippy::missing_errors_doc)]
100    pub fn visit_shape<V: ShapeVisitor>(&self, visitor: &mut V) -> Result<V::Output, V::Error> {
101        match self.case() {
102            ShapeCase::Bool(b) => visitor.visit_bool(self, b),
103            ShapeCase::String(s) => visitor.visit_string(self, s),
104            ShapeCase::Int(i) => visitor.visit_int(self, i),
105            ShapeCase::Float => visitor.visit_float(self),
106            ShapeCase::Null => visitor.visit_null(self),
107            ShapeCase::Array { prefix, tail } => visitor.visit_array(self, prefix, tail),
108            ShapeCase::Object { fields, rest } => visitor.visit_object(self, fields, rest),
109            ShapeCase::One(one) => visitor.visit_one(self, one),
110            ShapeCase::All(all) => visitor.visit_all(self, all),
111            // Visitor implementations may call weak.upgrade(name) to get the
112            // resolved target of the name, if any. It's tempting to perform
113            // that resolution here unconditionally, but then the visitor could
114            // fall into an infinitely deep cycle, so we have to let the
115            // implementation of visit_name decide whether to proceed further.
116            ShapeCase::Name(name, weak) => visitor.visit_name(self, name, weak),
117            ShapeCase::Unknown => visitor.visit_unknown(self),
118            ShapeCase::None => visitor.visit_none(self),
119            ShapeCase::Error(err) => visitor.visit_error(self, err),
120        }
121    }
122}