1extern crate self as struct_to_config;
2
3use config::{ConfigBuilder, Source, ValueKind};
4use config::builder::DefaultState;
5use lazy_static::lazy_static;
6use serde_json::{Value};
7#[cfg(test)]
8mod tests;
9
10
11const COULD_NOT_SET_ITEM : &'static str = "Could not set default for key/value pair on config_builder.";
12const NOT_SUPPORTED_TYPE : &'static str = "Serialized object was not one of supported types.";
13
14
15enum Kind {
16 String, Float, Boolean, Object, Nil
17}
18
19lazy_static! {
20 static ref DEFAULT_VEC : Vec<Value> = Vec::<Value>::new();
21}
22fn get_value_kind_from_value(val: &Value, should_panic: bool) -> (ValueKind, Kind) {
23 match val {
24 Value::Null => {
25 (ValueKind::Nil, Kind::Nil)
26 }
27 Value::String(f ) => {
28 (ValueKind::String(f.to_string()), Kind::String)
29 },
30 Value::Number(f ) => {
31 (ValueKind::Float(f.as_f64().unwrap()), Kind::Float)
32 },
33 Value::Bool(f ) => {
34 (ValueKind::Boolean(*f), Kind::Boolean)
35 },
36 Value::Object(o) => {
37 let values : Vec<ValueKind> = o.iter().map(|i| {
38 return get_value_kind_from_value(i.1, should_panic).0.clone();
39 }).collect();
40 let val_kind = config::ValueKind::from(values);
41 (val_kind, Kind::Object)
42 },
43 _ => {
44 if should_panic {
45 panic!("Found a value in array that is not a String, Number, Struct, or Bool");
46 } else {
47 (ValueKind::Nil, Kind::Nil)
48 }
49 }
50 }
51}
52pub fn convert_panic(value : &Value, cfg_builder: Option<ConfigBuilder<DefaultState>>) -> ConfigBuilder<DefaultState> {
53 let mut config_builder = cfg_builder.unwrap_or(config::Config::builder());
54 if value.is_object() {
55 let map = value.as_object();
56 for item in map.unwrap() {
57 if item.1.is_array() {
58 let arr = item.1.as_array().expect(COULD_NOT_SET_ITEM);
59 let mut new_arr : Vec<ValueKind> = Vec::new();
60 for ref i in arr.iter() {
61 let val : ValueKind = get_value_kind_from_value(i, true).0;
62 new_arr.push(val);
63 }
64 config_builder = config_builder.set_default(item.0.as_str(), new_arr).expect(COULD_NOT_SET_ITEM);
65 }else if item.1.is_string() {
66 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_str().unwrap()).expect(COULD_NOT_SET_ITEM);
67 } else if item.1.is_i64() {
68 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_i64().unwrap()).expect(COULD_NOT_SET_ITEM);
69 } else if item.1.is_boolean() {
70 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_bool().unwrap()).expect(COULD_NOT_SET_ITEM);
71 } else if item.1.is_f64() {
72 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_f64().unwrap()).expect(COULD_NOT_SET_ITEM);
73 } else if item.1.is_u64() {
74 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_u64().unwrap()).expect(COULD_NOT_SET_ITEM);
75 } else if item.1.is_object() {
76 config_builder = convert_panic(item.1, Some(config_builder));
77 } else if item.1.is_null() {
78 continue;
79 } else {
80 panic!("{}", NOT_SUPPORTED_TYPE);
81 }
82 }
83 }
84 config_builder
85}
86
87pub fn convert_non_panic(value : &Value, cfg_builder: Option<ConfigBuilder<DefaultState>>) -> ConfigBuilder<DefaultState> {
88 let mut config_builder = cfg_builder.unwrap_or(config::Config::builder());
89 if value.is_object() {
90 let map = value.as_object();
91 for item in map.unwrap() {
92 if item.1.is_array() {
93 let arr = item.1.as_array().unwrap_or(&DEFAULT_VEC);
94 let mut new_arr : Vec<ValueKind> = Vec::new();
95 for ref i in arr.iter() {
96 let val : ValueKind = get_value_kind_from_value(i, false).0;
97 new_arr.push(val);
98 }
99 config_builder = config_builder.set_default(item.0.as_str(), new_arr).unwrap_or_default();
100 }else if item.1.is_string() {
101 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_str().unwrap()).unwrap_or_default();
102 } else if item.1.is_i64() {
103 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_i64().unwrap()).unwrap_or_default();
104 } else if item.1.is_boolean() {
105 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_bool().unwrap()).unwrap_or_default();
106 } else if item.1.is_f64() {
107 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_f64().unwrap()).unwrap_or_default();
108 } else if item.1.is_u64() {
109 config_builder = config_builder.set_default(item.0.as_str(), item.1.as_u64().unwrap()).unwrap_or_default();
110 } else if item.1.is_object() {
111 config_builder = convert_non_panic(item.1, Some(config_builder));
112 } else if item.1.is_null() {
113 continue;
114 } else {
115 println!("Deserialized object is not one of supported types, so it was not added to the config.");
116 }
117 }
118 }
119 config_builder
120}
121#[macro_export]
122macro_rules! make_cfg {
128 ($($serializeable:ident),+) => {{
129 use serde_json::Value;
130 use struct_to_config::convert_panic;
131 let mut config_builder = Config::builder();
132 $(
133 let value = serde_json::to_value($serializeable).unwrap();
134 config_builder = convert_panic(&value, Some(config_builder));
135 )+
136 config_builder.build().unwrap()
137 }};
138 ($bool_should_panic:literal,$($serializeable:ident ),+) => {{
139 use struct_to_config::convert_panic;
140 use struct_to_config::convert_non_panic;
141 let mut config_builder = Config::builder();
142 if !$bool_should_panic {
143 $(
144 let value = serde_json::to_value($serializeable).unwrap();
145 config_builder = convert_non_panic(&value, Some(config_builder));
146 )+
147 } else {
148 $(
149 let value = serde_json::to_value($serializeable).unwrap();
150 config_builder = convert_panic(&value, Some(config_builder));
151 )+
152 }
153 config_builder.build().unwrap()
154 }};
155}