1use crate::error::{Error, Result};
2use crate::tokenizer::Token;
3use toml::{map::Map, Value};
5
6pub fn resolve<'doc>(toml: &'doc mut Value, tokens: &Token) -> Result<&'doc mut Value> {
7 match *tokens {
22 Token::Identifier { ref ident, .. } => match toml {
23 Value::Table(ref mut t) => {
24 if t.contains_key(ident) {
25 match tokens.next() {
26 Some(next) => resolve(t.get_mut(ident).unwrap(), next),
27 None => t.get_mut(ident).ok_or_else(|| unreachable!()),
28 }
29 } else {
30 match tokens.next() {
31 Some(next) => {
32 let subdoc = t.entry(ident.clone()).or_insert(Value::Table(Map::new()));
33 resolve(subdoc, next)
34 }
35 None => Ok(t.entry(ident.clone()).or_insert(Value::Table(Map::new()))),
36 }
37 }
38 }
39 Value::Array(_) => Err(Error::NoIdentifierInArray(ident.clone())),
40 _ => unimplemented!(),
41 },
42 Token::Index { idx, .. } => {
43 match toml {
44 Value::Table(_) => Err(Error::NoIndexInTable(idx)),
45 Value::Array(ref mut ary) => {
46 if ary.len() > idx {
47 match tokens.next() {
48 Some(next) => resolve(ary.get_mut(idx).unwrap(), next),
49 None => ary.get_mut(idx).ok_or_else(|| unreachable!()),
50 }
51 } else if let Some(next) = tokens.next() {
52 match next {
53 Token::Identifier { .. } => {
54 ary.push(Value::Table(Map::new()));
55 }
56 Token::Index { .. } => {
57 ary.push(Value::Array(vec![]));
58 }
59 }
60 panic!("Cannot do this")
62 } else {
63 unimplemented!()
64 }
65 }
66 _ => unimplemented!(),
67 }
68 }
69 }
70}
71
72#[cfg(test)]
73mod test {
74 use super::resolve;
75 use crate::tokenizer::*;
76 use toml::from_str as toml_from_str;
77 use toml::Value;
78
79 macro_rules! do_resolve {
80 ( $toml:ident => $query:expr ) => {
81 resolve(
82 &mut $toml,
83 &tokenize_with_seperator(&String::from($query), '.').unwrap(),
84 )
85 };
86 }
87
88 #[test]
89 fn test_resolve_empty_toml_simple_query() {
90 let mut toml = toml_from_str("").unwrap();
91 let result = do_resolve!(toml => "example");
92
93 assert!(result.is_ok());
94 let result = result.unwrap();
95 assert!(is_match!(result, Value::Table(_)));
96 match result {
97 Value::Table(ref tab) => assert!(tab.is_empty()),
98 _ => unreachable!("Expected Table, got something else"),
99 }
100 }
101
102 #[test]
103 fn test_resolve_present_bool() {
104 let mut toml = toml_from_str("example = true").unwrap();
105 let result = do_resolve!(toml => "example");
106
107 assert!(result.is_ok());
108 let result = result.unwrap();
109
110 assert!(is_match!(result, Value::Boolean(true)));
111 }
112
113 #[test]
114 fn test_resolve_present_integer() {
115 let mut toml = toml_from_str("example = 1").unwrap();
116 let result = do_resolve!(toml => "example");
117
118 assert!(result.is_ok());
119 let result = result.unwrap();
120
121 assert!(is_match!(result, Value::Integer(1)));
122 }
123
124 #[test]
125 fn test_resolve_present_float() {
126 let mut toml = toml_from_str("example = 1.0").unwrap();
127 let result = do_resolve!(toml => "example");
128
129 assert!(result.is_ok());
130 let result = result.unwrap();
131
132 assert!(is_match!(result, Value::Float(_)));
133 assert_eq!(result.as_float(), Some(1.0));
134 }
135
136 #[test]
137 fn test_resolve_present_string() {
138 let mut toml = toml_from_str("example = 'string'").unwrap();
139 let result = do_resolve!(toml => "example");
140
141 assert!(result.is_ok());
142 let result = result.unwrap();
143
144 assert!(is_match!(result, Value::String(_)));
145 match result {
146 Value::String(ref s) => assert_eq!("string", s),
147 _ => panic!("What just happened?"),
148 }
149 }
150
151 #[test]
152 fn test_resolve_present_array_bools() {
153 let mut toml = toml_from_str("example = [ true, false ]").unwrap();
154 let result = do_resolve!(toml => "example");
155
156 assert!(result.is_ok());
157 let result = result.unwrap();
158
159 assert!(is_match!(result, Value::Array(_)));
160 match result {
161 Value::Array(ref ary) => {
162 assert_eq!(ary[0], Value::Boolean(true));
163 assert_eq!(ary[1], Value::Boolean(false));
164 }
165 _ => panic!("What just happened?"),
166 }
167 }
168
169 #[test]
170 fn test_resolve_present_array_integers() {
171 let mut toml = toml_from_str("example = [ 1, 1337 ]").unwrap();
172 let result = do_resolve!(toml => "example");
173
174 assert!(result.is_ok());
175 let result = result.unwrap();
176
177 assert!(is_match!(result, Value::Array(_)));
178 match result {
179 Value::Array(ref ary) => {
180 assert_eq!(ary[0], Value::Integer(1));
181 assert_eq!(ary[1], Value::Integer(1337));
182 }
183 _ => panic!("What just happened?"),
184 }
185 }
186
187 #[test]
188 fn test_resolve_present_array_floats() {
189 let mut toml = toml_from_str("example = [ 1.0, 133.25 ]").unwrap();
190 let result = do_resolve!(toml => "example");
191
192 assert!(result.is_ok());
193 let result = result.unwrap();
194
195 assert!(is_match!(result, Value::Array(_)));
196 match result {
197 Value::Array(ref ary) => {
198 assert!(is_match!(ary[0], Value::Float(_)));
199 assert_eq!(ary[0].as_float(), Some(1.0));
200 assert!(is_match!(ary[1], Value::Float(_)));
201 assert_eq!(ary[1].as_float(), Some(133.25));
202 }
203 _ => panic!("What just happened?"),
204 }
205 }
206
207 #[test]
208 fn test_resolve_array_index_query_1() {
209 let mut toml = toml_from_str("example = [ 1 ]").unwrap();
210 let result = do_resolve!(toml => "example.[0]");
211
212 assert!(result.is_ok());
213 let result = result.unwrap();
214
215 assert!(is_match!(result, Value::Integer(1)));
216 }
217
218 #[test]
219 fn test_resolve_array_index_query_2() {
220 let mut toml = toml_from_str("example = [ 1, 2, 3, 4, 5 ]").unwrap();
221 let result = do_resolve!(toml => "example.[4]");
222
223 assert!(result.is_ok());
224 let result = result.unwrap();
225
226 assert!(is_match!(result, Value::Integer(5)));
227 }
228
229 #[test]
230 fn test_resolve_table_element_query() {
231 let mut toml = toml_from_str(
232 r#"
233 [table]
234 value = 42
235 "#,
236 )
237 .unwrap();
238 let result = do_resolve!(toml => "table.value");
239
240 assert!(result.is_ok());
241 let result = result.unwrap();
242
243 assert!(is_match!(result, Value::Integer(42)));
244 }
245
246 #[test]
247 fn test_resolve_table_with_many_elements_element_query() {
248 let mut toml = toml_from_str(
249 r#"
250 [table]
251 value1 = 42
252 value2 = 43
253 value3 = 44
254 value4 = 45
255 value5 = 46
256 "#,
257 )
258 .unwrap();
259 let result = do_resolve!(toml => "table.value1");
260
261 assert!(result.is_ok());
262 let result = result.unwrap();
263
264 assert!(is_match!(result, Value::Integer(42)));
265 }
266
267 #[test]
268 fn test_resolve_table_array_query() {
269 let mut toml = toml_from_str(
270 r#"
271 [table]
272 value1 = [ 42.0, 50.0 ]
273 "#,
274 )
275 .unwrap();
276 let result = do_resolve!(toml => "table.value1");
277
278 assert!(result.is_ok());
279 let result = result.unwrap();
280
281 assert!(is_match!(result, Value::Array(_)));
282 match result {
283 Value::Array(ref ary) => {
284 assert!(is_match!(ary[0], Value::Float(_)));
285 assert_eq!(ary[0].as_float(), Some(42.0));
286 assert!(is_match!(ary[1], Value::Float(_)));
287 assert_eq!(ary[1].as_float(), Some(50.0));
288 }
289 _ => panic!("What just happened?"),
290 }
291 }
292
293 #[test]
294 fn test_resolve_table_array_element_query() {
295 let mut toml = toml_from_str(
296 r#"
297 [table]
298 value1 = [ 42 ]
299 "#,
300 )
301 .unwrap();
302 let result = do_resolve!(toml => "table.value1.[0]");
303
304 assert!(result.is_ok());
305 let result = result.unwrap();
306
307 assert!(is_match!(result, Value::Integer(42)));
308 }
309
310 #[test]
311 fn test_resolve_multi_table_query() {
312 let mut toml = toml_from_str(
313 r#"
314 [table0]
315 value = [ 1 ]
316 [table1]
317 value = [ "Foo" ]
318 [table2]
319 value = [ 42.0 ]
320 [table3]
321 value = [ true ]
322 "#,
323 )
324 .unwrap();
325 let result = do_resolve!(toml => "table1.value.[0]");
326
327 assert!(result.is_ok());
328 let result = result.unwrap();
329
330 assert!(is_match!(result, Value::String(_)));
331 match result {
332 Value::String(ref s) => assert_eq!("Foo", s),
333 _ => panic!("What just happened?"),
334 }
335 }
336
337 static FRUIT_TABLE: &str = r#"
338 [[fruit.blah]]
339 name = "apple"
340
341 [fruit.blah.physical]
342 color = "red"
343 shape = "round"
344
345 [[fruit.blah]]
346 name = "banana"
347
348 [fruit.blah.physical]
349 color = "yellow"
350 shape = "bent"
351 "#;
352
353 #[test]
354 fn test_resolve_array_table_query_1() {
355 let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
356 let result = do_resolve!(toml => "fruit.blah.[0].name");
357
358 assert!(result.is_ok());
359 let result = result.unwrap();
360
361 assert!(is_match!(result, Value::String(_)));
362 match result {
363 Value::String(ref s) => assert_eq!("apple", s),
364 _ => panic!("What just happened?"),
365 }
366 }
367
368 #[test]
369 fn test_resolve_array_table_query_2() {
370 let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
371 let result = do_resolve!(toml => "fruit.blah.[0].physical");
372
373 assert!(result.is_ok());
374 let result = result.unwrap();
375
376 assert!(is_match!(result, Value::Table(_)));
377 match result {
378 Value::Table(ref tab) => {
379 match tab.get("color") {
380 Some(&Value::String(ref s)) => assert_eq!("red", s),
381 _ => unreachable!(),
382 }
383 match tab.get("shape") {
384 Some(&Value::String(ref s)) => assert_eq!("round", s),
385 _ => unreachable!(),
386 }
387 }
388 _ => panic!("What just happened?"),
389 }
390 }
391
392 #[test]
393 fn test_resolve_query_on_result() {
394 let mut toml = toml_from_str(FRUIT_TABLE).unwrap();
395 let result = do_resolve!(toml => "fruit.blah.[1].physical");
396
397 assert!(result.is_ok());
398 let result = result.unwrap();
399
400 let tokens = tokenize_with_seperator(&String::from("color"), '.').unwrap();
401 let result = resolve(result, &tokens);
402
403 assert!(result.is_ok());
404 let result = result.unwrap();
405
406 assert!(is_match!(result, Value::String(_)));
407 match result {
408 Value::String(ref s) => assert_eq!("yellow", s),
409 _ => panic!("What just happened?"),
410 }
411 }
412
413 #[test]
414 fn test_resolve_query_empty_table() {
415 let mut toml = toml_from_str(
416 r#"
417 [example]
418 "#,
419 )
420 .unwrap();
421 let result = do_resolve!(toml => "example");
422
423 assert!(result.is_ok());
424 let result = result.unwrap();
425
426 assert!(is_match!(result, Value::Table(_)));
427 match result {
428 Value::Table(ref t) => assert!(t.is_empty()),
429 _ => panic!("What just happened?"),
430 }
431 }
432
433 #[test]
434 fn test_resolve_query_member_of_empty_table() {
435 let mut toml = toml_from_str("").unwrap();
436 let result = do_resolve!(toml => "example.foo");
437
438 assert!(result.is_ok());
439 let result = result.unwrap();
440 assert!(is_match!(result, Value::Table(_)));
441 match result {
442 Value::Table(ref t) => assert!(t.is_empty()),
443 _ => panic!("What just happened?"),
444 }
445 }
446
447 #[test]
448 fn test_resolve_query_index_in_table() {
449 let mut toml = toml_from_str("").unwrap();
450 let result = do_resolve!(toml => "example.[0]");
451
452 assert!(result.is_err());
454
455 }
464
465 #[test]
466 fn test_resolve_query_identifier_in_array() {
467 let mut toml = toml_from_str("").unwrap();
468 let result = do_resolve!(toml => "example.foo.bar");
469
470 assert!(result.is_ok());
471 let result = result.unwrap();
472
473 match result {
474 Value::Table(ref t) => assert!(t.is_empty()),
475 _ => panic!("What just happened?"),
476 }
477 }
478
479 #[test]
480 fn test_resolve_query_value_as_table() {
481 let mut toml = toml_from_str("").unwrap();
482 let result = do_resolve!(toml => "example.foo.bar");
483
484 assert!(result.is_ok());
485 let result = result.unwrap();
486
487 match result {
488 Value::Table(ref t) => assert!(t.is_empty()),
489 _ => panic!("What just happened?"),
490 }
491 }
492
493 #[test]
494 fn test_resolve_query_value_as_array() {
495 let mut toml = toml_from_str("").unwrap();
496 let result = do_resolve!(toml => "example.foo.[0]");
497
498 assert!(result.is_err());
500
501 }
509}