storm_config/
config.rs

1use std::fmt::Debug;
2
3use serde::de::Deserialize;
4use serde::ser::Serialize;
5
6use crate::builder::{ConfigBuilder, DefaultState};
7use crate::errors::{ConfigError, Result};
8use crate::map::Map;
9use crate::path;
10use crate::ser::ConfigSerializer;
11use crate::source::Source;
12use crate::value::{Table, Value};
13
14/// A prioritized configuration repository. It maintains a set of
15/// configuration sources, fetches values to populate those, and provides
16/// them according to the source's priority.
17#[derive(Clone, Debug)]
18pub struct Config {
19  defaults: Map<path::Expression, Value>,
20  overrides: Map<path::Expression, Value>,
21  sources: Vec<Box<dyn Source + Send + Sync>>,
22
23  /// Root of the cached configuration.
24  pub cache: Value,
25}
26
27impl Default for Config {
28  fn default() -> Self {
29    Self {
30      defaults: Default::default(),
31      overrides: Default::default(),
32      sources: Default::default(),
33      cache: Value::new(None, Table::new()),
34    }
35  }
36}
37
38impl Config {
39  pub(crate) fn new(value: Value) -> Self {
40    Self { cache: value, ..Self::default() }
41  }
42
43  /// Creates new [`ConfigBuilder`] instance
44  pub fn builder() -> ConfigBuilder<DefaultState> {
45    ConfigBuilder::<DefaultState>::default()
46  }
47
48  /// Merge in a configuration property source.
49  pub fn merge<T>(&mut self, source: T) -> Result<&mut Self>
50  where
51    T: 'static,
52    T: Source + Send + Sync,
53  {
54    self.sources.push(Box::new(source));
55
56    #[allow(deprecated)]
57    self.refresh()
58  }
59
60  /// Merge in a configuration property source.
61  pub fn with_merged<T>(mut self, source: T) -> Result<Self>
62  where
63    T: 'static,
64    T: Source + Send + Sync,
65  {
66    self.sources.push(Box::new(source));
67
68    #[allow(deprecated)]
69    self.refresh()?;
70    Ok(self)
71  }
72
73  /// Refresh the configuration cache with fresh
74  /// data from added sources.
75  ///
76  /// Configuration is automatically refreshed after a mutation
77  /// operation (`set`, `merge`, `set_default`, etc.).
78  #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")]
79  pub fn refresh(&mut self) -> Result<&mut Self> {
80    self.cache = {
81      let mut cache: Value = Map::<String, Value>::new().into();
82
83      // Add defaults
84      for (key, val) in &self.defaults {
85        key.set(&mut cache, val.clone());
86      }
87
88      // Add sources
89      self.sources.collect_to(&mut cache)?;
90
91      // Add overrides
92      for (key, val) in &self.overrides {
93        key.set(&mut cache, val.clone());
94      }
95
96      cache
97    };
98
99    Ok(self)
100  }
101
102  /// Set a default `value` at `key`
103  #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")]
104  pub fn set_default<T>(&mut self, key: &str, value: T) -> Result<&mut Self>
105  where
106    T: Into<Value>,
107  {
108    self.defaults.insert(key.to_lowercase().as_str().parse()?, value.into());
109
110    #[allow(deprecated)]
111    self.refresh()
112  }
113
114  /// Set an overwrite
115  ///
116  /// This function sets an overwrite value.
117  /// The overwrite `value` is written to the `key` location on every `refresh()`
118  ///
119  /// # Warning
120  ///
121  /// Errors if config is frozen
122  #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")]
123  pub fn set<T>(&mut self, key: &str, value: T) -> Result<&mut Self>
124  where
125    T: Into<Value>,
126  {
127    self.overrides.insert(key.to_lowercase().as_str().parse()?, value.into());
128
129    #[allow(deprecated)]
130    self.refresh()
131  }
132
133  #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")]
134  pub fn set_once(&mut self, key: &str, value: Value) -> Result<()> {
135    let expr: path::Expression = key.to_lowercase().as_str().parse()?;
136
137    // Traverse the cache using the path to (possibly) retrieve a value
138    if let Some(ref mut val) = expr.get_mut(&mut self.cache) {
139      **val = value;
140    } else {
141      expr.set(&mut self.cache, value);
142    }
143    Ok(())
144  }
145
146  fn get_value(&self, key: &str) -> Result<Value> {
147    let k: String = key.to_lowercase();
148    let key = k.as_str();
149    // Parse the key into a path expression
150    let expr: path::Expression = key.parse()?;
151
152    // Traverse the cache using the path to (possibly) retrieve a value
153    let value = expr.get(&self.cache).cloned();
154
155    value.ok_or_else(|| ConfigError::NotFound(key.into()))
156  }
157
158  pub fn get<'de, T: Deserialize<'de>>(&self, key: &str) -> Result<T> {
159    self.get_value(key).and_then(|value| {
160      // Deserialize the received value into the requested type
161      T::deserialize(value).map_err(|e| e.extend_with_key(key))
162    })
163  }
164
165  pub fn get_string(&self, key: &str) -> Result<String> {
166    self.get_value(key).and_then(|value| value.into_string().map_err(|e| e.extend_with_key(key)))
167  }
168
169  pub fn get_int(&self, key: &str) -> Result<i64> {
170    self.get_value(key).and_then(|value| value.into_int().map_err(|e| e.extend_with_key(key)))
171  }
172
173  pub fn get_float(&self, key: &str) -> Result<f64> {
174    self.get_value(key).and_then(|value| value.into_float().map_err(|e| e.extend_with_key(key)))
175  }
176
177  pub fn get_bool(&self, key: &str) -> Result<bool> {
178    self.get_value(key).and_then(|value| value.into_bool().map_err(|e| e.extend_with_key(key)))
179  }
180
181  pub fn get_table(&self, key: &str) -> Result<Map<String, Value>> {
182    self.get_value(key).and_then(|value| value.into_table().map_err(|e| e.extend_with_key(key)))
183  }
184
185  pub fn get_array(&self, key: &str) -> Result<Vec<Value>> {
186    self.get_value(key).and_then(|value| value.into_array().map_err(|e| e.extend_with_key(key)))
187  }
188
189  /// Attempt to deserialize the entire configuration into the requested type.
190  pub fn try_deserialize<'de, T: Deserialize<'de>>(self) -> Result<T> {
191    T::deserialize(self)
192  }
193
194  /// Attempt to serialize the entire configuration from the given type.
195  pub fn try_from<T: Serialize>(from: &T) -> Result<Self> {
196    let mut serializer = ConfigSerializer::default();
197    from.serialize(&mut serializer)?;
198    Ok(serializer.output)
199  }
200}
201
202impl Source for Config {
203  fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
204    Box::new((*self).clone())
205  }
206
207  fn collect(&self) -> Result<Map<String, Value>> {
208    self.cache.clone().into_table()
209  }
210}