1use crate::yaml::{Document, Mapping, Scalar, Sequence, TaggedNode, YamlFile};
39
40pub trait YamlVisitor {
42 fn visit_yaml(&mut self, yaml: &YamlFile) {
44 for doc in yaml.documents() {
46 self.visit_document(&doc);
47 }
48 }
49
50 fn visit_document(&mut self, document: &Document) {
54 self.walk_document(document);
55 }
56
57 fn walk_document(&mut self, document: &Document) {
59 if let Some(tagged) = document.as_tagged() {
60 self.visit_tagged_node(&tagged);
61 } else if let Some(mapping) = document.as_mapping() {
62 self.visit_mapping(&mapping);
63 } else if let Some(sequence) = document.as_sequence() {
64 self.visit_sequence(&sequence);
65 } else if let Some(scalar) = document.as_scalar() {
66 self.visit_scalar(&scalar);
67 }
68 }
69
70 fn visit_scalar(&mut self, _scalar: &Scalar) {}
72
73 fn visit_mapping(&mut self, mapping: &Mapping) {
79 self.walk_mapping(mapping);
80 }
81
82 fn visit_sequence(&mut self, sequence: &Sequence) {
87 self.walk_sequence(sequence);
88 }
89
90 fn visit_tagged_node(&mut self, tagged: &TaggedNode) {
96 self.walk_tagged_node(tagged);
97 }
98
99 fn walk_tagged_node(&mut self, tagged: &TaggedNode) {
102 if let Some(mapping) = tagged.as_mapping() {
103 self.visit_mapping(&mapping);
104 } else if let Some(sequence) = tagged.as_sequence() {
105 self.visit_sequence(&sequence);
106 } else if let Some(scalar) = tagged.value() {
107 self.visit_scalar(&scalar);
108 }
109 }
110
111 fn walk_mapping(&mut self, mapping: &Mapping) {
117 for (key_node, value_node) in mapping.pairs() {
118 visit_node(self, &key_node);
119 visit_node(self, &value_node);
120 }
121 }
122
123 fn walk_sequence(&mut self, sequence: &Sequence) {
129 for item in sequence.items() {
130 visit_node(self, &item);
131 }
132 }
133}
134
135fn visit_node<V: YamlVisitor + ?Sized>(visitor: &mut V, node: &crate::yaml::SyntaxNode) {
137 use crate::yaml::extract;
138
139 if let Some(scalar) = extract(node) {
140 visitor.visit_scalar(&scalar);
141 } else if let Some(tagged) = extract(node) {
142 visitor.visit_tagged_node(&tagged);
143 } else if let Some(mapping) = extract(node) {
144 visitor.visit_mapping(&mapping);
145 } else if let Some(sequence) = extract(node) {
146 visitor.visit_sequence(&sequence);
147 }
148}
149
150pub trait YamlAccept {
152 fn accept<V: YamlVisitor>(&self, visitor: &mut V);
154}
155
156impl YamlAccept for YamlFile {
157 fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
158 visitor.visit_yaml(self);
159 }
160}
161
162impl YamlAccept for Document {
163 fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
164 visitor.visit_document(self);
165 }
166}
167
168impl YamlAccept for Scalar {
169 fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
170 visitor.visit_scalar(self);
171 }
172}
173
174impl YamlAccept for Mapping {
175 fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
176 visitor.visit_mapping(self);
177 }
178}
179
180impl YamlAccept for Sequence {
181 fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
182 visitor.visit_sequence(self);
183 }
184}
185
186#[derive(Debug, Clone)]
188pub struct ScalarCollector {
189 pub scalars: Vec<String>,
191}
192
193impl ScalarCollector {
194 pub fn new() -> Self {
196 Self {
197 scalars: Vec::new(),
198 }
199 }
200}
201
202impl Default for ScalarCollector {
203 fn default() -> Self {
204 Self::new()
205 }
206}
207
208impl YamlVisitor for ScalarCollector {
209 fn visit_scalar(&mut self, scalar: &Scalar) {
210 self.scalars.push(scalar.to_string());
211 }
212 }
214
215#[derive(Debug, Clone)]
217pub struct NodeCounter {
218 pub document_count: usize,
220 pub scalar_count: usize,
222 pub mapping_count: usize,
224 pub sequence_count: usize,
226}
227
228impl NodeCounter {
229 pub fn new() -> Self {
231 Self {
232 document_count: 0,
233 scalar_count: 0,
234 mapping_count: 0,
235 sequence_count: 0,
236 }
237 }
238
239 pub fn total(&self) -> usize {
241 self.document_count + self.scalar_count + self.mapping_count + self.sequence_count
242 }
243}
244
245impl Default for NodeCounter {
246 fn default() -> Self {
247 Self::new()
248 }
249}
250
251impl YamlVisitor for NodeCounter {
252 fn visit_document(&mut self, document: &Document) {
253 self.document_count += 1;
254 self.walk_document(document);
255 }
256
257 fn visit_scalar(&mut self, _scalar: &Scalar) {
258 self.scalar_count += 1;
259 }
260
261 fn visit_mapping(&mut self, mapping: &Mapping) {
262 self.mapping_count += 1;
263 self.walk_mapping(mapping);
265 }
266
267 fn visit_sequence(&mut self, sequence: &Sequence) {
268 self.sequence_count += 1;
269 self.walk_sequence(sequence);
271 }
272}
273
274pub struct ScalarTransformer<F>
276where
277 F: FnMut(&str) -> String,
278{
279 transform: F,
280 transformed: Vec<(String, String)>, }
282
283impl<F> ScalarTransformer<F>
284where
285 F: FnMut(&str) -> String,
286{
287 pub fn new(transform: F) -> Self {
289 Self {
290 transform,
291 transformed: Vec::new(),
292 }
293 }
294
295 pub fn results(&self) -> &[(String, String)] {
297 &self.transformed
298 }
299}
300
301impl<F> YamlVisitor for ScalarTransformer<F>
302where
303 F: FnMut(&str) -> String,
304{
305 fn visit_scalar(&mut self, scalar: &Scalar) {
306 let original = scalar.to_string();
307 let transformed = (self.transform)(&original);
308 self.transformed.push((original, transformed));
309 }
310
311 }