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