1use crate::macros::cfg_log;
2use crate::*;
3
4#[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 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 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}