1 #![allow(missing_docs)]
2 
3 //! Document tree traversal to mutate an exclusive borrow of a document tree in place.
4 //!
5 //!
6 //! Each method of the [`VisitMut`] trait is a hook that can be overridden
7 //! to customize the behavior when mutating the corresponding type of node.
8 //! By default, every method recursively visits the substructure of the
9 //! input by invoking the right visitor method of each of its fields.
10 //!
11 //! ```
12 //! # use toml_edit::{Item, ArrayOfTables, Table, Value};
13 //!
14 //! pub trait VisitMut {
15 //!     /* ... */
16 //!
17 //!     fn visit_item_mut(&mut self, i: &mut Item) {
18 //!         visit_item_mut(self, i);
19 //!     }
20 //!
21 //!     /* ... */
22 //!     # fn visit_value_mut(&mut self, i: &mut Value);
23 //!     # fn visit_table_mut(&mut self, i: &mut Table);
24 //!     # fn visit_array_of_tables_mut(&mut self, i: &mut ArrayOfTables);
25 //! }
26 //!
27 //! pub fn visit_item_mut<V>(v: &mut V, node: &mut Item)
28 //! where
29 //!     V: VisitMut + ?Sized,
30 //! {
31 //!     match node {
32 //!         Item::None => {}
33 //!         Item::Value(value) => v.visit_value_mut(value),
34 //!         Item::Table(table) => v.visit_table_mut(table),
35 //!         Item::ArrayOfTables(array) => v.visit_array_of_tables_mut(array),
36 //!     }
37 //! }
38 //! ```
39 //!
40 //! The API is modeled after [`syn::visit_mut`](https://docs.rs/syn/1/syn/visit_mut).
41 //!
42 //! # Examples
43 //!
44 //! This visitor replaces every floating point value with its decimal string representation, to
45 //! 2 decimal points.
46 //!
47 //! ```
48 //! # #[cfg(feature = "parse")] {
49 //! # #[cfg(feature = "display")] {
50 //! # use toml_edit::*;
51 //! use toml_edit::visit_mut::*;
52 //!
53 //! struct FloatToString;
54 //!
55 //! impl VisitMut for FloatToString {
56 //!     fn visit_value_mut(&mut self, node: &mut Value) {
57 //!         if let Value::Float(f) = node {
58 //!             // Convert the float to a string.
59 //!             let mut s = Formatted::new(format!("{:.2}", f.value()));
60 //!             // Copy over the formatting.
61 //!             std::mem::swap(s.decor_mut(), f.decor_mut());
62 //!             *node = Value::String(s);
63 //!         }
64 //!         // Most of the time, you will also need to call the default implementation to recurse
65 //!         // further down the document tree.
66 //!         visit_value_mut(self, node);
67 //!     }
68 //! }
69 //!
70 //! let input = r#"
71 //! banana = 3.26
72 //! table = { apple = 4.5 }
73 //! "#;
74 //!
75 //! let mut document: Document = input.parse().unwrap();
76 //! let mut visitor = FloatToString;
77 //! visitor.visit_document_mut(&mut document);
78 //!
79 //! let output = r#"
80 //! banana = "3.26"
81 //! table = { apple = "4.50" }
82 //! "#;
83 //!
84 //! assert_eq!(format!("{}", document), output);
85 //! # }
86 //! # }
87 //! ```
88 //!
89 //! For a more complex example where the visitor has internal state, see `examples/visit.rs`
90 //! [on GitHub](https://github.com/toml-rs/toml/blob/main/crates/toml_edit/examples/visit.rs).
91 
92 use crate::{
93     Array, ArrayOfTables, Datetime, Document, Formatted, InlineTable, Item, KeyMut, Table,
94     TableLike, Value,
95 };
96 
97 /// Document tree traversal to mutate an exclusive borrow of a document tree in-place.
98 ///
99 /// See the [module documentation](self) for details.
100 pub trait VisitMut {
visit_document_mut(&mut self, node: &mut Document)101     fn visit_document_mut(&mut self, node: &mut Document) {
102         visit_document_mut(self, node);
103     }
104 
visit_item_mut(&mut self, node: &mut Item)105     fn visit_item_mut(&mut self, node: &mut Item) {
106         visit_item_mut(self, node);
107     }
108 
visit_table_mut(&mut self, node: &mut Table)109     fn visit_table_mut(&mut self, node: &mut Table) {
110         visit_table_mut(self, node);
111     }
112 
visit_inline_table_mut(&mut self, node: &mut InlineTable)113     fn visit_inline_table_mut(&mut self, node: &mut InlineTable) {
114         visit_inline_table_mut(self, node)
115     }
116 
117     /// [`visit_table_mut`](Self::visit_table_mut) and
118     /// [`visit_inline_table_mut`](Self::visit_inline_table_mut) both recurse into this method.
visit_table_like_mut(&mut self, node: &mut dyn TableLike)119     fn visit_table_like_mut(&mut self, node: &mut dyn TableLike) {
120         visit_table_like_mut(self, node);
121     }
122 
visit_table_like_kv_mut(&mut self, key: KeyMut<'_>, node: &mut Item)123     fn visit_table_like_kv_mut(&mut self, key: KeyMut<'_>, node: &mut Item) {
124         visit_table_like_kv_mut(self, key, node);
125     }
126 
visit_array_mut(&mut self, node: &mut Array)127     fn visit_array_mut(&mut self, node: &mut Array) {
128         visit_array_mut(self, node);
129     }
130 
visit_array_of_tables_mut(&mut self, node: &mut ArrayOfTables)131     fn visit_array_of_tables_mut(&mut self, node: &mut ArrayOfTables) {
132         visit_array_of_tables_mut(self, node);
133     }
134 
visit_value_mut(&mut self, node: &mut Value)135     fn visit_value_mut(&mut self, node: &mut Value) {
136         visit_value_mut(self, node);
137     }
138 
visit_boolean_mut(&mut self, node: &mut Formatted<bool>)139     fn visit_boolean_mut(&mut self, node: &mut Formatted<bool>) {
140         visit_boolean_mut(self, node)
141     }
142 
visit_datetime_mut(&mut self, node: &mut Formatted<Datetime>)143     fn visit_datetime_mut(&mut self, node: &mut Formatted<Datetime>) {
144         visit_datetime_mut(self, node);
145     }
146 
visit_float_mut(&mut self, node: &mut Formatted<f64>)147     fn visit_float_mut(&mut self, node: &mut Formatted<f64>) {
148         visit_float_mut(self, node)
149     }
150 
visit_integer_mut(&mut self, node: &mut Formatted<i64>)151     fn visit_integer_mut(&mut self, node: &mut Formatted<i64>) {
152         visit_integer_mut(self, node)
153     }
154 
visit_string_mut(&mut self, node: &mut Formatted<String>)155     fn visit_string_mut(&mut self, node: &mut Formatted<String>) {
156         visit_string_mut(self, node)
157     }
158 }
159 
visit_document_mut<V>(v: &mut V, node: &mut Document) where V: VisitMut + ?Sized,160 pub fn visit_document_mut<V>(v: &mut V, node: &mut Document)
161 where
162     V: VisitMut + ?Sized,
163 {
164     v.visit_table_mut(node.as_table_mut());
165 }
166 
visit_item_mut<V>(v: &mut V, node: &mut Item) where V: VisitMut + ?Sized,167 pub fn visit_item_mut<V>(v: &mut V, node: &mut Item)
168 where
169     V: VisitMut + ?Sized,
170 {
171     match node {
172         Item::None => {}
173         Item::Value(value) => v.visit_value_mut(value),
174         Item::Table(table) => v.visit_table_mut(table),
175         Item::ArrayOfTables(array) => v.visit_array_of_tables_mut(array),
176     }
177 }
178 
visit_table_mut<V>(v: &mut V, node: &mut Table) where V: VisitMut + ?Sized,179 pub fn visit_table_mut<V>(v: &mut V, node: &mut Table)
180 where
181     V: VisitMut + ?Sized,
182 {
183     v.visit_table_like_mut(node);
184 }
185 
visit_inline_table_mut<V>(v: &mut V, node: &mut InlineTable) where V: VisitMut + ?Sized,186 pub fn visit_inline_table_mut<V>(v: &mut V, node: &mut InlineTable)
187 where
188     V: VisitMut + ?Sized,
189 {
190     v.visit_table_like_mut(node);
191 }
192 
visit_table_like_mut<V>(v: &mut V, node: &mut dyn TableLike) where V: VisitMut + ?Sized,193 pub fn visit_table_like_mut<V>(v: &mut V, node: &mut dyn TableLike)
194 where
195     V: VisitMut + ?Sized,
196 {
197     for (key, item) in node.iter_mut() {
198         v.visit_table_like_kv_mut(key, item);
199     }
200 }
201 
visit_table_like_kv_mut<V>(v: &mut V, _key: KeyMut<'_>, node: &mut Item) where V: VisitMut + ?Sized,202 pub fn visit_table_like_kv_mut<V>(v: &mut V, _key: KeyMut<'_>, node: &mut Item)
203 where
204     V: VisitMut + ?Sized,
205 {
206     v.visit_item_mut(node)
207 }
208 
visit_array_mut<V>(v: &mut V, node: &mut Array) where V: VisitMut + ?Sized,209 pub fn visit_array_mut<V>(v: &mut V, node: &mut Array)
210 where
211     V: VisitMut + ?Sized,
212 {
213     for value in node.iter_mut() {
214         v.visit_value_mut(value);
215     }
216 }
217 
visit_array_of_tables_mut<V>(v: &mut V, node: &mut ArrayOfTables) where V: VisitMut + ?Sized,218 pub fn visit_array_of_tables_mut<V>(v: &mut V, node: &mut ArrayOfTables)
219 where
220     V: VisitMut + ?Sized,
221 {
222     for table in node.iter_mut() {
223         v.visit_table_mut(table);
224     }
225 }
226 
visit_value_mut<V>(v: &mut V, node: &mut Value) where V: VisitMut + ?Sized,227 pub fn visit_value_mut<V>(v: &mut V, node: &mut Value)
228 where
229     V: VisitMut + ?Sized,
230 {
231     match node {
232         Value::String(s) => v.visit_string_mut(s),
233         Value::Integer(i) => v.visit_integer_mut(i),
234         Value::Float(f) => v.visit_float_mut(f),
235         Value::Boolean(b) => v.visit_boolean_mut(b),
236         Value::Datetime(dt) => v.visit_datetime_mut(dt),
237         Value::Array(array) => v.visit_array_mut(array),
238         Value::InlineTable(table) => v.visit_inline_table_mut(table),
239     }
240 }
241 
242 macro_rules! empty_visit_mut {
243     ($name: ident, $t: ty) => {
244         fn $name<V>(_v: &mut V, _node: &mut $t)
245         where
246             V: VisitMut + ?Sized,
247         {
248         }
249     };
250 }
251 
252 empty_visit_mut!(visit_boolean_mut, Formatted<bool>);
253 empty_visit_mut!(visit_datetime_mut, Formatted<Datetime>);
254 empty_visit_mut!(visit_float_mut, Formatted<f64>);
255 empty_visit_mut!(visit_integer_mut, Formatted<i64>);
256 empty_visit_mut!(visit_string_mut, Formatted<String>);
257