okcodes_config/
config.rs

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