zng_ext_config/
switch.rs

1use zng_var::MergeVarBuilder;
2
3use super::*;
4
5/// Represents multiple config sources that are matched by key.
6///
7/// When a config key is requested a closure defined for each config case in the switch
8/// is called, if the closure returns a key the config case is used.
9///
10/// Note that the returned config variables are linked directly with the matched configs,
11/// and if none matches returns from a fallback [`MemoryConfig`]. If a config is pushed after no match
12/// the already returned variable will not update to link with the new config.
13#[derive(Default)]
14pub struct SwitchConfig {
15    cfgs: Vec<SwitchCfg>,
16}
17impl SwitchConfig {
18    /// New default empty.
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    /// Push a config case on the switch.
24    ///
25    /// The `match_key` closure will be called after the match of previous configs, if it returns `Some(key)`
26    /// the key will be used on the `config` to retrieve the value variable.
27    pub fn push(&mut self, match_key: impl Fn(&ConfigKey) -> Option<ConfigKey> + Send + Sync + 'static, config: impl AnyConfig) {
28        self.cfgs.push(SwitchCfg {
29            match_key: Box::new(match_key),
30            cfg: Box::new(config),
31        })
32    }
33
34    /// Push a config case matched by a key `prefix`.
35    ///
36    /// The `prefix` is stripped from the key before it is passed on to the `config`.
37    ///
38    /// Always matches the config if the prefix is empty.
39    pub fn push_prefix(&mut self, prefix: impl Into<Txt>, config: impl AnyConfig) {
40        let prefix = prefix.into();
41        if prefix.is_empty() {
42            self.push(|key| Some(key.clone()), config)
43        } else {
44            self.push(move |key| key.strip_prefix(prefix.as_str()).map(Txt::from_str), config)
45        }
46    }
47
48    /// Push the config and return.
49    ///
50    /// See [`push`] for more details.
51    ///
52    /// [`push`]: Self::push
53    pub fn with(mut self, match_key: impl Fn(&ConfigKey) -> Option<ConfigKey> + Send + Sync + 'static, config: impl AnyConfig) -> Self {
54        self.push(match_key, config);
55        self
56    }
57
58    /// Push the config and return.
59    ///
60    /// See [`push_prefix`] for more details.
61    ///
62    /// [`push_prefix`]: Self::push
63    pub fn with_prefix(mut self, prefix: impl Into<Txt>, config: impl AnyConfig) -> Self {
64        self.push_prefix(prefix, config);
65        self
66    }
67
68    fn cfg_mut(&mut self, key: &ConfigKey) -> Option<(ConfigKey, &mut dyn AnyConfig)> {
69        for c in &mut self.cfgs {
70            if let Some(key) = (c.match_key)(key) {
71                return Some((key, &mut *c.cfg));
72            }
73        }
74        None
75    }
76}
77impl AnyConfig for SwitchConfig {
78    fn status(&self) -> Var<ConfigStatus> {
79        let mut s = MergeVarBuilder::with_capacity(self.cfgs.len());
80        for c in &self.cfgs {
81            s.push(c.cfg.status());
82        }
83        s.build(|status| ConfigStatus::merge_status(status.iter().cloned()))
84    }
85
86    fn get_raw(&mut self, key: ConfigKey, default: RawConfigValue, insert: bool) -> Var<RawConfigValue> {
87        match self.cfg_mut(&key) {
88            Some((key, cfg)) => cfg.get_raw(key, default, insert),
89            None => const_var(default),
90        }
91    }
92
93    fn contains_key(&mut self, key: ConfigKey) -> Var<bool> {
94        match self.cfg_mut(&key) {
95            Some((key, cfg)) => cfg.contains_key(key),
96            None => const_var(false),
97        }
98    }
99
100    fn remove(&mut self, key: &ConfigKey) -> bool {
101        match self.cfg_mut(key) {
102            Some((key, cfg)) => cfg.remove(&key),
103            None => false,
104        }
105    }
106
107    fn low_memory(&mut self) {
108        for c in &mut self.cfgs {
109            c.cfg.low_memory();
110        }
111    }
112}
113
114struct SwitchCfg {
115    match_key: Box<dyn Fn(&ConfigKey) -> Option<ConfigKey> + Send + Sync>,
116    cfg: Box<dyn AnyConfig>,
117}