json_config/
lib.rs

1extern crate serde_json;
2
3mod macros;
4
5use std::io::Read;
6use std::collections::HashMap;
7use std::{env};
8use std::path::Path;
9use std::io::{Write, BufWriter};
10use std::fs::File;
11
12use serde_json::Value;
13use serde_json::from_str;
14use serde_json::to_string_pretty;
15
16#[derive(Clone)]
17pub enum ConfigurationSource {
18    StringContent(String),
19    FileContent(String),
20    JsonContent(Value)
21}
22
23pub enum ConfigurationDefinitionParams{
24    Source(ConfigurationSource),
25    Bundle(String, Vec<ConfigurationSource>)
26}
27
28pub struct ConfigurationBuilder {
29    config: Value,
30    bundles: HashMap<String, Vec<ConfigurationSource>>    
31}
32
33impl<'a> ConfigurationBuilder{
34
35    pub fn new(base_source: ConfigurationSource) -> ConfigurationBuilder{
36        let base_config: Value = from_str("{}").unwrap();
37        
38        let mut config_builder = ConfigurationBuilder{
39            config: base_config,
40            bundles: HashMap::new()
41        };
42
43        config_builder.merge_source(&base_source);
44
45        return config_builder;
46    }
47    
48    pub fn from_definition(definition: Vec<ConfigurationDefinitionParams>) -> ConfigurationBuilder{
49        let mut builder = ConfigurationBuilder::new(ConfigurationSource::StringContent(String::from("{}")));
50
51        for def_param in definition{
52            match def_param{
53                ConfigurationDefinitionParams::Source(source) => builder.merge_source(&source),
54                ConfigurationDefinitionParams::Bundle(bundle_key, sources) => builder.define_bundle(bundle_key, sources)
55            }
56        }
57
58        return builder;
59    }
60
61    pub fn merge_sources(&mut self, config_sources: &Vec<ConfigurationSource>){        
62        for source in config_sources{
63            self.merge_source(&source);
64        }
65    }
66
67    pub fn merge_source(&mut self, config_source: &ConfigurationSource){            
68        match config_source {
69            &ConfigurationSource::JsonContent(ref config_override) => {                
70                merge(&mut self.config, &config_override);
71            },
72            &ConfigurationSource::StringContent(ref content) => {                
73                let config_override: Value = from_str(&content[..]).unwrap();
74                merge(&mut self.config, &config_override);
75            },
76            &ConfigurationSource::FileContent(ref path) => {
77                let mut config_file = File::open(path).unwrap();
78                let mut config_file_content = String::new();
79                config_file.read_to_string(&mut config_file_content).unwrap();
80                
81                let config_override: Value = from_str(&config_file_content[..]).unwrap();
82                merge(&mut self.config, &config_override);
83            }
84        }      
85    }
86
87    pub fn define_bundle(&mut self, bundle_key: String, sources: Vec<ConfigurationSource>){
88        self.bundles.insert(bundle_key, sources);
89    }
90
91    pub fn merge_bundle(&mut self, bundle_key: &str){
92        let sources = self.bundles.get(bundle_key).unwrap().clone();
93        self.merge_sources(&sources);
94    }
95
96    pub fn to_compiled(&mut self, filename: &str){
97        let out_dir = env::var("OUT_DIR").unwrap();
98        let dest_path = Path::new(&out_dir).join(filename);
99        let mut f = BufWriter::new(File::create(&dest_path).unwrap());
100
101        write!(f, "{}", self.config.to_string().as_str()).unwrap();
102    }
103
104    pub fn to_string(&self) -> String{
105        return self.config.to_string();
106    }
107
108    pub fn to_string_pretty(&self) -> String{
109        return to_string_pretty(&self.config).unwrap();
110    }
111
112    pub fn to_enum(&self) -> Value{
113        return self.config.clone();
114    }
115}
116
117fn merge(a: &mut Value, b: &Value) {
118    match (a, b) {
119        (&mut Value::Object(ref mut a), &Value::Object(ref b)) => {
120            for (k, v) in b {
121                merge(a.entry(k.clone()).or_insert(Value::Null), v);
122            }
123        }
124        (a, b) => {
125            *a = b.clone();
126        }
127    }
128}
129
130// fn merge(a: &mut Value, b: &Value) {
131//     match (a, b) {
132//         (&mut Value::Object(ref mut a), &Value::Object(ref b)) => {
133//             for (k, v) in b {
134//                 merge(a.entry(k.clone()).or_insert(Value::Null), v);
135//             }
136//         }
137//         (a, b) => {
138//             *a = b.clone();
139//         }
140//     }
141// }
142
143#[cfg(test)]
144mod tests {
145    #[test]
146    fn it_works() {
147        assert_eq!(2 + 2, 4);
148    }
149}