cfg_rs/source/
memory.rs

1//! In memory source.
2use std::{
3    borrow::Borrow,
4    collections::{HashMap, HashSet},
5    vec,
6};
7
8use crate::{
9    key::{PartialKey, PartialKeyIter},
10    source::{ConfigSource, ConfigSourceAdaptor},
11    value_ref::Refresher,
12    ConfigError, ConfigKey, ConfigValue, PartialKeyCollector,
13};
14
15/// Hash Source.
16#[doc(hidden)]
17#[allow(missing_debug_implementations, unreachable_pub)]
18pub struct HashSource {
19    pub(crate) value: HashMap<String, HashValue>,
20    name: String,
21    pub(crate) refs: Refresher,
22}
23
24impl ConfigSource for HashSource {
25    fn name(&self) -> &str {
26        &self.name
27    }
28    fn load(&self, builder: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError> {
29        for (k, v) in &self.value {
30            if let Some(v) = &v.value {
31                builder.set(k, v.clone_static());
32            }
33        }
34        Ok(())
35    }
36}
37
38/// Hash Value.
39#[derive(Debug)]
40pub(crate) struct HashValue {
41    sub_str: HashSet<String>,
42    sub_int: Option<usize>,
43    value: Option<ConfigValue<'static>>,
44}
45
46/// Config source builder.
47#[derive(Debug)]
48pub struct ConfigSourceBuilder<'a> {
49    key: Vec<String>,
50    map: &'a mut HashMap<String, HashValue>,
51    count: usize,
52}
53
54impl HashValue {
55    #[inline]
56    fn new() -> Self {
57        Self {
58            sub_str: HashSet::new(),
59            sub_int: None,
60            value: None,
61        }
62    }
63
64    #[inline]
65    fn push_val<V: Into<ConfigValue<'static>>>(&mut self, val: V) {
66        if self.value.is_none() {
67            self.value = Some(val.into());
68        }
69    }
70
71    #[inline]
72    fn push_key(&mut self, key: &PartialKey<'_>) {
73        match key {
74            PartialKey::Str(i) => {
75                self.sub_str.insert(i.to_string());
76            }
77            PartialKey::Int(i) => {
78                let v = self.sub_int.get_or_insert(*i);
79                if *v < *i {
80                    *v = *i;
81                }
82            }
83        }
84    }
85}
86
87impl HashSource {
88    pub(crate) fn new<K: Into<String>>(name: K) -> Self {
89        Self {
90            value: HashMap::new(),
91            name: name.into(),
92            refs: Refresher::new(),
93        }
94    }
95
96    #[inline]
97    pub(crate) fn prefixed(&mut self) -> ConfigSourceBuilder<'_> {
98        ConfigSourceBuilder {
99            key: vec![],
100            map: &mut self.value,
101            count: 0,
102        }
103    }
104
105    pub(crate) fn get_value(&self, key: &ConfigKey<'_>) -> Option<ConfigValue<'_>> {
106        let key = key.as_str();
107        self.value
108            .get(key)
109            .and_then(|f| f.value.as_ref())
110            .map(|v| match v {
111                ConfigValue::StrRef(v) => ConfigValue::StrRef(v),
112                ConfigValue::Str(v) => ConfigValue::StrRef(v),
113                ConfigValue::Int(v) => ConfigValue::Int(*v),
114                ConfigValue::Float(v) => ConfigValue::Float(*v),
115                ConfigValue::Bool(v) => ConfigValue::Bool(*v),
116                #[cfg(feature = "rand")]
117                ConfigValue::Rand(v) => ConfigValue::Rand(*v),
118            })
119    }
120
121    pub(crate) fn collect_keys<'a>(
122        &'a self,
123        prefix: &ConfigKey<'_>,
124        sub: &mut PartialKeyCollector<'a>,
125    ) {
126        if let Some(v) = self.value.get(prefix.as_str()) {
127            for k in v.sub_str.iter() {
128                sub.str_key.insert(k.as_str());
129            }
130            if let Some(i) = v.sub_int {
131                sub.insert_int(i);
132            }
133        }
134    }
135    pub(crate) fn set<K: Borrow<str>, V: Into<ConfigValue<'static>>>(mut self, k: K, v: V) -> Self {
136        let mut c = self.prefixed();
137        c.set(k.borrow(), v);
138        self
139    }
140}
141
142impl ConfigSourceBuilder<'_> {
143    /// Set value.
144    #[allow(single_use_lifetimes)]
145    pub fn set<'b, K: Into<PartialKeyIter<'b>>, V: Into<ConfigValue<'static>>>(
146        &mut self,
147        k: K,
148        v: V,
149    ) {
150        self.push(k);
151        self.insert(v);
152        self.pop();
153    }
154
155    /// Insert map into source.
156    pub fn insert_map<I: IntoIterator<Item = (K, V)>, K: Borrow<str>, V: ConfigSourceAdaptor>(
157        &mut self,
158        iter: I,
159    ) -> Result<(), ConfigError> {
160        for (k, v) in iter {
161            self.push(k.borrow());
162            let x = v.convert_source(self);
163            self.pop();
164            x?;
165        }
166        Ok(())
167    }
168
169    /// Insert array into source.
170    pub fn insert_array<I: IntoIterator<Item = S>, S: ConfigSourceAdaptor>(
171        &mut self,
172        iter: I,
173    ) -> Result<(), ConfigError> {
174        for (i, s) in iter.into_iter().enumerate() {
175            self.push(i);
176            let x = s.convert_source(self);
177            self.pop();
178            x?;
179        }
180        Ok(())
181    }
182
183    #[inline]
184    fn push<'b, K: Into<PartialKeyIter<'b>>>(&mut self, key: K) {
185        let mut curr = self.curr();
186        let mut vs = vec![];
187        let iter: PartialKeyIter<'b> = key.into();
188        for k in iter {
189            let v = self.map.entry(curr.clone()).or_insert_with(HashValue::new);
190            v.push_key(&k);
191            k.update_string(&mut curr);
192            vs.push(k);
193        }
194        self.key.push(curr);
195    }
196
197    #[inline]
198    fn pop(&mut self) {
199        self.key.pop();
200    }
201
202    #[inline]
203    fn curr(&self) -> String {
204        self.key
205            .last()
206            .map(|f| f.as_str())
207            .unwrap_or("")
208            .to_string()
209    }
210
211    /// Insert value into source.
212    #[inline]
213    pub fn insert<V: Into<ConfigValue<'static>>>(&mut self, value: V) {
214        self.count += 1;
215        self.map
216            .entry(self.curr())
217            .or_insert_with(HashValue::new)
218            .push_val(value);
219    }
220
221    pub(crate) fn count(&self) -> usize {
222        self.count
223    }
224}
225
226#[cfg_attr(coverage_nightly, coverage(off))]
227#[cfg(test)]
228mod tests {
229    use super::*;
230
231    #[test]
232    fn hash_source_new_and_name() {
233        let hs = HashSource::new("abc");
234        assert_eq!(hs.name(), "abc");
235    }
236
237    #[test]
238    fn hash_source_prefixed_and_builder_set() {
239        let mut hs = HashSource::new("test");
240        {
241            let mut builder = hs.prefixed();
242            builder.set("a", 1);
243            builder.set("b", "str");
244        }
245        let mut cache_a = crate::key::CacheString::new();
246        let mut ka = cache_a.new_key();
247        ka.push("a");
248        let mut cache_b = crate::key::CacheString::new();
249        let mut kb = cache_b.new_key();
250        kb.push("b");
251        match hs.get_value(&ka) {
252            Some(ConfigValue::Int(1)) => {}
253            _ => panic!("Expected Int(1)"),
254        }
255        match hs.get_value(&kb) {
256            Some(ConfigValue::StrRef("str")) => {}
257            Some(ConfigValue::Str(s)) if s == "str" => {}
258            _ => panic!("Expected StrRef(\"str\")"),
259        }
260    }
261
262    #[test]
263    fn hash_source_collect_keys() {
264        let mut hs = HashSource::new("test");
265        {
266            let mut builder = hs.prefixed();
267            builder.set("foo.bar", 1);
268            builder.set("foo.baz", 2);
269            builder.set("foo[0]", 3);
270        }
271        let mut collector = PartialKeyCollector::new();
272        let mut cache = crate::key::CacheString::new();
273        let mut key = cache.new_key();
274        key.push("foo");
275        hs.collect_keys(&key, &mut collector);
276        assert!(collector.str_key.iter().any(|&x| x == "bar"));
277        assert!(collector.str_key.iter().any(|&x| x == "baz"));
278        assert!(collector.int_key.iter().any(|&x| x == 1));
279    }
280
281    #[test]
282    fn hash_value_push_key_and_val() {
283        let mut hv = HashValue::new();
284        hv.push_key(&PartialKey::Str("abc"));
285        hv.push_key(&PartialKey::Int(2));
286        hv.push_key(&PartialKey::Int(1));
287        hv.push_val("val");
288        hv.push_val("should_not_overwrite");
289        assert!(hv.sub_str.contains("abc"));
290        assert_eq!(hv.sub_int, Some(2));
291        match hv.value {
292            Some(ConfigValue::Str(ref s)) => assert_eq!(s, "val"),
293            Some(ConfigValue::StrRef(s)) => assert_eq!(s, "val"),
294            _ => panic!("Expected Str(\"val\")"),
295        }
296    }
297
298    #[test]
299    fn config_source_builder_insert_map_and_array() {
300        struct Dummy;
301        impl ConfigSourceAdaptor for Dummy {
302            fn convert_source(
303                self,
304                builder: &mut ConfigSourceBuilder<'_>,
305            ) -> Result<(), ConfigError> {
306                builder.insert("dummy");
307                Ok(())
308            }
309        }
310        let mut hs = HashSource::new("test");
311        {
312            let mut builder = hs.prefixed();
313            let map = vec![("k1", Dummy), ("k2", Dummy)];
314            builder.insert_map(map).unwrap();
315            let arr = vec![Dummy, Dummy];
316            builder.insert_array(arr).unwrap();
317        }
318        assert!(hs.value.contains_key("k1"));
319        assert!(hs.value.contains_key("k2"));
320        assert!(hs.value.contains_key("[0]")); // index 1 of array
321    }
322
323    #[test]
324    fn config_source_builder_push_pop_curr_count() {
325        let mut hs = HashSource::new("test");
326        let mut builder = hs.prefixed();
327        assert_eq!(builder.curr(), "");
328        builder.push("foo");
329        assert_eq!(builder.curr(), "foo");
330        builder.push("bar");
331        assert_eq!(builder.curr(), "foo.bar");
332        builder.pop();
333        assert_eq!(builder.curr(), "foo");
334        builder.pop();
335        assert_eq!(builder.curr(), "");
336        let c = builder.count();
337        assert_eq!(c, 0);
338    }
339
340    #[test]
341    fn config_source_load_sets_values() {
342        let mut hs = HashSource::new("test");
343        {
344            let mut builder = hs.prefixed();
345            builder.set("x", 42);
346        }
347        let mut target = HashSource::new("target");
348        {
349            let mut builder = target.prefixed();
350            hs.load(&mut builder).unwrap();
351        }
352        let mut cache = crate::key::CacheString::new();
353        let mut key = cache.new_key();
354        key.push("x");
355        match target.get_value(&key) {
356            Some(ConfigValue::Int(42)) => {}
357            _ => panic!("Expected Int(42)"),
358        }
359    }
360
361    #[test]
362    fn hash_source_get_value_variants() {
363        let mut hs = HashSource::new("test");
364        {
365            let mut builder = hs.prefixed();
366            builder.set("s1", "abc");
367            builder.set("i1", 123);
368            builder.set("f1", 3.14);
369            builder.set("b1", true);
370        }
371        // String
372        let mut cache = crate::key::CacheString::new();
373        let mut key = cache.new_key();
374        key.push("s1");
375        match hs.get_value(&key) {
376            Some(ConfigValue::StrRef("abc")) => {}
377            Some(ConfigValue::Str(s)) if s == "abc" => {}
378            _ => panic!("Expected StrRef(\"abc\")"),
379        }
380        // Int
381        let mut cache = crate::key::CacheString::new();
382        let mut key = cache.new_key();
383        key.push("i1");
384        match hs.get_value(&key) {
385            Some(ConfigValue::Int(123)) => {}
386            _ => panic!("Expected Int(123)"),
387        }
388        // Float
389        let mut cache = crate::key::CacheString::new();
390        let mut key = cache.new_key();
391        key.push("f1");
392        match hs.get_value(&key) {
393            Some(ConfigValue::Float(f)) if (f - 3.14).abs() < 1e-6 => {}
394            _ => panic!("Expected Float(3.14)"),
395        }
396        // Bool
397        let mut cache = crate::key::CacheString::new();
398        let mut key = cache.new_key();
399        key.push("b1");
400        match hs.get_value(&key) {
401            Some(ConfigValue::Bool(true)) => {}
402            _ => panic!("Expected Bool(true)"),
403        }
404        // Not found
405        let mut cache = crate::key::CacheString::new();
406        let mut key = cache.new_key();
407        key.push("notfound");
408        assert!(hs.get_value(&key).is_none());
409    }
410}