]> git.proxmox.com Git - rustc.git/blame - vendor/toml-query/src/insert.rs
New upstream version 1.45.0+dfsg1
[rustc.git] / vendor / toml-query / src / insert.rs
CommitLineData
2c00a5a8
XL
1/// The Toml Insert extensions
2
9fa01778
XL
3#[cfg(feature = "typed")]
4use serde::Serialize;
2c00a5a8
XL
5use toml::Value;
6
dc9dc135
XL
7use crate::tokenizer::Token;
8use crate::tokenizer::tokenize_with_seperator;
9use crate::error::{Error, Result};
2c00a5a8
XL
10
11pub trait TomlValueInsertExt {
12
13 /// Extension function for inserting a value in the current toml::Value document
14 /// using a custom seperator.
15 ///
16 /// For difference to TomlSetExt::set() and friends, read [#semantics].
17 ///
18 /// # Semantics
19 ///
20 /// The function automatically creates intermediate data structures based on the query string.
21 /// That means, if the query string is `"a.b.c.[0]"`, but only a table `"a"` exists in the
22 /// document, the function automatically creates a table `"b"` inside `"a"` and `"c"` inside
23 /// `"b"`, and an array in `"c"`. The array index is ignored if the array is created.
24 ///
25 /// If an Array exists, but the specified index is larger than the last index, the array will
26 /// be expanded by one element: If the array has a length of 3, but the query string specifies
27 /// that the element should be put at 1000, the function ignores the large index and simply
28 /// appends the value to the index.
29 ///
30 /// If a Value is inserted into an Array, the array indexes are shifted. Semantically this is
31 /// the same as doing a `array.insert(4, _)` (see the standard library).
32 ///
33 /// ## Known Bugs
34 ///
35 /// The current implementation does _not_ create intermediate Arrays as described above.
36 /// This is a known bug. So queries like "foo.bar.[0].baz" (or any query which has an array
37 /// element) will fail with an error rather than work.
38 ///
39 /// # Return value
40 ///
41 /// If the insert operation worked correctly, `Ok(None)` is returned.
42 /// If the insert operation replaced an existing value `Ok(Some(old_value))` is returned
43 /// On failure, `Err(e)` is returned
44 ///
45 /// # Examples
46 ///
47 /// The following example shows a working `insert_with_seperator()` call on an empty toml
48 /// document. The Value is inserted as `"foo.bar = 1"` in the document.
49 ///
50 /// ```rust
51 /// extern crate toml;
52 /// extern crate toml_query;
53 ///
54 /// let mut toml : toml::Value = toml::from_str("").unwrap();
55 /// let query = "foo.bar";
56 /// let sep = '.';
57 /// let val = toml::Value::Integer(1);
58 ///
59 /// let res = toml_query::insert::TomlValueInsertExt::insert_with_seperator(&mut toml, query, sep, val);
60 /// assert!(res.is_ok());
61 /// let res = res.unwrap();
62 /// assert!(res.is_none());
63 /// ```
64 ///
65 /// The following example shows a failing `insert_with_seperator()` call on an empty toml
66 /// document. The Query does contain an array token, which does not yet work.
67 ///
68 /// ```rust,should_panic
69 /// extern crate toml;
70 /// extern crate toml_query;
71 ///
72 /// let mut toml : toml::Value = toml::from_str("").unwrap();
73 /// let query = "foo.[0]";
74 /// let sep = '.';
75 /// let val = toml::Value::Integer(1);
76 ///
77 /// let res = toml_query::insert::TomlValueInsertExt::insert_with_seperator(&mut toml, query, sep, val);
78 /// assert!(res.is_ok()); // panics
79 /// ```
80 ///
81 fn insert_with_seperator(&mut self, query: &str, sep: char, value: Value) -> Result<Option<Value>>;
82
83 /// Extension function for inserting a value from the current toml::Value document
84 ///
85 /// See documentation of `TomlValueinsertExt::insert_with_seperator`
86 fn insert(&mut self, query: &str, value: Value) -> Result<Option<Value>> {
87 self.insert_with_seperator(query, '.', value)
88 }
89
9fa01778
XL
90 /// A convenience method for inserting any arbitrary serializable value.
91 #[cfg(feature = "typed")]
92 fn insert_serialized<S: Serialize>(&mut self, query: &str, value: S) -> Result<Option<Value>> {
dc9dc135 93 let value = Value::try_from(value).map_err(Error::TomlSerialize)?;
9fa01778
XL
94 self.insert(query, value)
95 }
96
2c00a5a8
XL
97}
98
99impl TomlValueInsertExt for Value {
100
101 fn insert_with_seperator(&mut self, query: &str, sep: char, value: Value) -> Result<Option<Value>> {
dc9dc135 102 use crate::resolver::mut_creating_resolver::resolve;
2c00a5a8 103
dc9dc135 104 let mut tokens = r#try!(tokenize_with_seperator(query, sep));
2c00a5a8
XL
105 let (val, last) = match tokens.pop_last() {
106 None => (self, Box::new(tokens)),
dc9dc135 107 Some(last) => (r#try!(resolve(self, &tokens)), last),
2c00a5a8
XL
108
109 };
110
111 match *last {
112 Token::Identifier { ident, .. } => {
113 match val {
114 &mut Value::Table(ref mut t) => {
115 Ok(t.insert(ident, value))
116 },
dc9dc135 117 _ => Err(Error::NoIdentifierInArray(ident.clone()))
2c00a5a8
XL
118 }
119 },
120
121 Token::Index { idx , .. } => {
122 match val {
123 &mut Value::Array(ref mut a) => {
124 if a.len() > idx {
125 a.insert(idx, value);
126 Ok(None)
127 } else {
128 a.push(value);
129 Ok(None)
130 }
131 },
dc9dc135 132 _ => Err(Error::NoIndexInTable(idx))
2c00a5a8
XL
133 }
134 },
135 }
136 }
137
138}
139
140#[cfg(test)]
141mod test {
142 use super::*;
143 use toml::Value;
144 use toml::from_str as toml_from_str;
145
146 #[test]
147 fn test_insert_one_token() {
dc9dc135
XL
148 use toml::map::Map;
149 let mut toml = Value::Table(Map::new());
2c00a5a8
XL
150
151 let res = toml.insert(&String::from("value"), Value::Integer(1));
152 println!("TOML: {:?}", toml);
153 assert!(res.is_ok());
154
155 let res = res.unwrap();
156 assert!(res.is_none());
157
158 assert!(is_match!(toml, Value::Table(_)));
159 match toml {
160 Value::Table(ref t) => {
161 assert!(!t.is_empty());
162
163 let val = t.get("value");
164 assert!(val.is_some(), "'value' from table {:?} should be Some(_), is None", t);
165 let val = val.unwrap();
166
167 assert!(is_match!(val, &Value::Integer(1)), "Is not one: {:?}", val);
168 },
169 _ => panic!("What just happenend?"),
170 }
171 }
172
173 #[test]
174 fn test_insert_with_seperator_into_table() {
175 let mut toml : Value = toml_from_str(r#"
176 [table]
177 "#).unwrap();
178
179 let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));
180
181 assert!(res.is_ok());
182
183 let res = res.unwrap();
184 assert!(res.is_none());
185
186 assert!(is_match!(toml, Value::Table(_)));
187 match toml {
188 Value::Table(ref t) => {
189 assert!(!t.is_empty());
190
191 let table = t.get("table");
192 assert!(table.is_some());
193
194 let table = table.unwrap();
195 assert!(is_match!(table, &Value::Table(_)));
196 match table {
197 &Value::Table(ref t) => {
198 assert!(!t.is_empty());
199
200 let a = t.get("a");
201 assert!(a.is_some());
202
203 let a = a.unwrap();
204 assert!(is_match!(a, &Value::Integer(1)));
205 },
206 _ => panic!("What just happenend?"),
207 }
208 },
209 _ => panic!("What just happenend?"),
210 }
211 }
212
213 #[test]
214 fn test_insert_with_seperator_into_array() {
215 use std::ops::Index;
216
217 let mut toml : Value = toml_from_str(r#"
218 array = []
219 "#).unwrap();
220
221 let res = toml.insert_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));
222
223 assert!(res.is_ok());
224
225 let res = res.unwrap();
226 assert!(res.is_none());
227
228 assert!(is_match!(toml, Value::Table(_)));
229 match toml {
230 Value::Table(ref t) => {
231 assert!(!t.is_empty());
232
233 let array = t.get("array");
234 assert!(array.is_some());
235
236 let array = array.unwrap();
237 assert!(is_match!(array, &Value::Array(_)));
238 match array {
239 &Value::Array(ref a) => {
240 assert!(!a.is_empty());
241 assert!(is_match!(a.index(0), &Value::Integer(1)));
242 },
243 _ => panic!("What just happenend?"),
244 }
245 },
246 _ => panic!("What just happenend?"),
247 }
248 }
249
250 #[test]
251 fn test_insert_with_seperator_into_nested_table() {
252 let mut toml : Value = toml_from_str(r#"
253 [a.b.c]
254 "#).unwrap();
255
256 let res = toml.insert_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));
257
258 assert!(res.is_ok());
259
260 let res = res.unwrap();
261 assert!(res.is_none());
262
263 assert!(is_match!(toml, Value::Table(_)));
264 match toml {
265 Value::Table(ref outer) => {
266 assert!(!outer.is_empty());
267 let a_tab = outer.get("a");
268 assert!(a_tab.is_some());
269
270 let a_tab = a_tab.unwrap();
271 assert!(is_match!(a_tab, &Value::Table(_)));
272 match a_tab {
273 &Value::Table(ref a) => {
274 assert!(!a.is_empty());
275
276 let b_tab = a.get("b");
277 assert!(b_tab.is_some());
278
279 let b_tab = b_tab.unwrap();
280 assert!(is_match!(b_tab, &Value::Table(_)));
281 match b_tab {
282 &Value::Table(ref b) => {
283 assert!(!b.is_empty());
284
285 let c_tab = b.get("c");
286 assert!(c_tab.is_some());
287
288 let c_tab = c_tab.unwrap();
289 assert!(is_match!(c_tab, &Value::Table(_)));
290 match c_tab {
291 &Value::Table(ref c) => {
292 assert!(!c.is_empty());
293
294 let d = c.get("d");
295 assert!(d.is_some());
296
297 let d = d.unwrap();
298 assert!(is_match!(d, &Value::Integer(1)));
299 },
300 _ => panic!("What just happenend?"),
301 }
302 },
303 _ => panic!("What just happenend?"),
304 }
305 },
306 _ => panic!("What just happenend?"),
307 }
308 },
309 _ => panic!("What just happened?"),
310 }
311 }
312
313 #[test]
314 fn test_insert_with_seperator_into_table_where_array_is() {
315 let mut toml : Value = toml_from_str(r#"
316 table = []
317 "#).unwrap();
318
319 let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));
320
321 assert!(res.is_err());
322
323 let err = res.unwrap_err();
dc9dc135 324 assert!(is_match!(err, Error::NoIdentifierInArray(_)));
2c00a5a8
XL
325 }
326
327 #[test]
328 fn test_insert_with_seperator_into_array_where_table_is() {
329 let mut toml : Value = toml_from_str(r#"
330 [table]
331 "#).unwrap();
332
333 let res = toml.insert_with_seperator(&String::from("table.[0]"), '.', Value::Integer(1));
334
335 assert!(res.is_err());
336
337 let err = res.unwrap_err();
dc9dc135 338 assert!(is_match!(err, Error::NoIndexInTable(_)));
2c00a5a8
XL
339 }
340
341 #[test]
342 fn test_insert_with_seperator_into_array_between_values() {
343 use std::ops::Index;
344
345 let mut toml : Value = toml_from_str(r#"
346 array = [1, 2, 3, 4, 5]
347 "#).unwrap();
348
349 let res = toml.insert_with_seperator(&String::from("array.[2]"), '.', Value::Integer(6));
350
351 assert!(res.is_ok());
352
353 let res = res.unwrap();
354 assert!(res.is_none());
355
356 assert!(is_match!(toml, Value::Table(_)));
357 match toml {
358 Value::Table(ref t) => {
359 assert!(!t.is_empty());
360
361 let array = t.get("array");
362 assert!(array.is_some());
363
364 let array = array.unwrap();
365 assert!(is_match!(array, &Value::Array(_)));
366 match array {
367 &Value::Array(ref a) => {
368 assert!(!a.is_empty());
369 assert!(is_match!(a.index(0), &Value::Integer(1)));
370 assert!(is_match!(a.index(1), &Value::Integer(2)));
371 assert!(is_match!(a.index(2), &Value::Integer(6)));
372 assert!(is_match!(a.index(3), &Value::Integer(3)));
373 assert!(is_match!(a.index(4), &Value::Integer(4)));
374 assert!(is_match!(a.index(5), &Value::Integer(5)));
375 },
376 _ => panic!("What just happenend?"),
377 }
378 },
379 _ => panic!("What just happenend?"),
380 }
381 }
382
383 #[test]
384 fn test_insert_with_seperator_into_table_with_nonexisting_keys() {
385 let mut toml : Value = toml_from_str(r#"
386 "#).unwrap();
387
388 let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));
389
390 assert!(res.is_ok());
391
392 let res = res.unwrap();
393 assert!(res.is_none());
394
395 assert!(is_match!(toml, Value::Table(_)));
396 match toml {
397 Value::Table(ref t) => {
398 assert!(!t.is_empty());
399
400 let table = t.get("table");
401 assert!(table.is_some());
402
403 let table = table.unwrap();
404 assert!(is_match!(table, &Value::Table(_)));
405 match table {
406 &Value::Table(ref t) => {
407 assert!(!t.is_empty());
408
409 let a = t.get("a");
410 assert!(a.is_some());
411
412 let a = a.unwrap();
413 assert!(is_match!(a, &Value::Integer(1)));
414 },
415 _ => panic!("What just happenend?"),
416 }
417 },
418 _ => panic!("What just happenend?"),
419 }
420 }
421
422}
423