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#[cfg(test)]
144mod tests {
145 #[test]
146 fn it_works() {
147 assert_eq!(2 + 2, 4);
148 }
149}