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