zng_var/var_impl/
shared_var.rs1use std::{
4 mem,
5 sync::{Arc, Weak},
6};
7
8use parking_lot::{Mutex, RwLock};
9use smallvec::SmallVec;
10
11use crate::{AnyVar, VARS, Var, VarUpdateId, VarValue, animation::ModifyInfo};
12
13use super::*;
14
15pub fn var<T: VarValue>(initial_value: T) -> Var<T> {
17 Var::new_any(any_var(BoxAnyVarValue::new(initial_value)))
18}
19
20pub fn var_derived<T: VarValue>(initial_value: T, source: &AnyVar) -> Var<T> {
25 Var::new_any(any_var_derived(BoxAnyVarValue::new(initial_value), source))
26}
27
28pub fn any_var(initial_value: BoxAnyVarValue) -> AnyVar {
30 AnyVar(DynAnyVar::Shared(SharedVar::new(
31 initial_value,
32 VarUpdateId::never(),
33 ModifyInfo::never(),
34 )))
35}
36
37pub fn any_var_derived(initial_value: BoxAnyVarValue, source: &AnyVar) -> AnyVar {
42 AnyVar(DynAnyVar::Shared(SharedVar::new(
43 initial_value,
44 source.0.last_update(),
45 source.0.modify_info(),
46 )))
47}
48
49pub fn var_state() -> Var<bool> {
54 var(false)
55}
56
57pub fn var_getter<T: VarValue + Default>() -> Var<T> {
63 var(T::default())
64}
65
66pub(super) struct VarData {
67 pub(super) value: RwLock<(BoxAnyVarValue, VarUpdateId, ModifyInfo)>,
68 hooks: MutexHooks,
69}
70
71#[derive(Clone)]
72pub(crate) struct SharedVar(pub(super) Arc<VarData>);
73impl fmt::Debug for SharedVar {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 let mut b = f.debug_struct("SharedVar");
76 b.field("var_instance_tag()", &Arc::as_ptr(&self.0));
77 b.field("strong_count()", &self.strong_count());
78
79 if let Some(value) = self.0.value.try_read() {
80 b.field("value", &value.0.detailed_debug());
81 b.field("last_update", &value.1);
82 b.field("modify_info", &value.2);
83 } else {
84 b.field("value", &"<locked>");
85 }
86
87 b.field("hooks", &self.0.hooks);
88
89 b.finish()
90 }
91}
92impl SharedVar {
93 pub(crate) fn new(value: BoxAnyVarValue, last_update: VarUpdateId, modify_info: ModifyInfo) -> Self {
94 Self(Arc::new(VarData {
95 value: RwLock::new((value, last_update, modify_info)),
96 hooks: MutexHooks::default(),
97 }))
98 }
99
100 pub(super) fn downgrade_typed(&self) -> WeakSharedVar {
101 WeakSharedVar(Arc::downgrade(&self.0))
102 }
103}
104impl PartialEq for SharedVar {
105 fn eq(&self, other: &Self) -> bool {
106 Arc::ptr_eq(&self.0, &other.0)
107 }
108}
109impl VarImpl for SharedVar {
110 fn clone_dyn(&self) -> DynAnyVar {
111 DynAnyVar::Shared(self.clone())
112 }
113
114 fn current_context(&self) -> DynAnyVar {
115 self.clone_dyn()
116 }
117
118 fn value_type(&self) -> TypeId {
119 self.0.value.read().0.type_id()
120 }
121
122 #[cfg(feature = "type_names")]
123 fn value_type_name(&self) -> &'static str {
124 let value = self.0.value.read();
125 value.0.type_name()
126 }
127
128 fn strong_count(&self) -> usize {
129 Arc::strong_count(&self.0)
130 }
131
132 fn var_eq(&self, other: &DynAnyVar) -> bool {
133 match other {
134 DynAnyVar::Shared(v) => self == v,
135 _ => false,
136 }
137 }
138
139 fn var_instance_tag(&self) -> VarInstanceTag {
140 VarInstanceTag(Arc::as_ptr(&self.0) as usize)
141 }
142
143 fn downgrade(&self) -> DynWeakAnyVar {
144 DynWeakAnyVar::Shared(self.downgrade_typed())
145 }
146
147 fn capabilities(&self) -> VarCapability {
148 VarCapability::NEW | VarCapability::MODIFY | VarCapability::SHARE
149 }
150
151 fn with(&self, visitor: &mut dyn FnMut(&dyn AnyVarValue)) {
152 let value = self.0.value.read();
153 visitor(&*value.0);
154 }
155
156 fn get(&self) -> BoxAnyVarValue {
157 self.0.value.read().0.clone_boxed()
158 }
159
160 fn set(&self, new_value: BoxAnyVarValue) -> bool {
161 self.modify_impl(ValueOrModify::Value(new_value));
162 true
163 }
164
165 fn update(&self) -> bool {
166 self.modify(smallbox!(|v: &mut AnyVarModify| {
167 v.update();
168 }))
169 }
170
171 fn modify(&self, modify: SmallBox<dyn FnMut(&mut AnyVarModify) + Send + 'static, smallbox::space::S4>) -> bool {
172 self.modify_impl(ValueOrModify::Modify(modify));
173 true
174 }
175
176 fn hook(&self, on_new: HookFn) -> VarHandle {
177 self.0.hooks.push(on_new)
178 }
179
180 fn last_update(&self) -> VarUpdateId {
181 self.0.value.read().1
182 }
183
184 fn modify_info(&self) -> ModifyInfo {
185 self.0.value.read().2.clone()
186 }
187
188 fn modify_importance(&self) -> usize {
189 self.0.value.read().2.importance()
190 }
191
192 fn is_animating(&self) -> bool {
193 self.0.value.read().2.is_animating()
194 }
195
196 fn hook_animation_stop(&self, handler: AnimationStopFn) -> VarHandle {
197 self.0.value.read().2.hook_animation_stop(handler)
198 }
199}
200impl SharedVar {
201 fn modify_impl(&self, value_or_modify: ValueOrModify) {
202 let name = value_type_name(self);
203 let var = self.clone();
204 VARS.schedule_update(name, move || {
206 let mut value = var.0.value.write();
207
208 let current_modify = VARS.current_modify();
210 if current_modify.importance() < value.2.importance() {
211 return;
212 }
213 value.2 = current_modify;
214
215 let mut m = AnyVarModify {
217 value: &mut value.0,
218 update: VarModifyUpdate::empty(),
219 tags: vec![],
220 custom_importance: None,
221 };
222 match value_or_modify {
223 ValueOrModify::Value(v) => {
224 m.set(v);
225 }
226 ValueOrModify::Modify(mut f) => (f)(&mut m),
227 }
228
229 let AnyVarModify {
230 update,
231 tags,
232 custom_importance,
233 ..
234 } = m;
235
236 if let Some(i) = custom_importance {
237 value.2.importance = i;
238 }
239
240 if update.contains(VarModifyUpdate::UPDATE) {
241 value.1 = VARS.update_id();
242
243 let value = parking_lot::RwLockWriteGuard::downgrade(value);
244 let args = AnyVarHookArgs::new(
245 var.var_instance_tag(),
246 &*value.0,
247 update.contains(VarModifyUpdate::REQUESTED),
248 &tags,
249 );
250 var.0.hooks.notify(&args);
251 }
252 });
253 }
254}
255enum ValueOrModify {
258 Value(BoxAnyVarValue),
259 Modify(SmallBox<dyn FnMut(&mut AnyVarModify) + Send + 'static, smallbox::space::S4>),
260}
261
262#[derive(Clone)]
263pub(crate) struct WeakSharedVar(Weak<VarData>);
264impl fmt::Debug for WeakSharedVar {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 f.debug_tuple("WeakSharedVar").field(&self.0.as_ptr()).finish()
267 }
268}
269impl WeakSharedVar {
270 pub(super) fn upgrade_typed(&self) -> Option<SharedVar> {
271 self.0.upgrade().map(SharedVar)
272 }
273}
274impl WeakVarImpl for WeakSharedVar {
275 fn clone_dyn(&self) -> DynWeakAnyVar {
276 DynWeakAnyVar::Shared(self.clone())
277 }
278
279 fn strong_count(&self) -> usize {
280 self.0.strong_count()
281 }
282
283 fn upgrade(&self) -> Option<DynAnyVar> {
284 Some(DynAnyVar::Shared(self.upgrade_typed()?))
285 }
286}
287
288#[derive(Default)]
289pub(super) struct MutexHooks {
290 h: Mutex<SmallVec<[(HookFn, VarHandlerOwner); 1]>>,
291}
292impl MutexHooks {
293 pub fn push(&self, on_new: HookFn) -> VarHandle {
294 let (owner, handle) = VarHandle::new();
295 self.h.lock().push((on_new, owner));
296 handle
297 }
298
299 pub fn notify(&self, args: &AnyVarHookArgs) {
300 let mut hooks = mem::take(&mut *self.h.lock());
301
302 hooks.retain(|(f, handle)| handle.is_alive() && f(args));
303
304 if !hooks.is_empty() {
305 let mut hs = self.h.lock();
306 if hs.capacity() > hooks.capacity() {
307 hs.append(&mut hooks);
308 } else {
309 hooks.append(&mut *hs);
310 *hs = hooks;
311 }
312 }
313 }
314}
315impl fmt::Debug for MutexHooks {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 if let Some(h) = self.h.try_lock() {
318 let mut b = f.debug_list();
319 for (_, h) in h.iter() {
320 b.entry(h);
321 }
322 b.finish()
323 } else {
324 write!(f, "<locked>")
325 }
326 }
327}
328
329pub(super) type HookFn = SmallBox<dyn FnMut(&AnyVarHookArgs) -> bool + Send + 'static, smallbox::space::S4>;