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(test)]
132mod test {
133    use std::sync::Arc;
134
135    use crate::{
136        source::{memory::HashSource, ConfigSource, ConfigSourceBuilder},
137        Mutex, *,
138    };
139
140    #[derive(FromConfig)]
141    struct A {
142        _ref_b: RefValue<B>,
143    }
144    #[derive(FromConfig)]
145    struct B {
146        _ref_c: RefValue<u8>,
147    }
148
149    macro_rules! should_err {
150        ($v:ident) => {
151            assert_eq!(true, $v.is_err());
152            match $v.err().unwrap() {
153                ConfigError::RefValueRecursiveError => {}
154                e => {
155                    println!("{:?}", e);
156                    assert_eq!(true, false)
157                }
158            }
159        };
160    }
161
162    #[test]
163    fn recursive_test() {
164        let config = Configuration::new();
165        let v = config.get::<A>("hello");
166        should_err!(v);
167        let v = config.get::<RefValue<B>>("hello");
168        should_err!(v);
169        let v = config.get::<RefValue<RefValue<u8>>>("hello");
170        should_err!(v);
171    }
172
173    struct R(Arc<Mutex<(u64, bool)>>);
174
175    impl ConfigSource for R {
176        fn name(&self) -> &str {
177            "r"
178        }
179
180        fn load(&self, builder: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError> {
181            builder.set("hello", self.0.lock_c()?.0);
182            Ok(())
183        }
184
185        fn allow_refresh(&self) -> bool {
186            true
187        }
188
189        fn refreshable(&self) -> Result<bool, ConfigError> {
190            let mut g = self.0.lock_c()?;
191            let flag = g.1;
192            g.1 = false;
193            Ok(flag)
194        }
195    }
196
197    impl R {
198        fn set(&self, v: u64) {
199            *self.0.lock_c().unwrap() = (v, true);
200        }
201
202        fn get(&self) -> u64 {
203            self.0.lock_c().unwrap().0
204        }
205    }
206
207    macro_rules! should_eq {
208        ($config:ident: $r:ident. $v:ident = $i:ident) => {
209            $r.set($i);
210            assert_eq!(true, $config.refresh_ref().unwrap());
211            assert_eq!(false, $config.refresh_ref().unwrap());
212            assert_eq!($i, $v.get().unwrap());
213            assert_eq!(0, $config.get::<u64>("hello").unwrap());
214        };
215    }
216
217    #[test]
218    fn refresh_test() {
219        let r = R(Arc::new(Mutex::new((0, true))));
220        assert_eq!("r", r.name());
221        let config = Configuration::new()
222            .register_source(R(r.0.clone()))
223            .unwrap();
224        let v = config.get::<RefValue<u64>>("hello").unwrap();
225
226        for i in 0..1000 {
227            should_eq!(config: r.v = i);
228        }
229    }
230
231    macro_rules! should_eq_mut {
232        ($config:ident: $r:ident. $v:ident = $i:ident) => {
233            $r.set($i);
234            assert_eq!(true, $config.refresh().unwrap());
235            assert_eq!(false, $config.refresh().unwrap());
236            assert_eq!($i, $v.get().unwrap());
237            assert_eq!($i, $config.get::<u64>("hello").unwrap());
238        };
239    }
240    #[test]
241    fn refresh_mut_test() {
242        let r = R(Arc::new(Mutex::new((0, true))));
243        assert_eq!("r", r.name());
244        let mut config = Configuration::new()
245            .register_source(R(r.0.clone()))
246            .unwrap();
247        let v = config.get::<RefValue<u64>>("hello").unwrap();
248
249        for i in 0..1000 {
250            should_eq_mut!(config: r.v = i);
251        }
252    }
253
254    macro_rules! should_eq_2 {
255        ($config:ident: $r:ident.$s:ident. $v:ident = $i:ident) => {
256            $s.set($i);
257            assert_eq!(true, $config.refresh().unwrap());
258            assert_eq!(false, $config.refresh().unwrap());
259            assert_eq!($r.get(), $v.get().unwrap());
260            $r.set($i);
261            assert_eq!($i, $r.get());
262            assert_ne!($r.get(), $v.get().unwrap());
263            assert_eq!(true, $config.refresh().unwrap());
264            assert_eq!(false, $config.refresh().unwrap());
265            assert_eq!($i, $v.get().unwrap());
266            assert_eq!($i, $config.get::<u64>("hello").unwrap());
267        };
268    }
269
270    #[test]
271    fn multiple_source_refresh_test() {
272        let a = HashSource::new("name");
273        let r = R(Arc::new(Mutex::new((0, true))));
274        let s = R(Arc::new(Mutex::new((0, true))));
275        assert_eq!("r", r.name());
276        let mut config = Configuration::new()
277            .register_source(a)
278            .unwrap()
279            .register_source(R(r.0.clone()))
280            .unwrap()
281            .register_source(R(s.0.clone()))
282            .unwrap();
283        let v = config.get::<RefValue<u64>>("hello").unwrap();
284
285        for i in 1..1000 {
286            should_eq_2!(config: r.s.v = i);
287        }
288    }
289}