#![allow(missing_docs)] //! Document tree traversal to walk a shared borrow of a document tree. //! //! Each method of the [`Visit`] trait is a hook that can be overridden //! to customize the behavior when mutating the corresponding type of node. //! By default, every method recursively visits the substructure of the //! input by invoking the right visitor method of each of its fields. //! //! ``` //! # use toml_edit::{Item, ArrayOfTables, Table, Value}; //! //! pub trait Visit<'doc> { //! /* ... */ //! //! fn visit_item(&mut self, i: &'doc Item) { //! visit_item(self, i); //! } //! //! /* ... */ //! # fn visit_value(&mut self, i: &'doc Value); //! # fn visit_table(&mut self, i: &'doc Table); //! # fn visit_array_of_tables(&mut self, i: &'doc ArrayOfTables); //! } //! //! pub fn visit_item<'doc, V>(v: &mut V, node: &'doc Item) //! where //! V: Visit<'doc> + ?Sized, //! { //! match node { //! Item::None => {} //! Item::Value(value) => v.visit_value(value), //! Item::Table(table) => v.visit_table(table), //! Item::ArrayOfTables(array) => v.visit_array_of_tables(array), //! } //! } //! ``` //! //! The API is modeled after [`syn::visit`](https://docs.rs/syn/1/syn/visit). //! //! # Examples //! //! This visitor stores every string in the document. //! //! ``` //! # use toml_edit::*; //! use toml_edit::visit::*; //! //! #[derive(Default)] //! struct StringCollector<'doc> { //! strings: Vec<&'doc str>, //! } //! //! impl<'doc> Visit<'doc> for StringCollector<'doc> { //! fn visit_string(&mut self, node: &'doc Formatted) { //! self.strings.push(node.value().as_str()); //! } //! } //! //! let input = r#" //! laputa = "sky-castle" //! the-force = { value = "surrounds-you" } //! "#; //! //! let mut document: Document = input.parse().unwrap(); //! let mut visitor = StringCollector::default(); //! visitor.visit_document(&document); //! //! assert_eq!(visitor.strings, vec!["sky-castle", "surrounds-you"]); //! ``` //! //! For a more complex example where the visitor has internal state, see `examples/visit.rs` //! [on GitHub](https://github.com/ordian/toml_edit/blob/master/examples/visit.rs). use crate::{ Array, ArrayOfTables, Datetime, Document, Formatted, InlineTable, Item, Table, TableLike, Value, }; /// Document tree traversal to mutate an exclusive borrow of a document tree in-place. /// /// See the [module documentation](self) for details. pub trait Visit<'doc> { fn visit_document(&mut self, node: &'doc Document) { visit_document(self, node); } fn visit_item(&mut self, node: &'doc Item) { visit_item(self, node); } fn visit_table(&mut self, node: &'doc Table) { visit_table(self, node); } fn visit_inline_table(&mut self, node: &'doc InlineTable) { visit_inline_table(self, node) } fn visit_table_like(&mut self, node: &'doc dyn TableLike) { visit_table_like(self, node); } fn visit_table_like_kv(&mut self, key: &'doc str, node: &'doc Item) { visit_table_like_kv(self, key, node); } fn visit_array(&mut self, node: &'doc Array) { visit_array(self, node); } fn visit_array_of_tables(&mut self, node: &'doc ArrayOfTables) { visit_array_of_tables(self, node); } fn visit_value(&mut self, node: &'doc Value) { visit_value(self, node); } fn visit_boolean(&mut self, node: &'doc Formatted) { visit_boolean(self, node) } fn visit_datetime(&mut self, node: &'doc Formatted) { visit_datetime(self, node); } fn visit_float(&mut self, node: &'doc Formatted) { visit_float(self, node) } fn visit_integer(&mut self, node: &'doc Formatted) { visit_integer(self, node) } fn visit_string(&mut self, node: &'doc Formatted) { visit_string(self, node) } } pub fn visit_document<'doc, V>(v: &mut V, node: &'doc Document) where V: Visit<'doc> + ?Sized, { v.visit_table(node.as_table()); } pub fn visit_item<'doc, V>(v: &mut V, node: &'doc Item) where V: Visit<'doc> + ?Sized, { match node { Item::None => {} Item::Value(value) => v.visit_value(value), Item::Table(table) => v.visit_table(table), Item::ArrayOfTables(array) => v.visit_array_of_tables(array), } } pub fn visit_table<'doc, V>(v: &mut V, node: &'doc Table) where V: Visit<'doc> + ?Sized, { v.visit_table_like(node) } pub fn visit_inline_table<'doc, V>(v: &mut V, node: &'doc InlineTable) where V: Visit<'doc> + ?Sized, { v.visit_table_like(node) } pub fn visit_table_like<'doc, V>(v: &mut V, node: &'doc dyn TableLike) where V: Visit<'doc> + ?Sized, { for (key, item) in node.iter() { v.visit_table_like_kv(key, item) } } pub fn visit_table_like_kv<'doc, V>(v: &mut V, _key: &'doc str, node: &'doc Item) where V: Visit<'doc> + ?Sized, { v.visit_item(node) } pub fn visit_array<'doc, V>(v: &mut V, node: &'doc Array) where V: Visit<'doc> + ?Sized, { for value in node.iter() { v.visit_value(value); } } pub fn visit_array_of_tables<'doc, V>(v: &mut V, node: &'doc ArrayOfTables) where V: Visit<'doc> + ?Sized, { for table in node.iter() { v.visit_table(table); } } pub fn visit_value<'doc, V>(v: &mut V, node: &'doc Value) where V: Visit<'doc> + ?Sized, { match node { Value::String(s) => v.visit_string(s), Value::Integer(i) => v.visit_integer(i), Value::Float(f) => v.visit_float(f), Value::Boolean(b) => v.visit_boolean(b), Value::Datetime(dt) => v.visit_datetime(dt), Value::Array(array) => v.visit_array(array), Value::InlineTable(table) => v.visit_inline_table(table), } } macro_rules! empty_visit { ($name: ident, $t: ty) => { fn $name<'doc, V>(_v: &mut V, _node: &'doc $t) where V: Visit<'doc> + ?Sized, { } }; } empty_visit!(visit_boolean, Formatted); empty_visit!(visit_datetime, Formatted); empty_visit!(visit_float, Formatted); empty_visit!(visit_integer, Formatted); empty_visit!(visit_string, Formatted);