toml_edit/
visit_mut.rs

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: DocumentMut = 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
92use crate::{
93    Array, ArrayOfTables, Datetime, DocumentMut, 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.
100pub trait VisitMut {
101    fn visit_document_mut(&mut self, node: &mut DocumentMut) {
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
160pub fn visit_document_mut<V>(v: &mut V, node: &mut DocumentMut)
161where
162    V: VisitMut + ?Sized,
163{
164    v.visit_table_mut(node.as_table_mut());
165}
166
167pub fn visit_item_mut<V>(v: &mut V, node: &mut Item)
168where
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
179pub fn visit_table_mut<V>(v: &mut V, node: &mut Table)
180where
181    V: VisitMut + ?Sized,
182{
183    v.visit_table_like_mut(node);
184}
185
186pub fn visit_inline_table_mut<V>(v: &mut V, node: &mut InlineTable)
187where
188    V: VisitMut + ?Sized,
189{
190    v.visit_table_like_mut(node);
191}
192
193pub fn visit_table_like_mut<V>(v: &mut V, node: &mut dyn TableLike)
194where
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
202pub fn visit_table_like_kv_mut<V>(v: &mut V, _key: KeyMut<'_>, node: &mut Item)
203where
204    V: VisitMut + ?Sized,
205{
206    v.visit_item_mut(node);
207}
208
209pub fn visit_array_mut<V>(v: &mut V, node: &mut Array)
210where
211    V: VisitMut + ?Sized,
212{
213    for value in node.iter_mut() {
214        v.visit_value_mut(value);
215    }
216}
217
218pub fn visit_array_of_tables_mut<V>(v: &mut V, node: &mut ArrayOfTables)
219where
220    V: VisitMut + ?Sized,
221{
222    for table in node.iter_mut() {
223        v.visit_table_mut(table);
224    }
225}
226
227pub fn visit_value_mut<V>(v: &mut V, node: &mut Value)
228where
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
242macro_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
252empty_visit_mut!(visit_boolean_mut, Formatted<bool>);
253empty_visit_mut!(visit_datetime_mut, Formatted<Datetime>);
254empty_visit_mut!(visit_float_mut, Formatted<f64>);
255empty_visit_mut!(visit_integer_mut, Formatted<i64>);
256empty_visit_mut!(visit_string_mut, Formatted<String>);