zng_ext_config/
fallback.rs1use crate::task::parking_lot::Mutex;
2use zng_var::expr_var;
3
4use super::*;
5
6pub trait FallbackConfigReset: AnyConfig + Sync {
8 fn reset(&self, key: &ConfigKey);
10
11 fn can_reset(&self, key: ConfigKey) -> Var<bool>;
13
14 fn clone_boxed(&self) -> Box<dyn FallbackConfigReset>;
16}
17impl Clone for Box<dyn FallbackConfigReset> {
18 fn clone(&self) -> Self {
19 self.clone_boxed()
20 }
21}
22
23pub struct FallbackConfig<S: Config, F: Config>(Arc<Mutex<FallbackConfigData<S, F>>>);
31
32impl<S: Config, F: Config> FallbackConfig<S, F> {
33 pub fn new(source: S, fallback: F) -> Self {
35 Self(Arc::new(Mutex::new(FallbackConfigData {
36 source,
37 fallback,
38 output: Default::default(),
39 })))
40 }
41}
42
43impl<S: AnyConfig, F: AnyConfig> AnyConfig for FallbackConfig<S, F> {
44 fn status(&self) -> Var<ConfigStatus> {
45 let self_ = self.0.lock();
46 expr_var! {
47 ConfigStatus::merge_status([#{self_.fallback.status()}.clone(), #{self_.source.status()}.clone()].into_iter())
48 }
49 }
50
51 fn get_raw(&mut self, key: ConfigKey, default: RawConfigValue, insert: bool) -> Var<RawConfigValue> {
52 self.0.lock().bind_raw(key, default, insert)
53 }
54
55 fn contains_key(&mut self, key: ConfigKey) -> Var<bool> {
56 let mut self_ = self.0.lock();
57 expr_var! {
58 *#{self_.source.contains_key(key.clone())} || *#{self_.fallback.contains_key(key)}
59 }
60 }
61
62 fn remove(&mut self, key: &ConfigKey) -> bool {
63 let mut self_ = self.0.lock();
64 let a = self_.source.remove(key);
65 let b = self_.fallback.remove(key);
66 a || b
67 }
68
69 fn low_memory(&mut self) {
70 let mut self_ = self.0.lock();
71 self_.source.low_memory();
72 self_.fallback.low_memory();
73 self_.output.retain(|_, v| v.output_weak.strong_count() > 0);
74 }
75}
76impl<S: AnyConfig, F: AnyConfig> FallbackConfigReset for FallbackConfig<S, F> {
77 fn reset(&self, key: &ConfigKey) {
78 let mut self_ = self.0.lock();
79 self_.source.remove(key);
81 }
82
83 fn can_reset(&self, key: ConfigKey) -> Var<bool> {
84 let mut self_ = self.0.lock();
85 self_.source.contains_key(key)
86 }
87
88 fn clone_boxed(&self) -> Box<dyn FallbackConfigReset> {
89 Box::new(Self(self.0.clone()))
90 }
91}
92
93struct FallbackConfigData<S, F> {
94 source: S,
95 fallback: F,
96 output: HashMap<ConfigKey, OutputEntry>,
97}
98
99impl<S: AnyConfig, F: AnyConfig> FallbackConfigData<S, F> {
100 fn bind_raw(&mut self, key: ConfigKey, default: RawConfigValue, insert: bool) -> Var<RawConfigValue> {
101 if let Some(entry) = self.output.get(&key)
102 && let Some(output) = entry.output_weak.upgrade()
103 {
104 return output;
105 }
106
107 let fallback = self.fallback.get(key.clone(), default, false);
110 let source = self.source.get(key.clone(), fallback.get(), insert);
111 let source_contains = self.source.contains_key(key.clone());
112 let fallback_tag = fallback.var_instance_tag();
113
114 let output = var(if source_contains.get() { source.get() } else { fallback.get() });
115 let weak_output = output.downgrade();
116
117 let fallback_hook = fallback.hook(clmv!(weak_output, source_contains, |args| {
119 if let Some(output) = weak_output.upgrade() {
120 if !source_contains.get() {
121 let value = args.value().clone();
122 output.modify(move |o| {
123 o.set(value);
124 o.push_tag(fallback_tag);
125 });
126 }
127 true } else {
129 false }
131 }));
132
133 let source_hook = source.hook(clmv!(weak_output, |args| {
135 if let Some(output) = weak_output.upgrade() {
136 let output_tag = output.var_instance_tag();
137 if !args.contains_tag(&output_tag) {
138 output.set(args.value().clone());
139 }
140 true
141 } else {
142 false }
144 }));
145
146 let weak_fallback = fallback.downgrade(); let source_contains_hook = source_contains.hook(clmv!(weak_output, source, |args| {
150 if let Some(output) = weak_output.upgrade() {
151 if *args.value() {
152 output.set(source.get());
153 } else {
154 let fallback = weak_fallback.upgrade().unwrap();
155 let fallback_value = fallback.get();
156 let fallback_tag = fallback.var_instance_tag();
157 output.modify(move |o| {
158 o.set(fallback_value);
159 o.push_tag(fallback_tag);
160 });
161 }
162
163 true
164 } else {
165 false }
167 }));
168
169 let output_tag = output.var_instance_tag();
171 output
172 .hook(move |args| {
173 let _hold = (&fallback, &fallback_hook, &source_hook, &source_contains_hook);
174
175 if !args.contains_tag(&fallback_tag) {
176 let value = args.value().clone();
177 source.modify(move |s| {
178 s.set(value);
179 s.update(); s.push_tag(output_tag);
181 });
182 }
183 true
184 })
185 .perm();
186
187 self.output.insert(
188 key,
189 OutputEntry {
190 output_weak: output.downgrade(),
191 },
192 );
193
194 output
195 }
196}
197struct OutputEntry {
198 output_weak: WeakVar<RawConfigValue>,
199}