1use std::fmt;
2use std::error::Error as StdError;
3use std::borrow::Cow;
4use std::fs::File;
5use std::io;
6use std::io::prelude::Read;
7use std::ops::Index;
8
9use ::yaml::YamlLoader;
10use ::yaml::Yaml;
11use ::yaml::scanner::ScanError;
12use ::yaml::emitter::EmitError;
13
14#[derive(Debug)]
17pub enum ConfigError {
18 IoError(io::Error),
20 MissingComponent(String),
22 YamlSyntax(ScanError),
24 YamlEmit(EmitError),
26 Error(Box<StdError>),
28}
29
30impl fmt::Display for ConfigError {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 match *self {
33 ConfigError::IoError(ref err) => write!(f, "ConfigError: {}", err),
34 ConfigError::MissingComponent(ref comp) => write!(f, "ConfigError: Missing {}", comp),
35 ConfigError::YamlSyntax(ref err) => write!(f, "ConfigError: {}", err),
36 ConfigError::YamlEmit(ref err) => write!(f, "ConfigError: {:?}", err),
37 ConfigError::Error(ref err) => write!(f, "ConfigError: {:?}", err),
38 }
39 }
40}
41
42impl StdError for ConfigError {
43 fn description(&self) -> &str {
44 match *self {
45 ConfigError::IoError(ref err) => err.description(),
46 ConfigError::MissingComponent(_) => "Missing Required Component",
47 ConfigError::YamlSyntax(ref err) => err.description(),
48 ConfigError::YamlEmit(_) => "Problem emitting Yaml",
49 ConfigError::Error(ref err) => err.description(),
50 }
51 }
52
53 fn cause(&self) -> Option<&StdError> {
54 match *self {
55 ConfigError::IoError(ref err) => Some(err),
56 ConfigError::MissingComponent(_) => None,
57 ConfigError::YamlSyntax(ref err) => Some(err),
58 ConfigError::YamlEmit(_) => None,
59 ConfigError::Error(_) => None,
60 }
61 }
62}
63
64impl From<io::Error> for ConfigError {
65 fn from(err: io::Error) -> ConfigError {
66 ConfigError::IoError(err)
67 }
68}
69
70impl From<ScanError> for ConfigError {
71 fn from(err: ScanError) -> ConfigError {
72 ConfigError::YamlSyntax(err)
73 }
74}
75
76impl From<EmitError> for ConfigError {
77 fn from(err: EmitError) -> ConfigError {
78 ConfigError::YamlEmit(err)
79 }
80}
81
82impl From<Box<StdError>> for ConfigError {
83 fn from(err: Box<StdError>) -> ConfigError {
84 ConfigError::Error(err)
85 }
86}
87
88#[derive(Debug, Clone)]
90pub struct ConfigFile {
91 yaml: Yaml,
92}
93
94impl ConfigFile {
95 pub fn open<'a>(name: Cow<'a, str>) -> Result<Self, ConfigError> {
97 let mut config_file = File::open(name.as_ref())?;
98 let mut config_str = String::new();
99 config_file.read_to_string(&mut config_str).expect("Error reading config file");
100 let yamls = YamlLoader::load_from_str(&config_str)?;
101 let yaml: Yaml = yamls[0].clone();
102 Ok(ConfigFile {
103 yaml: yaml
104 })
105 }
106}
107
108static BAD_VALUE: Yaml = Yaml::BadValue;
109
110impl<'a> Index<&'a str> for ConfigFile {
112 type Output = Yaml;
113
114 fn index(&self, idx: &'a str) -> &Yaml {
115 let key = Yaml::String(idx.to_owned());
116 match self.yaml.as_hash() {
117 Some(h) => h.get(&key).unwrap_or(&BAD_VALUE),
118 None => &BAD_VALUE
119 }
120 }
121}
122
123impl Index<usize> for ConfigFile {
125 type Output = Yaml;
126
127 fn index(&self, idx: usize) -> &Yaml {
128 if let Some(v) = self.yaml.as_vec() {
129 v.get(idx).unwrap_or(&BAD_VALUE)
130 } else if let Some(v) = self.yaml.as_hash() {
131 let key = Yaml::Integer(idx as i64);
132 v.get(&key).unwrap_or(&BAD_VALUE)
133 } else {
134 &BAD_VALUE
135 }
136 }
137}