sml/
lib.rs

1//! # SML
2//! 
3//! `SML` is a simple markup language designed to convert human readable information into Rust
4//! types with a very specific purpose of loading config files and schemas.
5//!
6//! The format looks like
7//! 
8//! ```text
9//! hobbit:
10//!     name:           Frodo Baggins
11//!     age:            98
12//!     friends:
13//!         hobbit:
14//!             name:   Bilbo Baggins
15//!             age:    176
16//!         hobbit:
17//!             name:   Samwise Gamgee
18//!             age:    66
19//! ```
20//!
21//! ## Data Format Rules
22//! 
23//! 1. Indentation has meaning and is 4 spaces, relative to the top key. If indenting is relative
24//!    to the top key, then you can neatly align strings embedded in code.
25//! 
26//! 2. All values must be double quoted.
27//! 
28//! 3. Key/value combinations are used for fields
29//! ```text
30//! name: "Frodo"
31//! ```
32//! are used for `struct` fields and `enum` variants. Keys only
33//! ```text
34//! hobbit:
35//!     name: "Frodo"
36//! ```
37//! indicate a complete `struct` or `enum`. In this way, the data clearly indicates the mapping to
38//! Rust data structures.
39//! 
40//! 4. Separation of lines has meaning.
41//! 
42//! 5. Keys must not include but must be followed by a colon `:`.
43//! 
44//! 6. Double quotes in values must be escaped using `\"`.
45//! 
46//! 7. Everything after the second double quote is ignored.
47//! 
48//! 8. Empty lines or lines with whitespace only are ignored.
49//!
50//! 9. Comments require `//` at the start of the line for example
51//!
52//! ```text
53//! // comment
54//! hobbit:
55//!     name: "Frodo"
56//! ```
57//! 
58//! ## Example. From `Small`-formatted string to your data-structure.
59//!
60//! This examples should cover 90 percent of use cases.
61//! 
62//! ```rust
63//! use sml::{Small, FromSmall, SmallError};
64//! 
65//! #[derive(Debug)]
66//! struct Hobbit {
67//!     name:    String,
68//!     age:     u32,
69//!     friends: Vec<Hobbit>,
70//!     bicycle: Option<String>,
71//! }
72//! 
73//! impl FromSmall for Hobbit {
74//!     fn from_small(s: &Small) -> Result<Self, SmallError> {
75//!         Ok(Hobbit {
76//!             name:    String::path(&s, "hobbit::name")?,
77//!             age:     u32::path(&s, "hobbit::age")?,
78//!             friends: Vec::<Hobbit>::path(&s, "hobbit::friends::hobbit")?,
79//!             bicycle: Option::<String>::path(&s, "hobbit::bicycle")?,
80//!         })
81//!     }
82//! }
83//! 
84//! fn main() {
85//!     let s = r#"
86//!         hobbit:
87//!             name:         "Frodo Baggins"
88//!             age:          "98"
89//!             friends:
90//!                 hobbit:
91//!                     name: "Bilbo Baggins"
92//!                     age:  "176"
93//!                 hobbit:
94//!                     name: "Samwise Gamgee"
95//!                     age:  "66""#;
96//!     
97//!     let frodo = Hobbit::from_str_debug(s);
98//!     println!("name: {}", frodo.name);
99//! }
100//! ```
101//!
102//! ## `FromSmall` Trait
103//! Types that implement the `FromSmall` trait can be constructed from a `Small`-formatted string.
104//!
105//! Required function:
106//! ```rust
107//! from_small(slice: &Small) -> Result<Self, SmallError>
108//! ```
109//! The `from_small()` function describes how to create a data-structure from the parts of
110//! `Small`.
111//!
112//! ```rust
113//! path(small: &Small, key_path: &str) -> Result<Self, SmallError>
114//! ```
115//! Reduces `Small` to the `key_path` and then uses the `FromSmall` trait to convert to the
116//! receiver type.
117//!
118//! ```rust
119//! from_str(s: &str) -> Result<Self, SmallError>
120//! ```
121//! Top level function that convert a `Small`-formatted string into the receiver.
122//!
123//! ```rust
124//! from_str_debug(s: &str) -> Self
125//! ```
126//! Top level function that converts a `Small`-formatted string into the receiver giving helpful
127//! error messages for debugging.
128//!
129//! # Implementation
130//!
131//! A `Small` value may be a collection of `Small` values. For example,
132//!
133//! ```text
134//! hobbit:
135//!     name: "Bilbo Baggins"
136//!     age:  "176"
137//! hobbit:
138//!     name: "Samwise Gamgee"
139//!     age:  "66"
140//! ```
141//! is a collection of two elements
142//! ```text
143//! hobbit:
144//!     name: "Bilbo Baggins"
145//!     age:  "176"
146//! ```
147//! and 
148//! ```text
149//! hobbit:
150//!     name: "Samwise Gamgee"
151//!     age:  "66"
152//! ```
153//! Often when implementing `FromSmall` we want to convert a `Small` object into a single value, so
154//! we need to check that `Small` has only one element The implementation to convert from `Small`
155//! to `u32` gives indicates how to do this. `unique_value()` checks that there is only one element
156//! in `Small` and if so returns that one element and `value()` extracts that value as a `String`.
157//!
158//! ```rust
159//! impl FromSmall for u32 {
160//!     fn from_small(s: &Small) -> Result<Self, SmallError> {
161//!         let token = s.unique_value()?;
162//!         token
163//!             .value()?
164//!             .parse::<u32>()
165//!             .map_err(|_| SmallError::ParseValue(token, "u32"))
166//!     }
167//! }
168//! ```
169
170// #![feature(try_trait)]
171
172use colored::Colorize;
173use core::str::Split;
174use std::error::Error;
175use std::fmt::Display;
176use std::ops::Index;
177use std::fmt;
178use std::process::exit;
179
180const INDENTSTEP: usize = 4;
181
182fn spaces(i: usize) -> String {
183    let mut s = String::new();
184    for _n in 0..i { s.push_str(" ") };
185    s
186}
187
188// The line number of the error be found in `Token`.
189#[derive(Debug, PartialEq)]
190pub enum SmallError {
191    ///
192    /// Expected a key but could not find it. Holds the `Token` that failed to parse and the
193    /// position in the line of the following colon.
194    ///
195    EmptyKey(Token, usize), 
196
197    ///
198    /// Indentation should be aligned by 4 to the top key. `usize` refers to the indent of the top
199    /// key in the original string.
200    ///
201    Indent(Token, usize),
202
203    ///
204    /// The input string is empty.
205    ///
206    Empty,
207
208    /// 
209    /// Expected key/value pair but found a key only. Holds the `Token` that failed to parse.
210    ///
211    IsKey(Token),
212
213    /// 
214    /// Expected a key but found a key/value pair.
215    ///
216    IsValue(String),
217
218    ///
219    /// Failed to parse a key path.
220    ///
221    KeyParse(String),
222
223    ///
224    /// Expected a unique key or key/value pair but could not find it.
225    ///
226    MissingToken,
227
228    ///
229    /// Expected a colon after the key. Holds the `Token` that failed to parse and the position
230    /// where a colon was expected.
231    ///
232    NoColon(Token, usize),
233
234    ///
235    /// Values should start with a double quotemark. Holds the `Token` that failed to parse and a
236    /// `usize` of the expected position of the quote.
237    ///
238    NoQuoteAfterKey(Token, usize),
239
240    ///
241    /// Values should end with a double quotemark. Holds the `Token` that failed to parse and a
242    /// `usize` of the expected position of the second quote.
243    ///
244    NoSecondQuote(Token, usize),
245
246    ///
247    /// Keys and Values should be separated by at least one space. Holds the `Token` that failed to
248    /// parse.
249    ///
250    NoSpaceAfterKey(Token),
251
252    ///
253    /// Expected one key but found many. Holds a `usize` of the number of keys.
254    ///
255    NotUnique(usize),
256
257    ///
258    /// Could not parse the string. Holds the `Token` that failed to parse.
259    ///
260    ParseValue(Token, &'static str),
261
262    ///
263    /// Keys should not contain double quotemarks. Holds the `Token` that failed to parse and a
264    /// `usize` of the position of the double quote.
265    ///
266    QuotemarkInKey(Token, usize),  // usize refers to position of quote.
267
268    ///
269    /// For use by client code.
270    ///
271    User(String),
272}
273
274impl Error for SmallError {
275}
276
277impl fmt::Display for SmallError {
278
279    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280        match self {
281            SmallError::Empty => {
282                write!(f, "The input string is empty.")
283            },
284
285            SmallError::EmptyKey(token, pos) => {
286                write!(f, "Line {}:{} Empty key.", token.line, pos)
287            },
288
289            SmallError::Indent(token, _) => {
290                write!(f, "Line {}:{} Indentation should be aligned by {} to the top key ",
291                    token.line,
292                    token.start_key.unwrap(),
293                    INDENTSTEP
294                )
295            },
296
297            SmallError::IsKey(s) => {
298                write!(f, "Expected 'key: value' but found only key \"{}\"", s)
299            },
300
301            SmallError::IsValue(s) => {
302                write!(f, "\"{}\" is a value, not a key.", s)
303            },
304
305            SmallError::ParseValue(token, to_type) => {
306                write!(f, "Line {}:{} [{}] The value could not be parsed into a {}.",
307                       token.line,
308                       token.start_val.unwrap(),
309                       token.text.trim().cyan().bold(),
310                       to_type,
311                )
312            },
313
314            SmallError::KeyParse(s) => {
315                write!(f,
316                       "\"{}\" cannot be parsed.", s)
317            },
318
319            SmallError::NoColon(token, pos) => {
320                write!(f, "Line {}: [{}] should have a colon after the key at position {}.", token.line, token.text, pos)
321            },
322
323            SmallError::NotUnique(n) => {
324                write!(f,
325                       "Resulted in {} keys, but expected 1.", n)
326            },
327
328            SmallError::NoQuoteAfterKey(token, pos) => {
329                write!(f, "Line {}:{} Value must start with double quotemark", token.line, pos)
330            },
331
332            SmallError::NoSecondQuote(token, pos) => {
333                write!(f, "Line {}:{} No second quote.", token.line, pos)
334            },
335
336            SmallError::NoSpaceAfterKey(token) => {
337                write!(f, "Line {}:{} No space after .", token.line, token.end_key.unwrap())
338            },
339
340            SmallError::MissingToken => {
341                write!(f, "Expected another token.")
342            },
343
344            SmallError::QuotemarkInKey(token, pos) => {
345                write!(f, "Line {}:{} Quote mark in key.", token.line, pos)
346            },
347
348            SmallError::User(s) => {
349                write!(f, "{}", s)
350            },        
351        }
352    }
353}
354
355// A `KeyPath` looks like "hobbit::friends::name".
356#[derive(Debug)]
357pub struct KeyPath<'a>(&'a str, Split<'a, &'a str>);
358
359impl<'a> KeyPath<'a> {
360    pub fn from_str(s: &'a str) -> Result<Self, SmallError> {
361        if s.is_empty() { return Err(SmallError::KeyParse(s.to_owned())) };
362        if s.split("::").any(|k| k.contains(":")) {
363           return Err(SmallError::KeyParse(s.to_owned()))
364        };
365        Ok(KeyPath(s, s.split("::")))
366    }
367}
368
369impl<'a> fmt::Display for KeyPath<'a> {
370    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371        write!(f, "{}", self.0)
372    }
373}
374
375impl<'a> Iterator for KeyPath<'a> {
376    type Item = &'a str;
377    fn next(&mut self) -> Option<Self::Item> {
378        self.1.next()
379    }
380}
381
382/// The `Token` struct contains implementation details of a parsed line a `Small`-formatted string.
383/// It is not really part of the API, but gets passed around by `SmallError` and as such is public.
384//
385// Parsing makes one scan of the line from left to right. Options are required in the struct for
386// when a string fails to parse. In this case partial information is used to create error feedback
387// from the earlier part of the parse even if the later part of the parse is not complete.
388//
389//     a__long_key:            "Bilbo Baggins"
390//     ^          ^            ^             ^
391//     start_key  end_key      start_val     end_val
392//
393#[derive(Clone, Debug)]
394pub struct Token {
395    text:      String,        
396    line:      usize,         
397    start_key: Option<usize>, 
398    end_key:   Option<usize>, 
399    start_val: Option<usize>, 
400    end_val:   Option<usize>, 
401}
402
403// PartialEq requires same indentation, and same key and value, but is otherwise flexible on
404// spacing.
405impl PartialEq for Token {
406    fn eq(&self, other: &Token) -> bool {
407        self.indentation() == other.indentation() &&
408        self.key() == other.key() &&
409        self.value() == other.value()
410    }
411}
412
413// Parser State
414#[derive(Debug)]
415enum PS {
416    BK,       // Before key.
417    IK,       // In key.
418    RAK,      // Right after key.
419    AK,       // After key.
420    IV,       // In value.
421    AV,       // After value.
422}
423
424impl Token {
425
426    // Its worth having this constructor as it reduces verbosity in the Token::from_str() parsing
427    // function.
428    fn new(
429        text:       &str,
430        line:       usize,
431        start_key:  Option<usize>,
432        end_key:    Option<usize>,
433        start_val:  Option<usize>,
434        end_val:    Option<usize>) -> Self {
435
436        Token {
437            text:       text.to_string(),
438            line:       line,
439            start_key:  start_key,
440            end_key:    end_key,
441            start_val:  start_val,
442            end_val:    end_val,
443        }
444    }
445
446    fn indent(&mut self) {
447        self.text = format!("    {}", self.text);
448        self.start_key = self.start_key.map(|sk| sk + INDENTSTEP);
449        self.end_key   = self.end_key.map(|ek| ek + INDENTSTEP);
450        self.start_val = self.start_val.map(|sv| sv + INDENTSTEP);
451        self.end_val   = self.end_val.map(|ev| ev + INDENTSTEP);
452    }
453
454    // Parses a line of text and return a Token. Iterate over the characters, one at a time. The
455    // parse state (enum PS) changes as we go through the string. This function trims the string.
456    // String::from_str() is responsible for trimming whitespace.
457    fn from_str(s: &str, line: usize, root_indent: usize) -> Result<Self, SmallError> {
458        let mut ps = PS::BK;
459        let mut escape = false;
460        let mut start_key:   Option<usize> = None;
461        let mut end_key:     Option<usize> = None;
462        let mut start_val:   Option<usize> = None;
463        let mut end_val:     Option<usize> = None;
464
465        for (pos, c) in s.char_indices() {
466
467            // Before key.
468            if let PS::BK = ps {
469                if c == ':' {
470                    start_key = Some(pos);
471                    let token = Token::new(s, line, start_key, end_key, start_val, end_val);
472                    return Err(SmallError::EmptyKey(token, pos));
473                };
474                if !c.is_whitespace() {
475                    start_key = Some(pos);
476                    if (pos - root_indent) % INDENTSTEP != 0 {
477                        let token = Token::new(s, line, start_key, end_key, start_val, end_val);
478                        return Err(SmallError::Indent(token, root_indent));
479                    };
480                    ps = PS::IK;
481                };
482                continue; // Next char.
483            };
484
485            // In key.
486            if let PS::IK = ps {
487                if c == '"' {
488                    let token = Token::new(s, line, start_key, end_key, start_val, end_val);
489                    return Err(SmallError::QuotemarkInKey(token, pos));
490                };
491                if c.is_whitespace() {
492                    let token = Token::new(s, line, start_key, end_key, start_val, end_val);
493                    return Err(SmallError::NoColon(token, pos));
494                };
495                if c == ':' {
496                    if Some(pos) == start_key {
497                        let token = Token::new(s, line, start_key, end_key, start_val, end_val);
498                        return Err(SmallError::EmptyKey(token, pos))
499                    } else {
500                        end_key = Some(pos);
501                        ps = PS::RAK;
502                        continue;
503                    };
504                };
505            };
506
507            // Right after key.
508            if let PS::RAK = ps {
509                if !c.is_whitespace() {
510                    let token = Token::new(s, line, start_key, end_key, start_val, end_val);
511                    return Err(SmallError::NoSpaceAfterKey(token))
512                } else {
513                    ps = PS::AK;
514                    continue;
515                }
516            };
517
518            // After key.
519            if let PS::AK = ps {
520                if c.is_whitespace() {
521                    continue;
522                } else {
523                    if c != '"' {
524                        let token = Token::new(s, line, start_key, end_key, start_val, end_val);
525                        return Err(SmallError::NoQuoteAfterKey(token, pos))
526                    } else {
527                        start_val = Some(pos);
528                        ps = PS::IV;
529                        continue;
530                    }
531                }
532            };
533
534            // In value.
535            if let PS::IV = ps {
536                if c == '\\' {
537                    escape = true;
538                } else if c == '"' && escape {
539                        continue;
540                } else if c == '"' {
541                    ps = PS::AV;
542                    end_val = Some(pos);
543                } else {
544                    escape = false;
545                    continue;
546                }
547            };
548
549            // After value.
550            if let PS::AV = ps { break };
551        };
552
553        let token = Token::new(s, line, start_key, end_key, start_val, end_val);
554
555        match ps {
556            PS::BK  => { 
557                panic!("Shouldn't fail here")
558            },
559            PS::IK  => { Err(SmallError::NoColon(token, s.char_indices().count())) },
560            PS::RAK => { Ok(token) },
561            PS::AK  => { Ok(token) },
562            PS::IV  => { return Err(SmallError::NoSecondQuote(token, s.char_indices().count())) },
563            PS::AV  => { Ok(token) },
564        }
565    }
566
567    fn key(&self) -> String {
568        self.text[self.start_key.unwrap()..=self.end_key.unwrap() - 1].to_string()
569    }
570
571    // This function shouldn't fail, as indentation should be checked during parsing.
572    fn indentation(&self) -> usize {
573        self.start_key.expect("Bug: start_key was None but should always be Some.")
574    }
575
576    fn line(&self) -> usize {
577        self.line
578    }
579
580    fn is_value(&self) -> bool {
581        if let (Some(_), Some(_), Some(_), Some(_)) = 
582            (self.start_key, self.end_key, self.start_val, self.end_val) {
583                true
584            } else {
585                false
586            }
587    }
588
589    pub fn value(&self) -> Result<String, SmallError> {
590        if self.is_value() {
591            Ok(self.text[self.start_val.unwrap() + 1..=self.end_val.unwrap() - 1].to_string())
592        } else {
593            Err(SmallError::IsKey(self.clone()))
594        }
595    }
596}
597
598impl Display for Token {
599    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
600        write!(f, "{}", self.text)
601    }
602}
603
604/// `SmallString` represents a string in `Small` data format.
605#[derive(Debug)]
606pub struct SmallString(Vec<Token>);
607
608fn empty_line(line: &str) -> bool {
609    line.starts_with("//") ||
610    !line.chars().any(|c| !c.is_whitespace())
611}
612
613impl SmallString {
614    
615    // Create a `SmallString` structure from a string.
616    pub fn from_str(s: &str) -> Result<Self, SmallError> {
617
618        let mut v                 = Vec::new();
619        let mut before_start_line = true;
620        let mut root_indent       = 0;
621        let mut line_num          = 0;
622
623        for ln in s.lines() {
624            if empty_line(ln) { continue };
625            
626            // First line.
627            if before_start_line == true {
628                root_indent = ln.chars().position(|c| !c.is_whitespace()).unwrap();
629                before_start_line = false;
630            };
631            v.push(Token::from_str(ln, line_num, root_indent)?);
632            line_num += 1;
633        };
634        if v.is_empty() { Err(SmallError::Empty) } else { Ok(SmallString(v)) }
635    }
636
637    fn indent(&mut self) {
638        for token in self.0.iter_mut() {
639            token.indent();
640        }
641    }
642
643    /// Converts `self` into a `Small`. 
644    pub fn to_ref(&self) -> Small {
645        Small {
646            small:      self,
647            reduction:  vec!(&self.0[..]),
648        }
649    }
650
651    // Calculate the position of the value column to vertically align keys.
652    fn max_key_end(&self) -> (usize, usize) {
653        let root_indent = self.0[0].indentation();
654        let max_end_key = self.0.iter().map(|token| token.end_key.unwrap()).max().unwrap();
655        (root_indent, max_end_key - root_indent)
656    }
657}
658
659impl Index<usize> for SmallString {
660    type Output = Token;
661
662    fn index(&self, i: usize) -> &Token {
663        &self.0[i]
664    }
665}
666
667impl fmt::Display for SmallString {
668    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
669        let (root_indent, max_key_end) = self.max_key_end();
670        let mut s = String::new();
671
672        // Vertically align the values.
673        for token in self.0.iter() {
674            let val_shift: Option<i32> = match token.start_val {
675                Some(sv) => Some((max_key_end + 1) as i32 - sv as i32),
676                None     => None,
677            };
678            let (start_val, end_val) = match (token.start_val, token.end_val, val_shift) {
679                (Some(sv), Some(ev), Some(vs)) => {
680                    (Some((sv as i32 + vs as i32) as usize), Some((ev as i32 + vs as i32) as usize))
681                },
682                _ => {
683                    (None, None)
684                },
685            };
686            let new_token = Token {
687                text:       token.text.clone(),
688                line:       token.line,
689                start_key:  Some(token.start_key.unwrap() - root_indent),
690                end_key:    Some(token.end_key.unwrap() - root_indent),
691                start_val:  start_val,
692                end_val:    end_val,
693            };
694            s.push_str(&format!("{}\n", new_token.to_string()));
695        };
696        s.pop();
697        write!(f, "{}", s)
698    }
699}
700
701/// `Small` is a selection of `SmallString`. Its function is to encapsulate path selections. See the
702/// `path()` function implemented by the `FromSmall` trait.
703#[derive(Clone, Debug)]
704pub struct Small<'a> {
705    pub small:     &'a SmallString,
706
707    // reduction holds a vec of slices into small.
708    //
709    //  name:         "Frodo Baggins"
710    //  age:          "98"
711    //  friends:
712    //      hobbit:                     <----          
713    //          name: "Bilbo Baggins"        slice1 <-- vec[0]
714    //          age:  "176"             <----
715    //      hobbit:                     <----
716    //          name: "Samwise Gamgee"       slice2 <-- vec[1]
717    //          age:  "66""#;           <----           
718    //
719    reduction:  Vec<&'a [Token]>,
720}
721
722impl<'a> Small<'a> {
723
724    fn tokens(&self) -> Vec<String> {
725        let mut v = Vec::new();
726
727        for key_set in self.reduction.iter() {
728            for token in key_set.iter() {
729                v.push(token.to_string())
730            }
731        }
732        v
733    }
734
735    // Applies a key to Small, returning a subset of Self. If the key cannot be found, the
736    // result will be empty. Iterates through Small once. 
737    fn apply_key(self, key: &str) -> Result<Small<'a>, SmallError> {
738        let mut reduction: Vec<&[Token]> = Vec::new();
739
740        for &slice in self.reduction.iter() {
741            let root_indent = slice[0].indentation();
742            let mut i = 0usize;
743            'outer: loop {
744                if slice[i].key() == key && (slice[i].indentation() - root_indent) / INDENTSTEP == 1 {
745                    let start_index = i;
746                    'inner: loop {
747
748                        // Process the case where the slice is not the last token and the next
749                        // token is a different key.
750                        if (i < slice.len() - 1) &&
751                           ((slice[i + 1].indentation() - root_indent) / INDENTSTEP <= 1) {
752                            let end_index = i;
753                            reduction.push(&slice[start_index..=end_index]);
754                            break 'inner;
755                        }
756
757                        // Process the case where the slice in the last token.
758                        if i == slice.len() - 1 {
759                            let end_index = i;
760                            reduction.push(&slice[start_index..=end_index]);
761                            break 'outer;
762                        };
763
764                        i += 1
765                    }
766                };
767                i += 1;
768                if i == slice.len() { break 'outer };
769            };
770        };
771        Ok(Small {
772            small:      self.small,
773            reduction:  reduction, 
774        })
775    }
776
777    // Applies a path of keys to Small, returning a subset of Self. If the key cannot be found,
778    // the result will be empty.
779    fn apply_path(&self, s: &str) -> Result<Small, SmallError> {
780        let mut reduction = self.clone();
781        for (i, key) in KeyPath::from_str(s)?.enumerate() {
782            if i > 0 {
783                reduction = reduction.apply_key(&key.to_string())?;
784            };
785        }
786        Ok(reduction)
787    }
788}
789
790impl<'a> Display for Small<'a> {
791    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
792        let mut s = String::new();
793        s.push_str("reductions:\n");
794        for slice in self.reduction.iter() {
795            s.push_str("[\n");
796            for token in slice.iter() {
797                s.push_str(&token.to_string());
798                s.push('\n');
799            }
800            s.push_str("]\n");
801        }
802        s.pop();
803        write!(f, "{}", s)
804    }
805}
806
807impl<'a> Small<'a> {
808    /// Checks that there is only one value in `Small` and returns it.
809    pub fn unique_value(&self) -> Result<Token, SmallError> {
810        if  self.reduction.is_empty() { return Err(SmallError::MissingToken) };
811        if self.reduction.len() > 1 { return Err(SmallError::NotUnique(self.reduction.len())) };
812        let token = &self.reduction[0][0];
813        if token.is_value() { Ok(token.clone()) } else { Err(SmallError::IsKey(token.clone())) }
814    }
815}
816
817/// Types that implement the `FromSmall` trait can be constructed from a `Small`-formatted string.
818pub trait FromSmall {
819
820    /// The `from_small()` function describes how to create a data-structure from the parts of
821    /// `Small`. See example 1 for canonical usage.
822    fn from_small(slice: &Small) -> Result<Self, SmallError>
823        where Self: std::marker::Sized;
824
825    /// Reduces `Small` to the `key_path` and then uses the `FromSmall` trait to convert to the
826    /// receiver type.
827    fn path(small: &Small, key_path: &str) -> Result<Self, SmallError>
828    where
829        Self: std::marker::Sized
830    {
831        Ok(Self::from_small(&small.apply_path(key_path)?)?)
832    }
833
834    /// Top level function that converts a `Small`-formatted string into the receiver.
835    fn from_str(s: &str) -> Result<Self, SmallError>
836        where Self: std::marker::Sized
837    {
838        let small = SmallString::from_str(s)?;
839        let small = Small {
840            small: &small,
841            reduction: vec!(&small.0[..]),
842        };
843        Ok(Self::from_small(&small)?)
844    }
845
846    /// Top level function that converts a `SmallString`-formatted string into the receiver giving
847    /// helpful error messages for debugging.
848    fn from_str_debug(s: &str) -> Self
849        where Self: std::marker::Sized
850    {
851        match Self::from_str(s) {
852            Ok(s) => s,
853            Err(e) => {
854                match e {
855
856                    SmallError::Empty => {
857                        eprintln!("The input data string is empty.");
858                    }
859
860                    SmallError::EmptyKey(token, pos) => {
861                        let info = &format!(
862                            "{}{} {}",
863                            " ".repeat(pos),
864                            "^".yellow().bold(),
865                            "missing key".yellow().bold(),
866                        );
867                        in_context(s, info, token.line);
868                    },
869
870                    SmallError::Indent(token, _) => {
871
872                        let info = &format!(
873                            "{}{}{}{} {} {} {}",
874                            " ".repeat(token.start_key.unwrap() - 4 - (token.start_key.unwrap() % 4)),
875                            "|".yellow().bold(),
876                            "_".repeat(3).yellow().bold(),
877                            "|".yellow().bold(),
878                            "indent".yellow().bold(),
879                            INDENTSTEP.to_string().yellow().bold(),
880                            "spaces only".yellow().bold()
881                        );
882                        in_context(s, info, token.line);
883                    },
884
885                    SmallError::NoColon(token, pos) => {
886                        let info = &format!(
887                            "{}{} {}",
888                            " ".repeat(token.start_key.unwrap()),
889                            "^".repeat(pos - token.start_key.unwrap()).yellow().bold(),
890                            "key requires colon".yellow().bold()
891                        );
892                        in_context(s, info, token.line);
893                    },
894
895                    SmallError::NoSecondQuote(token, pos) => {
896                        let info = &format!(
897                            "{}{} {}",
898                            " ".repeat(pos),
899                            "^".yellow().bold(),
900                            "missing second quotemark".yellow().bold(),
901                        );
902                        in_context(s, info, token.line);
903                    }
904
905                    SmallError::NoSpaceAfterKey(token) => {
906                        let info = &format!(
907                            "{}{}{} {}",
908                            " ".repeat(token.start_key.unwrap()),
909                            " ".repeat(token.end_key.unwrap() + 1 - token.start_key.unwrap()),
910                            "^".yellow().bold(),
911                            "requires at least one space after key".yellow().bold()
912                        );
913                        in_context(s, info, token.line);
914                    },
915
916                    SmallError::ParseValue(token, to_type) => {
917                        let info = &format!(
918                               "{}{} {}",
919                               " ".repeat(token.start_val.unwrap() + 1),
920                               "^".repeat(token.value().unwrap().char_indices().count()).yellow().bold(),
921                               format!("number could not be parsed into a {}", to_type).yellow().bold(), 
922                        );
923                        in_context(s, info, token.line);
924                    },
925
926                    SmallError::QuotemarkInKey(token, pos) => {
927                        let info = &format!(
928                            "{}{} {}",
929                            " ".repeat(pos),
930                            "^".yellow().bold(),
931                            "no double quotes allowed in key".yellow().bold(),
932                        );
933                        in_context(s, info, token.line);
934                    }
935
936                    _ => eprintln!("{}", e.to_string()),
937                };
938                exit(1);
939            },
940        }
941    }
942}
943
944fn in_context(s: &str, info: &str, line: usize) {
945    for (i, ln) in s.lines().take(20).enumerate() {
946        eprintln!("{}", ln);
947        if i == line {
948            eprintln!("{}", info);
949        };
950    };
951}
952
953impl FromSmall for String {
954    fn from_small(small: &Small) -> Result<Self, SmallError> {
955        small.unique_value()?.value()
956    }
957}
958
959impl FromSmall for u8 {
960    fn from_small(small: &Small) -> Result<Self, SmallError> {
961        let token = small.unique_value()?;
962        token
963            .value()?
964            .parse::<u8>()
965            .map_err(|_| SmallError::ParseValue(token, "u8"))
966    }
967}
968
969impl FromSmall for i8 {
970    fn from_small(small: &Small) -> Result<Self, SmallError> {
971        let token = small.unique_value()?;
972        token
973            .value()?
974            .parse::<i8>()
975            .map_err(|_| SmallError::ParseValue(token, "i8"))
976    }
977}
978
979impl FromSmall for u16 {
980    fn from_small(small: &Small) -> Result<Self, SmallError> {
981        let token = small.unique_value()?;
982        token
983            .value()?
984            .parse::<u16>()
985            .map_err(|_| SmallError::ParseValue(token, "u16"))
986    }
987}
988
989impl FromSmall for i16 {
990    fn from_small(small: &Small) -> Result<Self, SmallError> {
991        let token = small.unique_value()?;
992        token
993            .value()?
994            .parse::<i16>()
995            .map_err(|_| SmallError::ParseValue(token, "i16"))
996    }
997}
998
999impl FromSmall for u32 {
1000    fn from_small(small: &Small) -> Result<Self, SmallError> {
1001        let token = small.unique_value()?;
1002        token
1003            .value()?
1004            .parse::<u32>()
1005            .map_err(|_| SmallError::ParseValue(token, "u32"))
1006    }
1007}
1008
1009impl FromSmall for i32 {
1010    fn from_small(small: &Small) -> Result<Self, SmallError> {
1011        let token = small.unique_value()?;
1012        token
1013            .value()?
1014            .parse::<i32>()
1015            .map_err(|_| SmallError::ParseValue(token, "i32"))
1016    }
1017}
1018
1019impl FromSmall for u64 {
1020    fn from_small(small: &Small) -> Result<Self, SmallError> {
1021        let token = small.unique_value()?;
1022        token
1023            .value()?
1024            .parse::<u64>()
1025            .map_err(|_| SmallError::ParseValue(token, "u64"))
1026    }
1027}
1028
1029impl FromSmall for i64 {
1030    fn from_small(small: &Small) -> Result<Self, SmallError> {
1031        let token = small.unique_value()?;
1032        token
1033            .value()?
1034            .parse::<i64>()
1035            .map_err(|_| SmallError::ParseValue(token, "i64"))
1036    }
1037}
1038
1039impl FromSmall for u128 {
1040    fn from_small(small: &Small) -> Result<Self, SmallError> {
1041        let token = small.unique_value()?;
1042        token
1043            .value()?
1044            .parse::<u128>()
1045            .map_err(|_| SmallError::ParseValue(token, "u128"))
1046    }
1047}
1048
1049impl FromSmall for i128 {
1050    fn from_small(small: &Small) -> Result<Self, SmallError> {
1051        let token = small.unique_value()?;
1052        token
1053            .value()?
1054            .parse::<i128>()
1055            .map_err(|_| SmallError::ParseValue(token, "i128"))
1056    }
1057}
1058
1059impl FromSmall for usize {
1060    fn from_small(small: &Small) -> Result<Self, SmallError> {
1061        let token = small.unique_value()?;
1062        token.
1063            value()?
1064            .parse::<usize>()
1065            .map_err(|_| SmallError::ParseValue(token, "usize"))
1066    }
1067}
1068
1069impl FromSmall for isize {
1070    fn from_small(small: &Small) -> Result<Self, SmallError> {
1071        let token = small.unique_value()?;
1072        token.
1073            value()?
1074            .parse::<isize>()
1075            .map_err(|_| SmallError::ParseValue(token, "isize"))
1076    }
1077}
1078
1079impl FromSmall for f32 {
1080    fn from_small(small: &Small) -> Result<Self, SmallError> {
1081        let token = small.unique_value()?;
1082        token
1083            .value()?
1084            .parse::<f32>()
1085            .map_err(|_| SmallError::ParseValue(token, "f32"))
1086    }
1087}
1088
1089impl FromSmall for f64 {
1090    fn from_small(small: &Small) -> Result<Self, SmallError> {
1091        let token = small.unique_value()?;
1092        token
1093            .value()?
1094            .parse::<f64>()
1095            .map_err(|_| SmallError::ParseValue(token, "f64"))
1096    }
1097}
1098
1099impl FromSmall for bool {
1100    fn from_small(small: &Small) -> Result<Self, SmallError> {
1101        let token = small.unique_value()?;
1102        if "false" == &token.value()? {
1103            return Ok(false)
1104        };
1105        if "true" == &token.value()? {
1106            return Ok(true)
1107        };
1108        Err(SmallError::ParseValue(token, "bool"))
1109    }
1110}
1111
1112/// Converts a `Vec` with either one or no `Small` elements to an `Option<T>`. See Example 1 for
1113/// details.
1114impl<T> FromSmall for Option<T>
1115where
1116    T: FromSmall
1117{
1118    fn from_small(small: &Small) -> Result<Self, SmallError> {
1119        if small.reduction.is_empty() {
1120            return Ok(None)
1121        } else {
1122            Ok(Some(T::from_small(small)?))
1123        }
1124    }
1125}
1126
1127impl<T>FromSmall for Vec<T>
1128where
1129    T: FromSmall
1130{
1131    fn from_small(s: &Small) -> Result<Self, SmallError> {
1132        let mut v: Vec<T> = Vec::new();
1133        for &slice in s.reduction.iter() {
1134            let dat = Small {
1135                small: s.small,
1136                reduction: vec!(slice),
1137            };
1138            v.push(T::from_small(&dat)?);
1139        };
1140        Ok(v)
1141    }
1142}