1 #![allow(missing_docs)]
2 
3 //! Document tree traversal to walk a shared borrow of a document tree.
4 //!
5 //! Each method of the [`Visit`] trait is a hook that can be overridden
6 //! to customize the behavior when mutating the corresponding type of node.
7 //! By default, every method recursively visits the substructure of the
8 //! input by invoking the right visitor method of each of its fields.
9 //!
10 //! ```
11 //! # use toml_edit::{Item, ArrayOfTables, Table, Value};
12 //!
13 //! pub trait Visit<'doc> {
14 //!     /* ... */
15 //!
16 //!     fn visit_item(&mut self, i: &'doc Item) {
17 //!         visit_item(self, i);
18 //!     }
19 //!
20 //!     /* ... */
21 //!     # fn visit_value(&mut self, i: &'doc Value);
22 //!     # fn visit_table(&mut self, i: &'doc Table);
23 //!     # fn visit_array_of_tables(&mut self, i: &'doc ArrayOfTables);
24 //! }
25 //!
26 //! pub fn visit_item<'doc, V>(v: &mut V, node: &'doc Item)
27 //! where
28 //!     V: Visit<'doc> + ?Sized,
29 //! {
30 //!     match node {
31 //!         Item::None => {}
32 //!         Item::Value(value) => v.visit_value(value),
33 //!         Item::Table(table) => v.visit_table(table),
34 //!         Item::ArrayOfTables(array) => v.visit_array_of_tables(array),
35 //!     }
36 //! }
37 //! ```
38 //!
39 //! The API is modeled after [`syn::visit`](https://docs.rs/syn/1/syn/visit).
40 //!
41 //! # Examples
42 //!
43 //! This visitor stores every string in the document.
44 //!
45 //! ```
46 //! # #[cfg(feature = "parse")] {
47 //! # use toml_edit::*;
48 //! use toml_edit::visit::*;
49 //!
50 //! #[derive(Default)]
51 //! struct StringCollector<'doc> {
52 //!     strings: Vec<&'doc str>,
53 //! }
54 //!
55 //! impl<'doc> Visit<'doc> for StringCollector<'doc> {
56 //!     fn visit_string(&mut self, node: &'doc Formatted<String>) {
57 //!          self.strings.push(node.value().as_str());
58 //!     }
59 //! }
60 //!
61 //! let input = r#"
62 //! laputa = "sky-castle"
63 //! the-force = { value = "surrounds-you" }
64 //! "#;
65 //!
66 //! let mut document: Document = input.parse().unwrap();
67 //! let mut visitor = StringCollector::default();
68 //! visitor.visit_document(&document);
69 //!
70 //! assert_eq!(visitor.strings, vec!["sky-castle", "surrounds-you"]);
71 //! # }
72 //! ```
73 //!
74 //! For a more complex example where the visitor has internal state, see `examples/visit.rs`
75 //! [on GitHub](https://github.com/toml-rs/toml/blob/main/crates/toml_edit/examples/visit.rs).
76 
77 use crate::{
78     Array, ArrayOfTables, Datetime, Document, Formatted, InlineTable, Item, Table, TableLike, Value,
79 };
80 
81 /// Document tree traversal to mutate an exclusive borrow of a document tree in-place.
82 ///
83 /// See the [module documentation](self) for details.
84 pub trait Visit<'doc> {
visit_document(&mut self, node: &'doc Document)85     fn visit_document(&mut self, node: &'doc Document) {
86         visit_document(self, node);
87     }
88 
visit_item(&mut self, node: &'doc Item)89     fn visit_item(&mut self, node: &'doc Item) {
90         visit_item(self, node);
91     }
92 
visit_table(&mut self, node: &'doc Table)93     fn visit_table(&mut self, node: &'doc Table) {
94         visit_table(self, node);
95     }
96 
visit_inline_table(&mut self, node: &'doc InlineTable)97     fn visit_inline_table(&mut self, node: &'doc InlineTable) {
98         visit_inline_table(self, node)
99     }
100 
visit_table_like(&mut self, node: &'doc dyn TableLike)101     fn visit_table_like(&mut self, node: &'doc dyn TableLike) {
102         visit_table_like(self, node);
103     }
104 
visit_table_like_kv(&mut self, key: &'doc str, node: &'doc Item)105     fn visit_table_like_kv(&mut self, key: &'doc str, node: &'doc Item) {
106         visit_table_like_kv(self, key, node);
107     }
108 
visit_array(&mut self, node: &'doc Array)109     fn visit_array(&mut self, node: &'doc Array) {
110         visit_array(self, node);
111     }
112 
visit_array_of_tables(&mut self, node: &'doc ArrayOfTables)113     fn visit_array_of_tables(&mut self, node: &'doc ArrayOfTables) {
114         visit_array_of_tables(self, node);
115     }
116 
visit_value(&mut self, node: &'doc Value)117     fn visit_value(&mut self, node: &'doc Value) {
118         visit_value(self, node);
119     }
120 
visit_boolean(&mut self, node: &'doc Formatted<bool>)121     fn visit_boolean(&mut self, node: &'doc Formatted<bool>) {
122         visit_boolean(self, node)
123     }
124 
visit_datetime(&mut self, node: &'doc Formatted<Datetime>)125     fn visit_datetime(&mut self, node: &'doc Formatted<Datetime>) {
126         visit_datetime(self, node);
127     }
128 
visit_float(&mut self, node: &'doc Formatted<f64>)129     fn visit_float(&mut self, node: &'doc Formatted<f64>) {
130         visit_float(self, node)
131     }
132 
visit_integer(&mut self, node: &'doc Formatted<i64>)133     fn visit_integer(&mut self, node: &'doc Formatted<i64>) {
134         visit_integer(self, node)
135     }
136 
visit_string(&mut self, node: &'doc Formatted<String>)137     fn visit_string(&mut self, node: &'doc Formatted<String>) {
138         visit_string(self, node)
139     }
140 }
141 
visit_document<'doc, V>(v: &mut V, node: &'doc Document) where V: Visit<'doc> + ?Sized,142 pub fn visit_document<'doc, V>(v: &mut V, node: &'doc Document)
143 where
144     V: Visit<'doc> + ?Sized,
145 {
146     v.visit_table(node.as_table());
147 }
148 
visit_item<'doc, V>(v: &mut V, node: &'doc Item) where V: Visit<'doc> + ?Sized,149 pub fn visit_item<'doc, V>(v: &mut V, node: &'doc Item)
150 where
151     V: Visit<'doc> + ?Sized,
152 {
153     match node {
154         Item::None => {}
155         Item::Value(value) => v.visit_value(value),
156         Item::Table(table) => v.visit_table(table),
157         Item::ArrayOfTables(array) => v.visit_array_of_tables(array),
158     }
159 }
160 
visit_table<'doc, V>(v: &mut V, node: &'doc Table) where V: Visit<'doc> + ?Sized,161 pub fn visit_table<'doc, V>(v: &mut V, node: &'doc Table)
162 where
163     V: Visit<'doc> + ?Sized,
164 {
165     v.visit_table_like(node)
166 }
167 
visit_inline_table<'doc, V>(v: &mut V, node: &'doc InlineTable) where V: Visit<'doc> + ?Sized,168 pub fn visit_inline_table<'doc, V>(v: &mut V, node: &'doc InlineTable)
169 where
170     V: Visit<'doc> + ?Sized,
171 {
172     v.visit_table_like(node)
173 }
174 
visit_table_like<'doc, V>(v: &mut V, node: &'doc dyn TableLike) where V: Visit<'doc> + ?Sized,175 pub fn visit_table_like<'doc, V>(v: &mut V, node: &'doc dyn TableLike)
176 where
177     V: Visit<'doc> + ?Sized,
178 {
179     for (key, item) in node.iter() {
180         v.visit_table_like_kv(key, item)
181     }
182 }
183 
visit_table_like_kv<'doc, V>(v: &mut V, _key: &'doc str, node: &'doc Item) where V: Visit<'doc> + ?Sized,184 pub fn visit_table_like_kv<'doc, V>(v: &mut V, _key: &'doc str, node: &'doc Item)
185 where
186     V: Visit<'doc> + ?Sized,
187 {
188     v.visit_item(node)
189 }
190 
visit_array<'doc, V>(v: &mut V, node: &'doc Array) where V: Visit<'doc> + ?Sized,191 pub fn visit_array<'doc, V>(v: &mut V, node: &'doc Array)
192 where
193     V: Visit<'doc> + ?Sized,
194 {
195     for value in node.iter() {
196         v.visit_value(value);
197     }
198 }
199 
visit_array_of_tables<'doc, V>(v: &mut V, node: &'doc ArrayOfTables) where V: Visit<'doc> + ?Sized,200 pub fn visit_array_of_tables<'doc, V>(v: &mut V, node: &'doc ArrayOfTables)
201 where
202     V: Visit<'doc> + ?Sized,
203 {
204     for table in node.iter() {
205         v.visit_table(table);
206     }
207 }
208 
visit_value<'doc, V>(v: &mut V, node: &'doc Value) where V: Visit<'doc> + ?Sized,209 pub fn visit_value<'doc, V>(v: &mut V, node: &'doc Value)
210 where
211     V: Visit<'doc> + ?Sized,
212 {
213     match node {
214         Value::String(s) => v.visit_string(s),
215         Value::Integer(i) => v.visit_integer(i),
216         Value::Float(f) => v.visit_float(f),
217         Value::Boolean(b) => v.visit_boolean(b),
218         Value::Datetime(dt) => v.visit_datetime(dt),
219         Value::Array(array) => v.visit_array(array),
220         Value::InlineTable(table) => v.visit_inline_table(table),
221     }
222 }
223 
224 macro_rules! empty_visit {
225     ($name: ident, $t: ty) => {
226         fn $name<'doc, V>(_v: &mut V, _node: &'doc $t)
227         where
228             V: Visit<'doc> + ?Sized,
229         {
230         }
231     };
232 }
233 
234 empty_visit!(visit_boolean, Formatted<bool>);
235 empty_visit!(visit_datetime, Formatted<Datetime>);
236 empty_visit!(visit_float, Formatted<f64>);
237 empty_visit!(visit_integer, Formatted<i64>);
238 empty_visit!(visit_string, Formatted<String>);
239