1#[cfg(feature = "typed")]
8use serde::Serialize;
9use toml::Value;
10
11use crate::error::{Error, Result};
12use crate::tokenizer::tokenize_with_seperator;
13use crate::tokenizer::Token;
14
15pub trait TomlValueInsertExt {
17 fn insert_with_seperator(
86 &mut self,
87 query: &str,
88 sep: char,
89 value: Value,
90 ) -> Result<Option<Value>>;
91
92 fn insert(&mut self, query: &str, value: Value) -> Result<Option<Value>> {
96 self.insert_with_seperator(query, '.', value)
97 }
98
99 #[cfg(feature = "typed")]
101 fn insert_serialized<S: Serialize>(&mut self, query: &str, value: S) -> Result<Option<Value>> {
102 let value = Value::try_from(value).map_err(Error::TomlSerialize)?;
103 self.insert(query, value)
104 }
105}
106
107impl TomlValueInsertExt for Value {
108 fn insert_with_seperator(
109 &mut self,
110 query: &str,
111 sep: char,
112 value: Value,
113 ) -> Result<Option<Value>> {
114 use crate::resolver::mut_creating_resolver::resolve;
115
116 let mut tokens = tokenize_with_seperator(query, sep)?;
117 let (val, last) = match tokens.pop_last() {
118 None => (self, Box::new(tokens)),
119 Some(last) => (resolve(self, &tokens)?, last),
120 };
121
122 match *last {
123 Token::Identifier { ident, .. } => match val {
124 Value::Table(ref mut t) => Ok(t.insert(ident, value)),
125 _ => Err(Error::NoIdentifierInArray(ident)),
126 },
127
128 Token::Index { idx, .. } => match val {
129 Value::Array(ref mut a) => {
130 if a.len() > idx {
131 a.insert(idx, value);
132 Ok(None)
133 } else {
134 a.push(value);
135 Ok(None)
136 }
137 }
138 _ => Err(Error::NoIndexInTable(idx)),
139 },
140 }
141 }
142}
143
144#[cfg(test)]
145mod test {
146 use super::*;
147 use toml::from_str as toml_from_str;
148 use toml::Value;
149
150 #[test]
151 fn test_insert_one_token() {
152 use toml::map::Map;
153 let mut toml = Value::Table(Map::new());
154
155 let res = toml.insert(&String::from("value"), Value::Integer(1));
156 println!("TOML: {:?}", toml);
157 assert!(res.is_ok());
158
159 let res = res.unwrap();
160 assert!(res.is_none());
161
162 assert!(is_match!(toml, Value::Table(_)));
163 match toml {
164 Value::Table(ref t) => {
165 assert!(!t.is_empty());
166
167 let val = t.get("value");
168 assert!(
169 val.is_some(),
170 "'value' from table {:?} should be Some(_), is None",
171 t
172 );
173 let val = val.unwrap();
174
175 assert!(is_match!(val, Value::Integer(1)), "Is not one: {:?}", val);
176 }
177 _ => panic!("What just happenend?"),
178 }
179 }
180
181 #[test]
182 fn test_insert_with_seperator_into_table() {
183 let mut toml: Value = toml_from_str(
184 r#"
185 [table]
186 "#,
187 )
188 .unwrap();
189
190 let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));
191
192 assert!(res.is_ok());
193
194 let res = res.unwrap();
195 assert!(res.is_none());
196
197 assert!(is_match!(toml, Value::Table(_)));
198 match toml {
199 Value::Table(ref t) => {
200 assert!(!t.is_empty());
201
202 let table = t.get("table");
203 assert!(table.is_some());
204
205 let table = table.unwrap();
206 assert!(is_match!(table, Value::Table(_)));
207 match table {
208 Value::Table(ref t) => {
209 assert!(!t.is_empty());
210
211 let a = t.get("a");
212 assert!(a.is_some());
213
214 let a = a.unwrap();
215 assert!(is_match!(a, Value::Integer(1)));
216 }
217 _ => panic!("What just happenend?"),
218 }
219 }
220 _ => panic!("What just happenend?"),
221 }
222 }
223
224 #[test]
225 fn test_insert_with_seperator_into_array() {
226 use std::ops::Index;
227
228 let mut toml: Value = toml_from_str(
229 r#"
230 array = []
231 "#,
232 )
233 .unwrap();
234
235 let res = toml.insert_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));
236
237 assert!(res.is_ok());
238
239 let res = res.unwrap();
240 assert!(res.is_none());
241
242 assert!(is_match!(toml, Value::Table(_)));
243 match toml {
244 Value::Table(ref t) => {
245 assert!(!t.is_empty());
246
247 let array = t.get("array");
248 assert!(array.is_some());
249
250 let array = array.unwrap();
251 assert!(is_match!(array, Value::Array(_)));
252 match array {
253 Value::Array(ref a) => {
254 assert!(!a.is_empty());
255 assert!(is_match!(a.index(0), Value::Integer(1)));
256 }
257 _ => panic!("What just happenend?"),
258 }
259 }
260 _ => panic!("What just happenend?"),
261 }
262 }
263
264 #[test]
265 fn test_insert_with_seperator_into_nested_table() {
266 let mut toml: Value = toml_from_str(
267 r#"
268 [a.b.c]
269 "#,
270 )
271 .unwrap();
272
273 let res = toml.insert_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));
274
275 assert!(res.is_ok());
276
277 let res = res.unwrap();
278 assert!(res.is_none());
279
280 assert!(is_match!(toml, Value::Table(_)));
281 match toml {
282 Value::Table(ref outer) => {
283 assert!(!outer.is_empty());
284 let a_tab = outer.get("a");
285 assert!(a_tab.is_some());
286
287 let a_tab = a_tab.unwrap();
288 assert!(is_match!(a_tab, Value::Table(_)));
289 match a_tab {
290 Value::Table(ref a) => {
291 assert!(!a.is_empty());
292
293 let b_tab = a.get("b");
294 assert!(b_tab.is_some());
295
296 let b_tab = b_tab.unwrap();
297 assert!(is_match!(b_tab, Value::Table(_)));
298 match b_tab {
299 Value::Table(ref b) => {
300 assert!(!b.is_empty());
301
302 let c_tab = b.get("c");
303 assert!(c_tab.is_some());
304
305 let c_tab = c_tab.unwrap();
306 assert!(is_match!(c_tab, Value::Table(_)));
307 match c_tab {
308 Value::Table(ref c) => {
309 assert!(!c.is_empty());
310
311 let d = c.get("d");
312 assert!(d.is_some());
313
314 let d = d.unwrap();
315 assert!(is_match!(d, Value::Integer(1)));
316 }
317 _ => panic!("What just happenend?"),
318 }
319 }
320 _ => panic!("What just happenend?"),
321 }
322 }
323 _ => panic!("What just happenend?"),
324 }
325 }
326 _ => panic!("What just happened?"),
327 }
328 }
329
330 #[test]
331 fn test_insert_with_seperator_into_table_where_array_is() {
332 let mut toml: Value = toml_from_str(
333 r#"
334 table = []
335 "#,
336 )
337 .unwrap();
338
339 let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));
340
341 assert!(res.is_err());
342
343 let err = res.unwrap_err();
344 assert!(is_match!(err, Error::NoIdentifierInArray(_)));
345 }
346
347 #[test]
348 fn test_insert_with_seperator_into_array_where_table_is() {
349 let mut toml: Value = toml_from_str(
350 r#"
351 [table]
352 "#,
353 )
354 .unwrap();
355
356 let res = toml.insert_with_seperator(&String::from("table.[0]"), '.', Value::Integer(1));
357
358 assert!(res.is_err());
359
360 let err = res.unwrap_err();
361 assert!(is_match!(err, Error::NoIndexInTable(_)));
362 }
363
364 #[test]
365 fn test_insert_with_seperator_into_array_between_values() {
366 use std::ops::Index;
367
368 let mut toml: Value = toml_from_str(
369 r#"
370 array = [1, 2, 3, 4, 5]
371 "#,
372 )
373 .unwrap();
374
375 let res = toml.insert_with_seperator(&String::from("array.[2]"), '.', Value::Integer(6));
376
377 assert!(res.is_ok());
378
379 let res = res.unwrap();
380 assert!(res.is_none());
381
382 assert!(is_match!(toml, Value::Table(_)));
383 match toml {
384 Value::Table(ref t) => {
385 assert!(!t.is_empty());
386
387 let array = t.get("array");
388 assert!(array.is_some());
389
390 let array = array.unwrap();
391 assert!(is_match!(array, Value::Array(_)));
392 match array {
393 Value::Array(ref a) => {
394 assert!(!a.is_empty());
395 assert!(is_match!(a.index(0), Value::Integer(1)));
396 assert!(is_match!(a.index(1), Value::Integer(2)));
397 assert!(is_match!(a.index(2), Value::Integer(6)));
398 assert!(is_match!(a.index(3), Value::Integer(3)));
399 assert!(is_match!(a.index(4), Value::Integer(4)));
400 assert!(is_match!(a.index(5), Value::Integer(5)));
401 }
402 _ => panic!("What just happenend?"),
403 }
404 }
405 _ => panic!("What just happenend?"),
406 }
407 }
408
409 #[test]
410 fn test_insert_with_seperator_into_table_with_nonexisting_keys() {
411 let mut toml: Value = toml_from_str(
412 r#"
413 "#,
414 )
415 .unwrap();
416
417 let res = toml.insert_with_seperator(&String::from("table.a"), '.', Value::Integer(1));
418
419 assert!(res.is_ok());
420
421 let res = res.unwrap();
422 assert!(res.is_none());
423
424 assert!(is_match!(toml, Value::Table(_)));
425 match toml {
426 Value::Table(ref t) => {
427 assert!(!t.is_empty());
428
429 let table = t.get("table");
430 assert!(table.is_some());
431
432 let table = table.unwrap();
433 assert!(is_match!(table, Value::Table(_)));
434 match table {
435 Value::Table(ref t) => {
436 assert!(!t.is_empty());
437
438 let a = t.get("a");
439 assert!(a.is_some());
440
441 let a = a.unwrap();
442 assert!(is_match!(a, Value::Integer(1)));
443 }
444 _ => panic!("What just happenend?"),
445 }
446 }
447 _ => panic!("What just happenend?"),
448 }
449 }
450}