cfg_rs/
value_ref.rs

1use crate::macros::cfg_log;
2use crate::*;
3
4/// [`RefValue`] means reference of value or refreshable value,
5/// it holds a value which can be updated when [`Configuration`] is refreshed.
6///
7/// It implements [`FromConfig`], user can use it in auto deriving config objects.
8///
9/// But it is not supporting **recursively** usage, following example will cause runtime error:
10/// ```rust,ignore
11/// #[derive(FromConfig)]
12/// struct A {
13///   ref_b: RefValue<B>,
14/// }
15/// #[derive(FromConfig)]
16/// struct B {
17///   ref_c: RefValue<u8>,
18/// }
19/// ```
20#[allow(missing_debug_implementations)]
21pub struct RefValue<T>(Arc<Mutex<T>>, String);
22
23impl<T> Clone for RefValue<T> {
24    fn clone(&self) -> Self {
25        RefValue(self.0.clone(), self.1.clone())
26    }
27}
28
29impl<T> RefValue<T> {
30    fn new(k: String, v: T) -> Self {
31        Self(Arc::new(Mutex::new(v)), k)
32    }
33
34    fn set(&self, v: T) -> Result<(), ConfigError> {
35        *self.0.lock_c()? = v;
36        Ok(())
37    }
38
39    /// Use referenced value, be careful with lock.
40    pub fn with<F: FnOnce(&T) -> R, R>(&self, f: F) -> Result<R, ConfigError> {
41        let g = self.0.lock_c()?;
42        Ok((f)(&*g))
43    }
44}
45impl<T: Clone> RefValue<T> {
46    /// Get cloned value.
47    pub fn get(&self) -> Result<T, ConfigError> {
48        self.with(|v| v.clone())
49    }
50}
51
52impl<T: FromConfig + Send + 'static> FromConfig for RefValue<T> {
53    fn from_config(
54        context: &mut ConfigContext<'_>,
55        value: Option<ConfigValue<'_>>,
56    ) -> Result<Self, ConfigError> {
57        if context.ref_value_flag {
58            return Err(ConfigError::RefValueRecursiveError);
59        }
60        context.ref_value_flag = true;
61        let v = do_from_config(context, value);
62        context.ref_value_flag = false;
63        if v.is_ok() {
64            cfg_log!(
65                log::Level::Debug,
66                "RefValue {} registered!",
67                context.current_key_str()
68            );
69        }
70        v
71    }
72}
73
74#[inline]
75fn do_from_config<T: FromConfig + Send + 'static>(
76    context: &mut ConfigContext<'_>,
77    value: Option<ConfigValue<'_>>,
78) -> Result<RefValue<T>, ConfigError> {
79    let v = RefValue::new(context.current_key(), T::from_config(context, value)?);
80    context.as_refresher().push(v.clone())?;
81    Ok(v)
82}
83
84trait Ref: Send {
85    fn refresh(&self, config: &Configuration) -> Result<(), ConfigError>;
86}
87
88impl<T: FromConfig + Send> Ref for RefValue<T> {
89    fn refresh(&self, config: &Configuration) -> Result<(), ConfigError> {
90        cfg_log!(log::Level::Debug, "RefValue {} refreshing...", &self.1);
91        self.set(config.get(&self.1)?)
92    }
93}
94
95pub(crate) struct Refresher {
96    max: usize,
97    refs: Mutex<Vec<Box<dyn Ref + Send + 'static>>>,
98}
99
100impl Refresher {
101    pub(crate) fn new() -> Self {
102        Self {
103            max: 1024,
104            refs: Mutex::new(vec![]),
105        }
106    }
107
108    fn push(&self, r: impl Ref + 'static) -> Result<(), ConfigError> {
109        let g = self.refs.try_lock_c()?;
110        if let Some(mut g) = g {
111            if g.len() >= self.max {
112                return Err(ConfigError::TooManyInstances(self.max));
113            }
114            g.push(Box::new(r));
115            Ok(())
116        } else {
117            Err(ConfigError::RefValueRecursiveError)
118        }
119    }
120
121    pub(crate) fn refresh(&self, c: &Configuration) -> Result<(), ConfigError> {
122        let g = self.refs.lock_c()?;
123        let it = g.iter();
124        for i in it {
125            i.refresh(c)?;
126        }
127        Ok(())
128    }
129}
130
131#[cfg_attr(coverage_nightly, coverage(off))]
132#[cfg(test)]
133mod test {
134    use std::sync::Arc;
135
136    use crate::{
137        source::{memory::HashSource, ConfigSource, ConfigSourceBuilder},
138        Mutex, *,
139    };
140
141    #[derive(FromConfig)]
142    #[config(crate = "crate")]
143    struct A {
144        _ref_b: RefValue<B>,
145    }
146    #[derive(FromConfig)]
147    #[config(crate = "crate")]
148    struct B {
149        _ref_c: RefValue<u8>,
150    }
151
152    macro_rules! should_err {
153        ($v:ident) => {
154            assert_eq!(true, $v.is_err());
155            match $v.err().unwrap() {
156                ConfigError::RefValueRecursiveError => {}
157                e => {
158                    println!("{:?}", e);
159                    assert_eq!(true, false)
160                }
161            }
162        };
163    }
164
165    #[test]
166    fn recursive_test() {
167        let config = Configuration::new();
168        let v = config.get::<A>("hello");
169        should_err!(v);
170        let v = config.get::<RefValue<B>>("hello");
171        should_err!(v);
172        let v = config.get::<RefValue<RefValue<u8>>>("hello");
173        should_err!(v);
174    }
175
176    struct R(Arc<Mutex<(u64, bool)>>);
177
178    impl ConfigSource for R {
179        fn name(&self) -> &str {
180            "r"
181        }
182
183        fn load(&self, builder: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError> {
184            builder.set("hello", self.0.lock_c()?.0);
185            Ok(())
186        }
187
188        fn allow_refresh(&self) -> bool {
189            true
190        }
191
192        fn refreshable(&self) -> Result<bool, ConfigError> {
193            let mut g = self.0.lock_c()?;
194            let flag = g.1;
195            g.1 = false;
196            Ok(flag)
197        }
198    }
199
200    impl R {
201        fn set(&self, v: u64) {
202            *self.0.lock_c().unwrap() = (v, true);
203        }
204
205        fn get(&self) -> u64 {
206            self.0.lock_c().unwrap().0
207        }
208    }
209
210    macro_rules! should_eq {
211        ($config:ident: $r:ident. $v:ident = $i:ident) => {
212            $r.set($i);
213            assert_eq!(true, $config.refresh_ref().unwrap());
214            assert_eq!(false, $config.refresh_ref().unwrap());
215            assert_eq!($i, $v.get().unwrap());
216            assert_eq!(0, $config.get::<u64>("hello").unwrap());
217        };
218    }
219
220    #[test]
221    fn refresh_test() {
222        let r = R(Arc::new(Mutex::new((0, true))));
223        assert_eq!("r", r.name());
224        let config = Configuration::new()
225            .register_source(R(r.0.clone()))
226            .unwrap();
227        let v = config.get::<RefValue<u64>>("hello").unwrap();
228
229        for i in 0..1000 {
230            should_eq!(config: r.v = i);
231        }
232    }
233
234    macro_rules! should_eq_mut {
235        ($config:ident: $r:ident. $v:ident = $i:ident) => {
236            $r.set($i);
237            assert_eq!(true, $config.refresh().unwrap());
238            assert_eq!(false, $config.refresh().unwrap());
239            assert_eq!($i, $v.get().unwrap());
240            assert_eq!($i, $config.get::<u64>("hello").unwrap());
241        };
242    }
243    #[test]
244    fn refresh_mut_test() {
245        let r = R(Arc::new(Mutex::new((0, true))));
246        assert_eq!("r", r.name());
247        let mut config = Configuration::new()
248            .register_source(R(r.0.clone()))
249            .unwrap();
250        let v = config.get::<RefValue<u64>>("hello").unwrap();
251
252        for i in 0..1000 {
253            should_eq_mut!(config: r.v = i);
254        }
255    }
256
257    macro_rules! should_eq_2 {
258        ($config:ident: $r:ident.$s:ident. $v:ident = $i:ident) => {
259            $s.set($i);
260            assert_eq!(true, $config.refresh().unwrap());
261            assert_eq!(false, $config.refresh().unwrap());
262            assert_eq!($r.get(), $v.get().unwrap());
263            $r.set($i);
264            assert_eq!($i, $r.get());
265            assert_ne!($r.get(), $v.get().unwrap());
266            assert_eq!(true, $config.refresh().unwrap());
267            assert_eq!(false, $config.refresh().unwrap());
268            assert_eq!($i, $v.get().unwrap());
269            assert_eq!($i, $config.get::<u64>("hello").unwrap());
270        };
271    }
272
273    #[test]
274    fn multiple_source_refresh_test() {
275        let a = HashSource::new("name");
276        let r = R(Arc::new(Mutex::new((0, true))));
277        let s = R(Arc::new(Mutex::new((0, true))));
278        assert_eq!("r", r.name());
279        let mut config = Configuration::new()
280            .register_source(a)
281            .unwrap()
282            .register_source(R(r.0.clone()))
283            .unwrap()
284            .register_source(R(s.0.clone()))
285            .unwrap();
286        let v = config.get::<RefValue<u64>>("hello").unwrap();
287
288        for i in 1..1000 {
289            should_eq_2!(config: r.s.v = i);
290        }
291    }
292}