toml_edit/
document.rs

1use std::str::FromStr;
2
3use crate::table::Iter;
4use crate::{Item, RawString, Table};
5
6/// The root TOML [`Table`], containing [`Key`][crate::Key]/[`Value`][crate::Value] pairs and all other logic [`Table`]s
7#[derive(Debug, Clone)]
8pub struct Document<S> {
9    pub(crate) root: Item,
10    // Trailing comments and whitespaces
11    pub(crate) trailing: RawString,
12    pub(crate) raw: S,
13}
14
15impl Document<&'static str> {
16    /// Creates an empty document
17    pub fn new() -> Self {
18        Default::default()
19    }
20}
21
22#[cfg(feature = "parse")]
23impl<S: AsRef<str>> Document<S> {
24    /// Parse a TOML document
25    pub fn parse(raw: S) -> Result<Self, crate::TomlError> {
26        let source = toml_parser::Source::new(raw.as_ref());
27        let mut sink = crate::error::TomlSink::<Option<_>>::new(source);
28        let doc = crate::parser::parse_document(source, &mut sink);
29        if let Some(err) = sink.into_inner() {
30            Err(err)
31        } else {
32            Ok(Self {
33                root: doc.root,
34                trailing: doc.trailing,
35                raw,
36            })
37        }
38    }
39}
40
41impl<S: AsRef<str>> Document<S> {
42    /// # Panics
43    ///
44    /// If run on a [`DocumentMut`] not generated by the parser
45    pub(crate) fn despan(&mut self) {
46        self.root.despan(self.raw.as_ref());
47        self.trailing.despan(self.raw.as_ref());
48    }
49}
50
51impl<S> Document<S> {
52    /// Returns a reference to the root item.
53    pub fn as_item(&self) -> &Item {
54        &self.root
55    }
56
57    /// Returns the root item.
58    pub fn into_item(self) -> Item {
59        self.root
60    }
61
62    /// Returns a reference to the root table.
63    pub fn as_table(&self) -> &Table {
64        self.root.as_table().expect("root should always be a table")
65    }
66
67    /// Returns the root table.
68    pub fn into_table(self) -> Table {
69        self.root
70            .into_table()
71            .expect("root should always be a table")
72    }
73
74    /// Returns an iterator over the root table.
75    pub fn iter(&self) -> Iter<'_> {
76        self.as_table().iter()
77    }
78
79    /// Whitespace after last element
80    pub fn trailing(&self) -> &RawString {
81        &self.trailing
82    }
83}
84
85impl<S: AsRef<str>> Document<S> {
86    /// Access the raw, unparsed document
87    pub fn raw(&self) -> &str {
88        self.raw.as_ref()
89    }
90}
91
92impl<S: AsRef<str>> Document<S> {
93    /// Allow editing of the [`DocumentMut`]
94    pub fn into_mut(mut self) -> DocumentMut {
95        self.despan();
96        DocumentMut {
97            root: self.root,
98            trailing: self.trailing,
99        }
100    }
101}
102
103impl Default for Document<&'static str> {
104    fn default() -> Self {
105        Self {
106            root: Item::Table(Table::with_pos(Some(0))),
107            trailing: Default::default(),
108            raw: "",
109        }
110    }
111}
112
113#[cfg(feature = "parse")]
114impl FromStr for Document<String> {
115    type Err = crate::TomlError;
116
117    /// Parses a document from a &str
118    fn from_str(s: &str) -> Result<Self, Self::Err> {
119        Self::parse(s.to_owned())
120    }
121}
122
123impl<S> std::ops::Deref for Document<S> {
124    type Target = Table;
125
126    fn deref(&self) -> &Self::Target {
127        self.as_table()
128    }
129}
130
131/// The editable root TOML [`Table`], containing [`Key`][crate::Key]/[`Value`][crate::Value] pairs and all other logic [`Table`]s
132#[derive(Debug, Clone)]
133pub struct DocumentMut {
134    pub(crate) root: Item,
135    // Trailing comments and whitespaces
136    pub(crate) trailing: RawString,
137}
138
139impl DocumentMut {
140    /// Creates an empty document
141    pub fn new() -> Self {
142        Default::default()
143    }
144
145    /// Returns a reference to the root item.
146    pub fn as_item(&self) -> &Item {
147        &self.root
148    }
149
150    /// Returns a mutable reference to the root item.
151    pub fn as_item_mut(&mut self) -> &mut Item {
152        &mut self.root
153    }
154
155    /// Returns the root item.
156    pub fn into_item(self) -> Item {
157        self.root
158    }
159
160    /// Returns a reference to the root table.
161    pub fn as_table(&self) -> &Table {
162        self.root.as_table().expect("root should always be a table")
163    }
164
165    /// Returns a mutable reference to the root table.
166    pub fn as_table_mut(&mut self) -> &mut Table {
167        self.root
168            .as_table_mut()
169            .expect("root should always be a table")
170    }
171
172    /// Returns the root table.
173    pub fn into_table(self) -> Table {
174        self.root
175            .into_table()
176            .expect("root should always be a table")
177    }
178
179    /// Returns an iterator over the root table.
180    pub fn iter(&self) -> Iter<'_> {
181        self.as_table().iter()
182    }
183
184    /// Set whitespace after last element
185    pub fn set_trailing(&mut self, trailing: impl Into<RawString>) {
186        self.trailing = trailing.into();
187    }
188
189    /// Whitespace after last element
190    pub fn trailing(&self) -> &RawString {
191        &self.trailing
192    }
193}
194
195impl Default for DocumentMut {
196    fn default() -> Self {
197        Self {
198            root: Item::Table(Table::with_pos(Some(0))),
199            trailing: Default::default(),
200        }
201    }
202}
203
204#[cfg(feature = "parse")]
205impl FromStr for DocumentMut {
206    type Err = crate::TomlError;
207
208    /// Parses a document from a &str
209    fn from_str(s: &str) -> Result<Self, Self::Err> {
210        let im = Document::from_str(s)?;
211        Ok(im.into_mut())
212    }
213}
214
215impl std::ops::Deref for DocumentMut {
216    type Target = Table;
217
218    fn deref(&self) -> &Self::Target {
219        self.as_table()
220    }
221}
222
223impl std::ops::DerefMut for DocumentMut {
224    fn deref_mut(&mut self) -> &mut Self::Target {
225        self.as_table_mut()
226    }
227}
228
229impl From<Table> for DocumentMut {
230    fn from(root: Table) -> Self {
231        Self {
232            root: Item::Table(root),
233            ..Default::default()
234        }
235    }
236}
237
238#[test]
239#[cfg(feature = "parse")]
240#[cfg(feature = "display")]
241fn default_roundtrip() {
242    DocumentMut::default()
243        .to_string()
244        .parse::<DocumentMut>()
245        .unwrap();
246}