valid_toml/
toml_iter.rs

1/* Copyright 2016 Joshua Gentry
2 *
3 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 * option. This file may not be copied, modified, or distributed
7 * except according to those terms.
8 */
9use std::collections::BTreeMap;
10use std::collections::btree_map::Iter;
11use std::iter::Peekable;
12
13use toml::Value;
14
15use item_def::ItemDef;
16use notify::Notify;
17
18//*************************************************************************************************
19/// Internal state for the iterator.
20enum State
21{
22    //---------------------------------------------------------------------------------------------
23    /// Normal (success) state, we have an item along with it's definition.
24    Normal,
25
26    //---------------------------------------------------------------------------------------------
27    /// We've finished the iterator.
28    Done,
29
30    //---------------------------------------------------------------------------------------------
31    /// We've encountered an item that does not have a definition.
32    UnknownInput,
33
34    //---------------------------------------------------------------------------------------------
35    /// We've encountered an definition that does not have an item.
36    MissingInput
37}
38
39//*************************************************************************************************
40/// Returns the value from the next iteration.
41pub enum Next<'a, 'b, 'c>
42{
43    //---------------------------------------------------------------------------------------------
44    /// We have an item and it's definition.
45    NextItem(&'a String, &'a Value, &'b Box<ItemDef>, Option<&'c Box<Notify>>),
46
47    //---------------------------------------------------------------------------------------------
48    /// The next item in the input doesn't have a matching definition.
49    UnknownInput(&'a String, &'a Value),
50
51    //---------------------------------------------------------------------------------------------
52    /// We have a definition but no matching input item.
53    MissingInput(&'b String, &'b Box<ItemDef>, Option<&'c Box<Notify>>),
54
55}
56
57//*************************************************************************************************
58/// This object iterates over three BTreeMap iterators and keeps them in sync by comparing the
59/// keys.  This is possible since the BTreeMap keeps the keys in the same order.
60pub struct TomlIter<'a, 'b, 'c>
61{
62    //---------------------------------------------------------------------------------------------
63    /// The iterator iterating over the values read from the TOML file.
64    input_iter : Peekable<Iter<'a, String, Value>>,
65
66    //---------------------------------------------------------------------------------------------
67    /// The iterator iterating over the definitions for the items.
68    define_iter : Peekable<Iter<'b, String, Box<ItemDef>>>,
69
70    //---------------------------------------------------------------------------------------------
71    /// The iterator iterating over the notifications we need to make.
72    notify_iter : Peekable<Iter<'c, String, Box<Notify>>>
73}
74
75impl<'a, 'b, 'c> TomlIter<'a, 'b, 'c>
76{
77    //*********************************************************************************************
78    /// Construct a new instance of the object.
79    pub fn new(
80        input : &'a BTreeMap<String, Value>,
81        define : &'b BTreeMap<String, Box<ItemDef>>,
82        notify : &'c BTreeMap<String, Box<Notify>>
83        ) -> TomlIter<'a, 'b, 'c>
84    {
85        TomlIter {
86            input_iter  : input.iter().peekable(),
87            define_iter : define.iter().peekable(),
88            notify_iter : notify.iter().peekable()
89        }
90    }
91
92    //*********************************************************************************************
93    /// Determines the current state of the iterator.
94    fn state(&mut self) -> State
95    {
96        let input      = self.input_iter.peek();
97        let definition = self.define_iter.peek();
98
99        //-----------------------------------------------------------------------------------------
100        // Neither the input iterator or the definition iterator has completed, compare the
101        // names to see what the state is.
102        if input.is_some() && definition.is_some()
103        {
104            let &(input_name, _) = input.unwrap();
105            let &(def_name, _)   = definition.unwrap();
106
107            //-------------------------------------------------------------------------------------
108            // If the input name is before the definition name, then we don't have a definition
109            // for the input.
110            if input_name < def_name
111            {
112                State::UnknownInput
113            }
114            //-------------------------------------------------------------------------------------
115            // If the definition name is before the ionput name, then we are missing an element
116            // from the input.
117            else if def_name < input_name
118            {
119                State::MissingInput
120            }
121            //-------------------------------------------------------------------------------------
122            // The names are equal, we're in a "normal" state.
123            else
124            {
125                State::Normal
126            }
127        }
128        //-----------------------------------------------------------------------------------------
129        // If there is an input (and no definition) then we have an input value without a matching
130        // definition.
131        else if input.is_some()
132        {
133            State::UnknownInput
134        }
135        //-----------------------------------------------------------------------------------------
136        // If there is a definition (and no input) then we're missing an input.
137        else if definition.is_some()
138        {
139            State::MissingInput
140        }
141        //-----------------------------------------------------------------------------------------
142        // Both iterators are none, so we're done.
143        else
144        {
145            State::Done
146        }
147    }
148
149    //*********************************************************************************************
150    /// Checks if we have a notification for the specified name.
151    fn notification(
152        &mut self,
153        name : &String
154        ) -> Option<&'c Box<Notify>>
155    {
156        if let Some(&(notify_name, _)) = self.notify_iter.peek()
157        {
158            if name == notify_name
159            {
160                let (_, notify_value) = self.notify_iter.next().unwrap();
161
162                Some(notify_value)
163            }
164            else
165            {
166                None
167            }
168        }
169        else
170        {
171            None
172        }
173    }
174
175    //*********************************************************************************************
176    /// We have an item with no defintion, construct the UnknownInput enum to return to the client.
177    fn unknown_item(&mut self) -> Next<'a, 'b, 'c>
178    {
179        let (name, value) = self.input_iter.next().unwrap();
180
181        Next::UnknownInput(name, value)
182    }
183
184    //*********************************************************************************************
185    /// We have a definition without an input, construct the MissingInput enum to return to the
186    /// client.  Also check if there is a notification that needs to go out with it.
187    fn missing_item(&mut self) -> Next<'a, 'b, 'c>
188    {
189        let (name, value) = self.define_iter.next().unwrap();
190        let notify        = self.notification(name);
191
192        Next::MissingInput(name, value, notify)
193    }
194
195    //*********************************************************************************************
196    /// Normal state we have an item and a definition, also check if there is a notification that
197    /// needs to go out with it.
198    fn next_item(&mut self) -> Next<'a, 'b, 'c>
199    {
200        let (name, value) = self.input_iter.next().unwrap();
201        let (_, define)   = self.define_iter.next().unwrap();
202        let notify        = self.notification(name);
203
204        Next::NextItem(name, value, define, notify)
205    }
206
207    //*********************************************************************************************
208    /// Returns the next item from the interator.
209    pub fn next(&mut self) -> Option<Next>
210    {
211        match self.state()
212        {
213            State::Normal       => Some(self.next_item()),
214            State::Done         => None,
215            State::UnknownInput => Some(self.unknown_item()),
216            State::MissingInput => Some(self.missing_item())
217        }
218    }
219}
220
221#[cfg(test)]
222mod tests
223{
224    use std::collections::BTreeMap;
225
226    use toml::Value;
227
228    use data::ItemUsize;
229    use item_def::ItemDef;
230    use notify::Notify;
231    use value::UsizeValue;
232
233    macro_rules! assert_item {
234        ($test:expr, $name:expr, $val:expr, $notify:expr) => {{
235            match $test.unwrap()
236            {
237                super::Next::NextItem(name, value, def, notify) => {
238                    assert_eq!(name, $name);
239                    assert_eq!(def.name(), name);
240                    assert_eq!($val, value.as_integer().unwrap());
241
242                    if $notify
243                    {
244                        assert!(notify.is_some());
245                    }
246                    else
247                    {
248                        assert!(notify.is_none());
249                    }
250                },
251                _ => {
252                    panic!("{} not found.", $name);
253                }
254            }
255        }}
256    }
257
258    macro_rules! assert_unknown {
259        ($test:expr, $name:expr, $val:expr) => {{
260            match $test.unwrap()
261            {
262                super::Next::UnknownInput(name, value) => {
263                    assert_eq!(name, $name);
264                    assert_eq!($val, value.as_integer().unwrap());
265                },
266                _ => {
267                    panic!("{} is known.", $name);
268                }
269            }
270        }}
271    }
272
273    macro_rules! assert_missing {
274        ($test:expr, $name:expr, $notify:expr) => {{
275            match $test.unwrap()
276            {
277                super::Next::MissingInput(name, def, notify) => {
278                    assert_eq!(name, $name);
279                    assert_eq!(def.name(), name);
280
281                    if $notify
282                    {
283                        assert!(notify.is_some());
284                    }
285                    else
286                    {
287                        assert!(notify.is_none());
288                    }
289                },
290                _ => {
291                    panic!("{} is not missing.", $name);
292                }
293            }
294        }}
295    }
296
297    //*********************************************************************************************
298    /// Helper method to generate the 3 BTree maps we need to iterate over.
299    fn generate(
300        mut data : Vec<(&str, i64)>
301        ) -> (BTreeMap<String, Value>, BTreeMap<String, Box<ItemDef>>, BTreeMap<String, Box<Notify>>)
302    {
303        let mut input  : BTreeMap<String, Value>        = BTreeMap::new();
304        let mut define : BTreeMap<String, Box<ItemDef>> = BTreeMap::new();
305        let mut notify : BTreeMap<String, Box<Notify>>  = BTreeMap::new();
306
307        for (name, value) in data.drain(..)
308        {
309            input.insert(String::from(name), Value::Integer(value));
310            define.insert(String::from(name), Box::new(ItemUsize::with_name(name)));
311            notify.insert(String::from(name), Box::new(UsizeValue::new()));
312        }
313
314        (input, define, notify)
315    }
316
317    //*********************************************************************************************
318    /// "Normal" case everything exists.
319    #[test]
320    fn normal()
321    {
322        let (input, define, notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
323        let mut test = super::TomlIter::new(&input, &define, &notify);
324
325        assert_item!(test.next(), "a", 1, true);
326        assert_item!(test.next(), "b", 2, true);
327        assert_item!(test.next(), "c", 3, true);
328        assert_item!(test.next(), "d", 4, true);
329        assert!(test.next().is_none());
330    }
331
332    //*********************************************************************************************
333    /// Test with no notification elements.
334    #[test]
335    fn no_notify()
336    {
337        let (input, define, _) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
338        let notify = BTreeMap::new();
339        let mut test = super::TomlIter::new(&input, &define, &notify);
340
341        assert_item!(test.next(), "a", 1, false);
342        assert_item!(test.next(), "b", 2, false);
343        assert_item!(test.next(), "c", 3, false);
344        assert_item!(test.next(), "d", 4, false);
345        assert!(test.next().is_none());
346    }
347
348    //*********************************************************************************************
349    /// Test with no define elements.
350    #[test]
351    fn no_define()
352    {
353        let (input, _, _) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
354        let define = BTreeMap::new();
355        let notify = BTreeMap::new();
356        let mut test = super::TomlIter::new(&input, &define, &notify);
357
358        assert_unknown!(test.next(), "a", 1);
359        assert_unknown!(test.next(), "b", 2);
360        assert_unknown!(test.next(), "c", 3);
361        assert_unknown!(test.next(), "d", 4);
362        assert!(test.next().is_none());
363    }
364
365    //*********************************************************************************************
366    /// Test with no values.
367    #[test]
368    fn no_values()
369    {
370        let (_, define, notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
371        let input = BTreeMap::new();
372        let mut test = super::TomlIter::new(&input, &define, &notify);
373
374        assert_missing!(test.next(), "a", true);
375        assert_missing!(test.next(), "b", true);
376        assert_missing!(test.next(), "c", true);
377        assert_missing!(test.next(), "d", true);
378        assert!(test.next().is_none());
379    }
380
381    //*********************************************************************************************
382    /// Test with the first value missing.
383    #[test]
384    fn missing_first()
385    {
386        let (mut input, define, notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
387
388        input.remove("a");
389
390        let mut test = super::TomlIter::new(&input, &define, &notify);
391
392        assert_missing!(test.next(), "a", true);
393        assert_item!(test.next(), "b", 2, true);
394        assert_item!(test.next(), "c", 3, true);
395        assert_item!(test.next(), "d", 4, true);
396        assert!(test.next().is_none());
397    }
398
399    //*********************************************************************************************
400    /// Test with a middle value missing.
401    #[test]
402    fn missing_middle()
403    {
404        let (mut input, define, notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
405
406        input.remove("b");
407
408        let mut test = super::TomlIter::new(&input, &define, &notify);
409
410        assert_item!(test.next(), "a", 1, true);
411        assert_missing!(test.next(), "b", true);
412        assert_item!(test.next(), "c", 3, true);
413        assert_item!(test.next(), "d", 4, true);
414        assert!(test.next().is_none());
415    }
416
417    //*********************************************************************************************
418    /// Test with the lat value missing.
419    #[test]
420    fn missing_last()
421    {
422        let (mut input, define, notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
423
424        input.remove("d");
425
426        let mut test = super::TomlIter::new(&input, &define, &notify);
427
428        assert_item!(test.next(), "a", 1, true);
429        assert_item!(test.next(), "b", 2, true);
430        assert_item!(test.next(), "c", 3, true);
431        assert_missing!(test.next(), "d", true);
432        assert!(test.next().is_none());
433    }
434
435    //*********************************************************************************************
436    /// Test with the first item being undefined.
437    #[test]
438    fn undefined_first()
439    {
440        let (input, mut define, mut notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
441
442        define.remove("a");
443        notify.remove("a");
444
445        let mut test = super::TomlIter::new(&input, &define, &notify);
446
447        assert_unknown!(test.next(), "a", 1);
448        assert_item!(test.next(), "b", 2, true);
449        assert_item!(test.next(), "c", 3, true);
450        assert_item!(test.next(), "d", 4, true);
451        assert!(test.next().is_none());
452    }
453
454    //*********************************************************************************************
455    /// Test with a middle value being undefined.
456    #[test]
457    fn undefined_middle()
458    {
459        let (input, mut define, mut notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
460
461        define.remove("b");
462        notify.remove("b");
463
464        let mut test = super::TomlIter::new(&input, &define, &notify);
465
466        assert_item!(test.next(), "a", 1, true);
467        assert_unknown!(test.next(), "b", 2);
468        assert_item!(test.next(), "c", 3, true);
469        assert_item!(test.next(), "d", 4, true);
470        assert!(test.next().is_none());
471    }
472
473    //*********************************************************************************************
474    /// Test with the last value being undefined.
475    #[test]
476    fn undefined_last()
477    {
478        let (input, mut define, mut notify) = generate(vec![("a", 1), ("b", 2), ("c", 3), ("d", 4)]);
479
480        define.remove("d");
481        notify.remove("d");
482
483        let mut test = super::TomlIter::new(&input, &define, &notify);
484
485        assert_item!(test.next(), "a", 1, true);
486        assert_item!(test.next(), "b", 2, true);
487        assert_item!(test.next(), "c", 3, true);
488        assert_unknown!(test.next(), "d", 4);
489        assert!(test.next().is_none());
490    }
491
492}