pyc_shell/config/
configparser.rs

1//! ### configparser
2//!
3//! `configparser` is the module which provides some functions to facilitate the parsing of a YAML
4
5/*
6*
7*   Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
8*
9* 	This file is part of "Pyc"
10*
11*   Pyc is free software: you can redistribute it and/or modify
12*   it under the terms of the GNU General Public License as published by
13*   the Free Software Foundation, either version 3 of the License, or
14*   (at your option) any later version.
15*
16*   Pyc is distributed in the hope that it will be useful,
17*   but WITHOUT ANY WARRANTY; without even the implied warranty of
18*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19*   GNU General Public License for more details.
20*
21*   You should have received a copy of the GNU General Public License
22*   along with Pyc.  If not, see <http://www.gnu.org/licenses/>.
23*
24*/
25
26extern crate yaml_rust;
27
28use super::{ConfigError, ConfigErrorCode};
29use yaml_rust::Yaml;
30
31/// ### Config Parser
32pub struct ConfigParser {}
33
34impl ConfigParser {
35    /// ### get_child
36    ///
37    /// Get child from YAML
38    pub fn get_child(yaml_doc: &Yaml, child: String) -> Result<&Yaml, ConfigError> {
39        match yaml_doc[child.as_str()].is_badvalue() {
40            true => Err(ConfigError {
41                code: ConfigErrorCode::YamlSyntaxError,
42                message: String::from(format!("Missing key '{}'", child)),
43            }),
44            false => Ok(&yaml_doc[child.as_str()]),
45        }
46    }
47
48    /// ### get_bool
49    ///
50    /// get YAML value as bool
51    pub fn get_bool(yaml_doc: &Yaml, key: String) -> Result<bool, ConfigError> {
52        match ConfigParser::get_child(&yaml_doc, key.clone()) {
53            Ok(child) => match child.as_bool() {
54                Some(v) => Ok(v),
55                None => Err(ConfigError {
56                    code: ConfigErrorCode::YamlSyntaxError,
57                    message: String::from(format!("'{}' is not a bool", key)),
58                }),
59            },
60            Err(err) => Err(err),
61        }
62    }
63
64    /// ### get_usize
65    ///
66    /// get YAML value as usize
67    pub fn get_usize(yaml_doc: &Yaml, key: String) -> Result<usize, ConfigError> {
68        match ConfigParser::get_child(&yaml_doc, key.clone()) {
69            Ok(child) => match child.as_i64() {
70                Some(v) => Ok(v as usize),
71                None => Err(ConfigError {
72                    code: ConfigErrorCode::YamlSyntaxError,
73                    message: String::from(format!("'{}' is not a number", key)),
74                }),
75            },
76            Err(err) => Err(err),
77        }
78    }
79
80    /// ### get_string
81    ///
82    /// get YAML value as string
83    pub fn get_string(yaml_doc: &Yaml, key: String) -> Result<String, ConfigError> {
84        match ConfigParser::get_child(&yaml_doc, key.clone()) {
85            Ok(child) => match child.as_str() {
86                Some(s) => Ok(String::from(s)),
87                None => Err(ConfigError {
88                    code: ConfigErrorCode::YamlSyntaxError,
89                    message: String::from(format!("'{}' is not a string", key)),
90                }),
91            },
92            Err(err) => Err(err),
93        }
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use yaml_rust::{Yaml, YamlLoader};
101    
102    #[test]
103    fn test_configparser_yaml_parser() {
104        let yaml_doc: Yaml = gen_sample_yaml();
105        let sample_doc: &Yaml = ConfigParser::get_child(&yaml_doc, String::from("sample")).ok().unwrap();
106        //Test usize
107        assert_eq!(ConfigParser::get_usize(&sample_doc, String::from("usize")).ok().unwrap(), 2048);
108        //Test bool
109        assert_eq!(ConfigParser::get_bool(&sample_doc, String::from("bool")).ok().unwrap(), true);
110        //Test string
111        assert_eq!(ConfigParser::get_string(&sample_doc, String::from("str")).ok().unwrap(), String::from("foobar"));
112        //Test child
113        assert!(ConfigParser::get_child(&sample_doc, String::from("array")).is_ok());
114        assert!(ConfigParser::get_child(&sample_doc, String::from("map")).is_ok());
115    }
116
117    #[test]
118    fn test_configparser_yaml_bad_values() {
119        let yaml_doc: Yaml = gen_sample_yaml();
120        let sample_doc: &Yaml = ConfigParser::get_child(&yaml_doc, String::from("sample")).ok().unwrap();
121        assert!(ConfigParser::get_bool(&sample_doc, String::from("str")).is_err());
122        assert!(ConfigParser::get_usize(&sample_doc, String::from("str")).is_err());
123        assert!(ConfigParser::get_string(&sample_doc, String::from("array")).is_err());
124        assert!(ConfigParser::get_child(&sample_doc, String::from("foobar")).is_err());
125    }
126
127    fn gen_sample_yaml() -> Yaml {
128        let sample: String = String::from("sample:\n  usize: 2048\n  bool: true\n  str: \"foobar\"\n  array:\n    - 1\n    - 2\n    - 3\n  map:\n    foo: true\n    bar: \"pluto\"\n");
129        println!("{}", sample.clone());
130        match YamlLoader::load_from_str(sample.as_str()) {
131            Ok(mut doc) => doc.pop().unwrap(),
132            Err(_) => {
133                panic!("Could not parse YAML");
134            }
135        }
136    }
137}