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