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 { |
101 | fn visit_document_mut(&mut self, node: &mut Document) { |
102 | visit_document_mut(self, node); |
103 | } |
104 | |
105 | fn visit_item_mut(&mut self, node: &mut Item) { |
106 | visit_item_mut(self, node); |
107 | } |
108 | |
109 | fn visit_table_mut(&mut self, node: &mut Table) { |
110 | visit_table_mut(self, node); |
111 | } |
112 | |
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. |
119 | fn visit_table_like_mut(&mut self, node: &mut dyn TableLike) { |
120 | visit_table_like_mut(self, node); |
121 | } |
122 | |
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 | |
127 | fn visit_array_mut(&mut self, node: &mut Array) { |
128 | visit_array_mut(self, node); |
129 | } |
130 | |
131 | fn visit_array_of_tables_mut(&mut self, node: &mut ArrayOfTables) { |
132 | visit_array_of_tables_mut(self, node); |
133 | } |
134 | |
135 | fn visit_value_mut(&mut self, node: &mut Value) { |
136 | visit_value_mut(self, node); |
137 | } |
138 | |
139 | fn visit_boolean_mut(&mut self, node: &mut Formatted<bool>) { |
140 | visit_boolean_mut(self, node) |
141 | } |
142 | |
143 | fn visit_datetime_mut(&mut self, node: &mut Formatted<Datetime>) { |
144 | visit_datetime_mut(self, node); |
145 | } |
146 | |
147 | fn visit_float_mut(&mut self, node: &mut Formatted<f64>) { |
148 | visit_float_mut(self, node) |
149 | } |
150 | |
151 | fn visit_integer_mut(&mut self, node: &mut Formatted<i64>) { |
152 | visit_integer_mut(self, node) |
153 | } |
154 | |
155 | fn visit_string_mut(&mut self, node: &mut Formatted<String>) { |
156 | visit_string_mut(self, node) |
157 | } |
158 | } |
159 | |
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:node.as_table_mut()); |
165 | } |
166 | |
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: &mut Value) => v.visit_value_mut(node:value), |
174 | Item::Table(table: &mut Table) => v.visit_table_mut(node:table), |
175 | Item::ArrayOfTables(array: &mut ArrayOfTables) => v.visit_array_of_tables_mut(node:array), |
176 | } |
177 | } |
178 | |
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 | |
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 | |
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: KeyMut<'_>, item: &mut Item) in node.iter_mut() { |
198 | v.visit_table_like_kv_mut(key, node:item); |
199 | } |
200 | } |
201 | |
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 | |
209 | pub fn visit_array_mut<V>(v: &mut V, node: &mut Array) |
210 | where |
211 | V: VisitMut + ?Sized, |
212 | { |
213 | for value: &mut Value in node.iter_mut() { |
214 | v.visit_value_mut(node:value); |
215 | } |
216 | } |
217 | |
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: &mut Table in node.iter_mut() { |
223 | v.visit_table_mut(node:table); |
224 | } |
225 | } |
226 | |
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: &mut Formatted) => v.visit_string_mut(node:s), |
233 | Value::Integer(i: &mut Formatted) => v.visit_integer_mut(node:i), |
234 | Value::Float(f: &mut Formatted) => v.visit_float_mut(node:f), |
235 | Value::Boolean(b: &mut Formatted) => v.visit_boolean_mut(node:b), |
236 | Value::Datetime(dt: &mut Formatted) => v.visit_datetime_mut(node:dt), |
237 | Value::Array(array: &mut Array) => v.visit_array_mut(node:array), |
238 | Value::InlineTable(table: &mut InlineTable) => v.visit_inline_table_mut(node: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 | |