zng_var/
var_any.rs

1use core::fmt;
2use std::{
3    any::{Any, TypeId},
4    borrow::Cow,
5    marker::PhantomData,
6    mem,
7    sync::Arc,
8};
9
10use parking_lot::Mutex;
11use smallbox::{SmallBox, smallbox};
12use zng_clone_move::clmv;
13use zng_txt::{Txt, formatx};
14
15use crate::{
16    AnyVarModify, AnyVarValue, BoxAnyVarValue, VARS, Var, VarCapability, VarHandle, VarHandles, VarImpl, VarIsReadOnlyError, VarModify,
17    VarModifyUpdate, VarUpdateId, VarValue, WeakVarImpl,
18    animation::{Animation, AnimationController, AnimationHandle, AnimationStopFn},
19    any_contextual_var,
20};
21
22/// Variable of any type.
23pub struct AnyVar(pub(crate) crate::var_impl::DynAnyVar);
24impl Clone for AnyVar {
25    fn clone(&self) -> Self {
26        Self(self.0.clone_dyn())
27    }
28}
29impl fmt::Debug for AnyVar {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        f.debug_tuple("AnyVar").field(&self.0).finish()
32    }
33}
34/// Value.
35impl AnyVar {
36    /// Visit a reference to the current value.
37    pub fn with<O>(&self, visitor: impl FnOnce(&dyn AnyVarValue) -> O) -> O {
38        let mut once = Some(visitor);
39        let mut output = None;
40        self.0.with(&mut |v| {
41            output = Some(once.take().unwrap()(v));
42        });
43        output.unwrap()
44    }
45
46    /// Get a clone of the current value.
47    pub fn get(&self) -> BoxAnyVarValue {
48        self.0.get()
49    }
50
51    /// Debug format the current value.
52    pub fn get_debug(&self, alternate: bool) -> Txt {
53        let mut r = Txt::default();
54        self.0.with(&mut |v| {
55            r = if alternate { formatx!("{v:#?}") } else { formatx!("{v:?}") };
56        });
57        r
58    }
59
60    /// Gets if the value updated.
61    ///
62    /// Returns `true` if the [`last_update`] is the current one. Note that this will only work reliably in
63    /// UI code that is synchronized with app updates, prefer [`wait_update`] in async code.
64    ///
65    /// [`last_update`]: Self::last_update
66    /// [`wait_update`]: Self::wait_update
67    pub fn is_new(&self) -> bool {
68        self.last_update() == VARS.update_id()
69    }
70
71    /// Gets a clone of the current value if it [`is_new`].
72    ///
73    /// [`is_new`]: Self::is_new
74    pub fn get_new(&self) -> Option<BoxAnyVarValue> {
75        if self.is_new() { Some(self.get()) } else { None }
76    }
77
78    /// Visit a reference to the current value if it [`is_new`].
79    ///
80    /// [`is_new`]: Self::is_new
81    pub fn with_new<O>(&self, visitor: impl FnOnce(&dyn AnyVarValue) -> O) -> Option<O> {
82        if self.is_new() { Some(self.with(visitor)) } else { None }
83    }
84
85    /// Schedule `new_value` to be assigned next update, if the variable is not read-only.
86    ///
87    /// Panics if the value type does not match.
88    pub fn try_set(&self, new_value: BoxAnyVarValue) -> Result<(), VarIsReadOnlyError> {
89        if new_value.type_id() != self.value_type() {
90            #[cfg(feature = "type_names")]
91            panic!(
92                "cannot set `{}` on variable of type `{}`",
93                new_value.type_name(),
94                self.value_type_name()
95            );
96            #[cfg(not(feature = "type_names"))]
97            panic!("cannot set variable, type mismatch");
98        }
99        self.handle_modify(self.0.set(new_value))
100    }
101
102    /// Schedule `new_value` to be assigned next update.
103    ///
104    /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
105    /// Use [`try_set`] to get an error for read-only vars.
106    ///
107    /// [`try_set`]: Self::try_set
108    pub fn set(&self, new_value: BoxAnyVarValue) {
109        trace_debug_error!(self.try_set(new_value))
110    }
111
112    /// Schedule an update notification, without actually changing the value, if the variable is not read-only.
113    pub fn try_update(&self) -> Result<(), VarIsReadOnlyError> {
114        self.handle_modify(self.0.update())
115    }
116
117    /// Show variable value as new next update, without actually changing the value.
118    ///
119    /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
120    /// Use [`try_update`] to get an error for read-only vars.
121    ///
122    /// [`try_update`]: Self::try_set
123    pub fn update(&self) {
124        trace_debug_error!(self.try_update())
125    }
126
127    /// Schedule `modify` to be called on the value for the next update, if the variable is not read-only.
128    ///
129    /// If the [`AnyVarModify`] closure input is deref_mut the variable will notify an update.
130    pub fn try_modify(&self, modify: impl FnOnce(&mut AnyVarModify) + Send + 'static) -> Result<(), VarIsReadOnlyError> {
131        // can't have a SmallBox<dyn FnOnce> because Rust has special compiler magic for Box<dyn FnOnce>,
132        // so we wrap in an Option and FnMut that is only called once.
133        let mut modify = Some(modify);
134        let modify = move |value: &mut AnyVarModify| {
135            #[cfg(debug_assertions)]
136            let type_id = (&*value.value as &dyn Any).type_id();
137
138            modify.take().unwrap()(value);
139
140            #[cfg(debug_assertions)]
141            if !value.update.is_empty() {
142                assert_eq!((&*value.value as &dyn Any).type_id(), type_id, "AnyVar::modify changed value type");
143            }
144        };
145
146        self.handle_modify(self.0.modify(smallbox!(modify)))
147    }
148
149    /// Schedule `modify` to be called on the value for the next update, if the variable is not read-only.
150    ///
151    /// If the [`AnyVarModify`] closure input is deref_mut the variable will notify an update.
152    ///
153    /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
154    /// Use [`try_modify`] to get an error for read-only vars.
155    ///
156    /// [`try_modify`]: Self::try_modify
157    pub fn modify(&self, modify: impl FnOnce(&mut AnyVarModify) + Send + 'static) {
158        trace_debug_error!(self.try_modify(modify))
159    }
160
161    /// Schedule a new `value` for the variable, it will be set in the end of the current app update to the updated
162    /// value of `other`, so if the other var has already scheduled an update, the updated value will be used.
163    ///  
164    /// This can be used just before creating a binding to start with synchronized values.
165    pub fn try_set_from(&self, other: &AnyVar) -> Result<(), VarIsReadOnlyError> {
166        let other = other.current_context();
167        if other.capabilities().is_const() {
168            self.try_set(other.get())
169        } else if self.capabilities().is_read_only() {
170            Err(VarIsReadOnlyError {})
171        } else {
172            let weak_other = other.downgrade();
173            self.try_modify(move |v| {
174                if let Some(other) = weak_other.upgrade() {
175                    other.with(|ov| {
176                        if *ov != **v {
177                            // only clone if really changed
178                            let mut new_value = ov.clone_boxed();
179                            assert!(v.try_swap(&mut *new_value), "set_from other var not of the same type");
180
181                            // tag for bidi bindings
182                            v.push_tag(other.var_instance_tag());
183                        }
184                        // don't break animation of this if other just started animating after the `set_from` request was scheduled
185                        v.set_modify_importance(other.modify_importance());
186                    });
187                }
188            })
189        }
190    }
191
192    /// Schedule a new `value` for the variable, it will be set in the end of the current app update to the updated
193    /// value of `other`, so if the other var has already scheduled an update, the updated value will be used.
194    ///  
195    /// This can be used just before creating a binding to start with synchronized values.
196    ///
197    /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
198    /// Use [`try_set_from`] to get an error for read-only vars.
199    ///
200    /// [`try_set_from`]: Self::try_set_from
201    pub fn set_from(&self, other: &AnyVar) {
202        trace_debug_error!(self.try_set_from(other))
203    }
204
205    /// Like [`try_set_from`], but uses `map` to produce the new value from the updated value of `other`.
206    ///
207    /// [`try_set_from`]: Self::try_set_from
208    pub fn try_set_from_map(
209        &self,
210        other: &AnyVar,
211        map: impl FnOnce(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
212    ) -> Result<(), VarIsReadOnlyError> {
213        if other.capabilities().is_const() {
214            self.try_set(other.get())
215        } else if self.capabilities().is_read_only() {
216            Err(VarIsReadOnlyError {})
217        } else {
218            let weak_other = other.downgrade();
219            self.try_modify(move |v| {
220                if let Some(other) = weak_other.upgrade() {
221                    other.with(|ov| {
222                        let new_value = map(ov);
223                        if v.set(new_value) {
224                            // tag for bidi bindings
225                            v.push_tag(other.var_instance_tag());
226                        }
227                        // don't break animation of this if other just started animating after the `set_from` request was scheduled
228                        v.set_modify_importance(other.modify_importance());
229                    });
230                }
231            })
232        }
233    }
234
235    /// Like [`set_from`], but uses `map` to produce the new value from the updated value of `other`.
236    ///
237    /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
238    /// Use [`try_set_from_map`] to get an error for read-only vars.
239    ///
240    /// [`try_set_from_map`]: Self::try_set_from_map
241    /// [`set_from`]: Self::set_from
242    pub fn set_from_map(&self, other: &AnyVar, map: impl FnOnce(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static) {
243        trace_debug_error!(self.try_set_from_map(other, map))
244    }
245
246    /// Setups a callback for just after the variable value update is applied, the closure runs in the root app context, just like
247    /// the `modify` closure. The closure must return `true` to be retained and `false` to be dropped.
248    ///
249    /// If you modify another variable in the closure modification applies in the same update, variable mapping and
250    /// binding is implemented using hooks.
251    ///
252    /// The variable store a weak reference to the callback if it has the `MODIFY` or `CAPS_CHANGE` capabilities, otherwise
253    /// the callback is discarded and [`VarHandle::dummy`] returned.
254    pub fn hook(&self, on_update: impl FnMut(&AnyVarHookArgs) -> bool + Send + 'static) -> VarHandle {
255        self.0.hook(smallbox!(on_update))
256    }
257
258    ///Awaits for a value that passes the `predicate`, including the current value.
259    #[allow(clippy::manual_async_fn)] // false positive, async fn futures are not Send + Sync
260    pub fn wait_match(&self, predicate: impl Fn(&dyn AnyVarValue) -> bool + Send + Sync) -> impl Future<Output = ()> + Send + Sync {
261        async move {
262            while !self.with(&predicate) {
263                let future = self.wait_update();
264                if self.with(&predicate) {
265                    break;
266                }
267                future.await;
268            }
269        }
270    }
271
272    /// Awaits for an update them [`get`] the value.
273    ///
274    /// [`get`]: Self::get
275    #[allow(clippy::manual_async_fn)] // false positive, async fn futures are not Send + Sync
276    pub fn wait_next(&self) -> impl Future<Output = BoxAnyVarValue> + Send + Sync {
277        async {
278            self.wait_update().await;
279            self.get()
280        }
281    }
282
283    /// Last update ID a variable was modified.
284    ///
285    /// If the ID equals [`VARS.update_id`] the variable [`is_new`].
286    ///
287    /// [`is_new`]: Self::is_new
288    /// [`VARS.update_id`]: VARS::update_id
289    pub fn last_update(&self) -> VarUpdateId {
290        self.0.last_update()
291    }
292
293    /// Awaits for the [`last_update`] to change.
294    ///
295    /// Note that [`is_new`] will be `true` when the future elapses only when polled
296    /// in sync with the UI, but it will elapse in any thread when the variable updates after the future is instantiated.
297    ///
298    /// Note that outside of the UI tree there is no variable synchronization across multiple var method calls, so
299    /// a sequence of `get(); wait_update().await; get();` can miss a value between `get` and `wait_update`. The returned
300    /// future captures the [`last_update`] at the moment this method is called, this can be leveraged by double-checking to
301    /// avoid race conditions, see the [`wait_match`] default implementation for more details.
302    ///
303    /// [`wait_match`]: Self::wait_match
304    /// [`last_update`]: Self::last_update
305    /// [`is_new`]: Self::is_new
306    pub fn wait_update(&self) -> impl Future<Output = VarUpdateId> + Send + Sync {
307        crate::future::WaitUpdateFut::new(self)
308    }
309
310    /// Debug helper for tracing the lifetime of a value in this variable.
311    ///
312    /// See [`trace_value`] for more details.
313    ///
314    /// [`trace_value`]: Var::trace_value
315    pub fn trace_value<S: Send + 'static>(&self, mut enter_value: impl FnMut(&AnyVarHookArgs) -> S + Send + 'static) -> VarHandle {
316        let span = self.with(|v| {
317            enter_value(&AnyVarHookArgs {
318                var_instance_tag: self.var_instance_tag(),
319                value: v,
320                update: false,
321                tags: &[],
322            })
323        });
324        let mut span = Some(span);
325        self.hook(move |v| {
326            let _ = span.take();
327            span = Some(enter_value(v));
328            true
329        })
330    }
331
332    fn handle_modify(&self, scheduled: bool) -> Result<(), VarIsReadOnlyError> {
333        match scheduled {
334            true => Ok(()),
335            false => Err(VarIsReadOnlyError {}),
336        }
337    }
338}
339/// Value mapping.
340impl AnyVar {
341    /// Create a mapping variable from any to any.
342    ///
343    /// The `map` closure must only output values of `value_type`, this type is validated in debug builds and
344    /// is necessary for contextualizing variables.
345    ///
346    /// See [`map`] for more details about mapping variables.
347    ///
348    /// [`map`]: Var::map
349    pub fn map_any(&self, map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static, value_type: TypeId) -> AnyVar {
350        let caps = self.capabilities();
351
352        #[cfg(debug_assertions)]
353        let map = {
354            let mut map = map;
355            move |v: &dyn AnyVarValue| {
356                let output = map(v);
357                assert_eq!(value_type, output.type_id(), "map_any value type does not match");
358                output
359            }
360        };
361
362        if caps.is_contextual() {
363            let me = self.clone();
364            let map = Arc::new(Mutex::new(map));
365            // clone again inside the context to get a new clear (me as contextual_var)
366            return any_contextual_var(
367                move || me.clone().map_any_tail(clmv!(map, |v| map.lock()(v)), me.capabilities()),
368                value_type,
369            );
370        }
371        self.map_any_tail(map, caps)
372    }
373    // to avoid infinite closure type (contextual case)
374    fn map_any_tail(&self, mut map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static, caps: VarCapability) -> AnyVar {
375        let me = self.current_context();
376
377        let mut init_value = None;
378        me.with(&mut |v: &dyn AnyVarValue| init_value = Some(map(v)));
379        let init_value = init_value.unwrap();
380
381        if caps.is_const() {
382            return crate::any_const_var(init_value);
383        }
384
385        let output = crate::any_var_derived(init_value, &me);
386        me.bind_impl(&output, map).perm();
387        output.hold(me).perm();
388
389        output.read_only()
390    }
391
392    /// Create a strongly typed mapping variable.
393    ///
394    /// The `map` closure must produce a strongly typed value for every update of this variable.
395    ///
396    /// See [`map`] for more details about mapping variables.
397    ///
398    /// [`map`]: Var::map
399    pub fn map<O: VarValue>(&self, mut map: impl FnMut(&dyn AnyVarValue) -> O + Send + 'static) -> Var<O> {
400        let mapping = self.map_any(move |v| BoxAnyVarValue::new(map(v)), TypeId::of::<O>());
401        Var::new_any(mapping)
402    }
403
404    /// Create a mapping variable that contains the debug formatted value from this variable.
405    ///
406    /// See [`map`] for more details about mapping variables.
407    ///
408    /// [`map`]: Var::map
409    pub fn map_debug(&self, alternate: bool) -> Var<Txt> {
410        if alternate {
411            self.map(|v| formatx!("{v:#?}"))
412        } else {
413            self.map(|v| formatx!("{v:?}"))
414        }
415    }
416
417    /// Create a mapping variable that can skip updates.
418    ///
419    /// The `map` closure is called for every update this variable and if it returns a new value the mapping variable updates.
420    ///
421    /// If the `map` closure does not produce a value on init the `fallback_init` closure is called.
422    ///
423    /// See [`filter_map`] for more details about mapping variables.
424    ///
425    /// [`filter_map`]: Var::filter_map
426    pub fn filter_map_any(
427        &self,
428        map: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
429        fallback_init: impl Fn() -> BoxAnyVarValue + Send + 'static,
430        value_type: TypeId,
431    ) -> AnyVar {
432        let caps = self.capabilities();
433
434        if caps.is_contextual() {
435            let me = self.clone();
436            let fns = Arc::new(Mutex::new((map, fallback_init)));
437            return any_contextual_var(
438                move || {
439                    me.clone()
440                        .filter_map_any_tail(clmv!(fns, |v| fns.lock().0(v)), clmv!(fns, || fns.lock().1()), me.capabilities())
441                },
442                value_type,
443            );
444        }
445
446        self.filter_map_any_tail(map, fallback_init, caps)
447    }
448    // to avoid infinite closure type (contextual case)
449    fn filter_map_any_tail(
450        &self,
451        mut map: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
452        fallback_init: impl Fn() -> BoxAnyVarValue + Send + 'static,
453        caps: VarCapability,
454    ) -> AnyVar {
455        let me = self.current_context();
456
457        let mut init_value = None;
458        me.with(&mut |v: &dyn AnyVarValue| init_value = map(v));
459        let init_value = match init_value {
460            Some(v) => v,
461            None => fallback_init(),
462        };
463
464        if caps.is_const() {
465            return crate::any_const_var(init_value);
466        }
467
468        let output = crate::any_var_derived(init_value, &me);
469        let weak_output = output.downgrade();
470
471        me.hook(move |args| {
472            match weak_output.upgrade() {
473                Some(o) => {
474                    if let Some(new_value) = map(args.value) {
475                        o.set(new_value);
476                    }
477                    true
478                }
479                None => {
480                    // don't retain, output var dropped
481                    false
482                }
483            }
484        })
485        .perm();
486        output.hold(me).perm();
487
488        output.read_only()
489    }
490
491    /// Create a strongly typed mapping variable that can skip updates.
492    ///
493    /// The `map` closure is called for every update this variable and if it returns a new value the mapping variable updates.
494    ///
495    /// If the `map` closure does not produce a value on init the `fallback_init` closure is called.
496    ///
497    /// See [`filter_map`] for more details about mapping variables.
498    ///
499    /// [`filter_map`]: Var::filter_map
500    pub fn filter_map<O: VarValue>(
501        &self,
502        mut map: impl FnMut(&dyn AnyVarValue) -> Option<O> + Send + 'static,
503        fallback_init: impl Fn() -> O + Send + 'static,
504    ) -> Var<O> {
505        let mapping = self.filter_map_any(
506            move |v| map(v).map(BoxAnyVarValue::new),
507            move || BoxAnyVarValue::new(fallback_init()),
508            TypeId::of::<O>(),
509        );
510        Var::new_any(mapping)
511    }
512
513    /// Create a bidirectional mapping variable.
514    ///
515    /// The `map` closure must only output values of `value_type`, predefining this type is
516    /// is necessary for contextualizing variables.
517    ///
518    /// The `map_back` closure must produce values of the same type as this variable, this variable will panic
519    /// if map back value is not the same.
520    ///
521    /// See [`map_bidi`] for more details about bidirectional mapping variables.
522    ///
523    /// [`map_bidi`]: Var::map_bidi
524    pub fn map_bidi_any(
525        &self,
526        map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
527        map_back: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
528        value_type: TypeId,
529    ) -> AnyVar {
530        let caps = self.capabilities();
531
532        if caps.is_contextual() {
533            let me = self.clone();
534            let fns = Arc::new(Mutex::new((map, map_back)));
535            return any_contextual_var(
536                move || {
537                    me.clone()
538                        .map_bidi_tail(clmv!(fns, |v| fns.lock().0(v)), clmv!(fns, |v| fns.lock().1(v)), caps)
539                },
540                value_type,
541            );
542        }
543
544        self.map_bidi_tail(map, map_back, caps)
545    }
546    fn map_bidi_tail(
547        &self,
548        mut map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
549        map_back: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
550        caps: VarCapability,
551    ) -> AnyVar {
552        let me = self.current_context();
553
554        let mut init_value = None;
555        me.with(&mut |v: &dyn AnyVarValue| init_value = Some(map(v)));
556        let init_value = init_value.unwrap();
557
558        if caps.is_const() {
559            return crate::any_const_var(init_value);
560        }
561
562        let output = crate::any_var_derived(init_value, &me);
563
564        me.bind_map_bidi_any(&output, map, map_back).perm();
565        output.hold(me).perm();
566
567        output
568    }
569
570    /// Create a bidirectional mapping variable that modifies the source variable on change, instead of mapping back.
571    ///
572    /// The `map` closure must only output values of `value_type`, predefining this type is
573    /// is necessary for contextualizing variables.
574    ///
575    /// The `modify_back` closure is called to modify the source variable with the new output value.
576    ///
577    /// See [`map_bidi_modify`] for more details about bidirectional mapping variables.
578    ///
579    /// [`map_bidi_modify`]: Var::map_bidi_modify
580    pub fn map_bidi_modify_any(
581        &self,
582        map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
583        modify_back: impl FnMut(&dyn AnyVarValue, &mut AnyVarModify) + Send + 'static,
584        value_type: TypeId,
585    ) -> AnyVar {
586        let caps = self.capabilities();
587
588        if caps.is_contextual() {
589            let me = self.clone();
590            let fns = Arc::new(Mutex::new((map, modify_back)));
591            return any_contextual_var(
592                move || {
593                    me.clone()
594                        .map_bidi_modify_tail(clmv!(fns, |v| fns.lock().0(v)), clmv!(fns, |v, m| fns.lock().1(v, m)), caps)
595                },
596                value_type,
597            );
598        }
599        self.map_bidi_modify_tail(map, modify_back, caps)
600    }
601    fn map_bidi_modify_tail(
602        &self,
603        mut map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
604        modify_back: impl FnMut(&dyn AnyVarValue, &mut AnyVarModify) + Send + 'static,
605        caps: VarCapability,
606    ) -> AnyVar {
607        let me = self.current_context();
608
609        let mut init_value = None;
610        me.with(&mut |v: &dyn AnyVarValue| init_value = Some(map(v)));
611        let init_value = init_value.unwrap();
612
613        if caps.is_const() {
614            return crate::any_const_var(init_value);
615        }
616
617        let output = crate::any_var_derived(init_value, &me);
618        self.bind_map_any(&output, map).perm();
619        output.bind_modify_any(&me, modify_back).perm();
620        output.hold(me).perm();
621        output
622    }
623
624    /// Create a bidirectional mapping variable that can skip updates.
625    ///
626    /// The `map` closure must only output values of `value_type`, predefining this type is
627    /// is necessary for contextualizing variables.
628    ///
629    /// The `map_back` closure must produce values of the same type as this variable, this variable will panic
630    /// if map back value is not the same.
631    ///
632    /// See [`filter_map_bidi`] for more details about bidirectional mapping variables.
633    ///
634    /// [`filter_map_bidi`]: Var::filter_map_bidi
635    pub fn filter_map_bidi_any(
636        &self,
637        map: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
638        map_back: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
639        fallback_init: impl Fn() -> BoxAnyVarValue + Send + 'static,
640        value_type: TypeId,
641    ) -> AnyVar {
642        let caps = self.capabilities();
643
644        if caps.is_contextual() {
645            let me = self.clone();
646            let fns = Arc::new(Mutex::new((map, map_back, fallback_init)));
647            return any_contextual_var(
648                move || {
649                    me.clone().filter_map_bidi_tail(
650                        clmv!(fns, |v| fns.lock().0(v)),
651                        clmv!(fns, |v| fns.lock().1(v)),
652                        clmv!(fns, || fns.lock().2()),
653                        caps,
654                    )
655                },
656                value_type,
657            );
658        }
659
660        self.filter_map_bidi_tail(map, map_back, fallback_init, caps)
661    }
662    fn filter_map_bidi_tail(
663        &self,
664        mut map: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
665        map_back: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
666        fallback_init: impl Fn() -> BoxAnyVarValue + Send + 'static,
667        caps: VarCapability,
668    ) -> AnyVar {
669        let me = self.current_context();
670
671        let mut init_value = None;
672        me.with(&mut |v: &dyn AnyVarValue| init_value = map(v));
673        let init_value = init_value.unwrap_or_else(&fallback_init);
674
675        if caps.is_const() {
676            return crate::any_const_var(init_value);
677        }
678
679        let output = crate::any_var_derived(init_value, &me);
680
681        me.bind_filter_map_bidi_any(&output, map, map_back).perm();
682        output.hold(me).perm();
683
684        output
685    }
686
687    /// Create a mapping variable from any to any that *unwraps* an inner variable.
688    ///
689    /// See [`flat_map`] for more details about flat mapping variables.
690    ///
691    /// [`flat_map`]: Var::flat_map
692    pub fn flat_map_any(&self, map: impl FnMut(&dyn AnyVarValue) -> AnyVar + Send + 'static, value_type: TypeId) -> AnyVar {
693        let caps = self.capabilities();
694
695        if caps.is_contextual() {
696            let me = self.clone();
697            let map = Arc::new(Mutex::new(map));
698            return any_contextual_var(
699                move || me.clone().flat_map_tail(clmv!(map, |v| map.lock()(v)), me.capabilities()),
700                value_type,
701            );
702        }
703
704        self.flat_map_tail(map, caps)
705    }
706    fn flat_map_tail(&self, map: impl FnMut(&dyn AnyVarValue) -> AnyVar + Send + 'static, caps: VarCapability) -> AnyVar {
707        if caps.is_const() {
708            return self.with(map);
709        }
710        let me = self.current_context();
711        let mapping = crate::var_impl::flat_map_var::FlatMapVar::new(me, smallbox!(map));
712        AnyVar(crate::DynAnyVar::FlatMap(mapping))
713    }
714
715    /// Create a strongly typed flat mapping variable.
716    ///
717    /// See [`flat_map`] for more details about mapping variables.
718    ///
719    /// [`flat_map`]: Var::flat_map
720    pub fn flat_map<O: VarValue>(&self, mut map: impl FnMut(&dyn AnyVarValue) -> Var<O> + Send + 'static) -> Var<O> {
721        let mapping = self.flat_map_any(
722            move |v| {
723                let typed = map(v);
724                typed.into()
725            },
726            TypeId::of::<O>(),
727        );
728        Var::new_any(mapping)
729    }
730}
731/// Binding
732impl AnyVar {
733    /// Bind `other` to receive the new values from this variable.
734    ///
735    /// See [`bind`] for more details about variable bindings.
736    ///
737    /// [`bind`]: Var::bind
738    pub fn bind(&self, other: &AnyVar) -> VarHandle {
739        self.bind_map_any(other, |v| v.clone_boxed())
740    }
741
742    /// Like [`bind`] but also sets `other` to the current value.
743    ///
744    /// See [`set_bind`] for more details.
745    ///
746    /// [`bind`]: Self::bind
747    /// [`set_bind`]: Var::set_bind
748    pub fn set_bind(&self, other: &AnyVar) -> VarHandle {
749        other.set_from(self);
750        self.bind(other)
751    }
752
753    /// Bind `other` to receive the new values mapped from this variable.
754    ///
755    /// See [`bind_map`] for more details about variable bindings.
756    ///
757    /// [`bind_map`]: Var::bind_map
758    pub fn bind_map_any(&self, other: &AnyVar, map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static) -> VarHandle {
759        let other_caps = other.capabilities();
760        if self.capabilities().is_const() || other_caps.is_always_read_only() {
761            return VarHandle::dummy();
762        }
763
764        if other_caps.is_contextual() {
765            self.bind_impl(&other.current_context(), map)
766        } else {
767            self.bind_impl(other, map)
768        }
769    }
770
771    /// Bind `other` to be modified when this variable updates.
772    ///
773    /// See [`bind_modify`] for more details about modify bindings.
774    ///
775    /// [`bind_modify`]: Var::bind_modify
776    pub fn bind_modify_any(&self, other: &AnyVar, modify: impl FnMut(&dyn AnyVarValue, &mut AnyVarModify) + Send + 'static) -> VarHandle {
777        let self_caps = other.capabilities();
778        let other_caps = other.capabilities();
779        if self_caps.is_const() || other_caps.is_always_read_only() {
780            return VarHandle::dummy();
781        }
782
783        let mut source = Cow::Borrowed(self);
784        if self_caps.is_contextual() {
785            source = Cow::Owned(self.current_context());
786        }
787
788        if other_caps.is_contextual() {
789            source.bind_modify_impl(&other.current_context(), modify)
790        } else {
791            source.bind_modify_impl(other, modify)
792        }
793    }
794
795    /// Like [`bind_map_any`] but also sets `other` to the current value.
796    ///
797    /// See [`set_bind_map`] for more details.
798    ///
799    /// [`bind_map_any`]: Self::bind_map_any
800    /// [`set_bind_map`]: Var::set_bind_map
801    pub fn set_bind_map_any(&self, other: &AnyVar, map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static) -> VarHandle {
802        let map = Arc::new(Mutex::new(map));
803        other.set_from_map(self, clmv!(map, |v| map.lock()(v)));
804
805        enum MapFn<F> {
806            Hot(F),
807            Cold(Arc<Mutex<F>>),
808            Taken,
809        }
810        let mut map = MapFn::Cold(map);
811        self.bind_map_any(other, move |v| match mem::replace(&mut map, MapFn::Taken) {
812            MapFn::Hot(mut f) => {
813                let r = f(v);
814                map = MapFn::Hot(f);
815                r
816            }
817            MapFn::Cold(f) => match Arc::try_unwrap(f) {
818                Ok(f) => {
819                    let mut f = f.into_inner();
820                    let r = f(v);
821                    map = MapFn::Hot(f);
822                    r
823                }
824                Err(f) => {
825                    let r = f.lock()(v);
826                    map = MapFn::Cold(f);
827                    r
828                }
829            },
830            MapFn::Taken => unreachable!(),
831        })
832    }
833
834    /// Bind strongly typed `other` to receive the new values mapped from this variable.
835    ///
836    /// See [`bind_map`] for more details about variable bindings.
837    ///
838    /// [`bind_map`]: Var::bind_map
839    pub fn bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&dyn AnyVarValue) -> O + Send + 'static) -> VarHandle {
840        self.bind_map_any(other, move |v| BoxAnyVarValue::new(map(v)))
841    }
842
843    /// Bind `other` to be modified when this variable updates.
844    ///
845    /// See [`bind_modify`] for more details about modify bindings.
846    ///
847    /// [`bind_modify`]: Var::bind_modify
848    pub fn bind_modify<O: VarValue>(
849        &self,
850        other: &Var<O>,
851        mut modify: impl FnMut(&dyn AnyVarValue, &mut VarModify<O>) + Send + 'static,
852    ) -> VarHandle {
853        self.bind_modify_any(other, move |v, m| modify(v, &mut m.downcast::<O>().unwrap()))
854    }
855
856    /// Like [`bind_map_any`] but also sets `other` to the current value.
857    ///
858    /// See [`set_bind_map`] for more details.
859    ///
860    /// [`bind_map_any`]: Self::bind_map_any
861    /// [`set_bind_map`]: Var::set_bind_map
862    pub fn set_bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&dyn AnyVarValue) -> O + Send + 'static) -> VarHandle {
863        self.set_bind_map_any(other, move |v| BoxAnyVarValue::new(map(v)))
864    }
865
866    /// Bind `other` to receive the new values from this variable and this variable to receive new values from `other`.
867    ///
868    /// See [`bind_bidi`] for more details about variable bindings.
869    ///
870    /// [`bind_bidi`]: Var::bind_bidi
871    pub fn bind_bidi(&self, other: &AnyVar) -> VarHandles {
872        self.bind_map_bidi_any(other, |v| v.clone_boxed(), |v| v.clone_boxed())
873    }
874
875    /// Bind `other` to receive the new mapped values from this variable and this variable to receive new mapped values from `other`.
876    ///
877    /// See [`bind_bidi`] for more details about variable bindings.
878    ///
879    /// [`bind_bidi`]: Var::bind_bidi
880    pub fn bind_map_bidi_any(
881        &self,
882        other: &AnyVar,
883        map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
884        map_back: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static,
885    ) -> VarHandles {
886        assert!(!self.var_eq(other), "cannot bind var to itself");
887
888        let self_cap = self.capabilities();
889        let other_cap = other.capabilities();
890        if self_cap.is_const() || other_cap.is_const() {
891            return VarHandles::dummy();
892        }
893        if self_cap.is_always_read_only() {
894            return self.bind_map_any(other, map).into();
895        }
896        if other_cap.is_always_read_only() {
897            return other.bind_map_any(self, map_back).into();
898        }
899
900        let a = if other_cap.is_contextual() {
901            self.bind_impl(&other.current_context(), map)
902        } else {
903            self.bind_impl(other, map)
904        };
905        let b = if self_cap.is_contextual() {
906            other.bind_impl(&self.current_context(), map_back)
907        } else {
908            other.bind_impl(self, map_back)
909        };
910
911        a.chain(b)
912    }
913
914    /// Bind `other` to be modified when this variable updates and this variable to be modified when `other` updates.
915    ///
916    /// See [`bind_modify_bidi`] for more details about modify bindings.
917    ///
918    /// [`bind_modify_bidi`]: Var::bind_modify_bidi
919    pub fn bind_modify_bidi_any(
920        &self,
921        other: &AnyVar,
922        modify: impl FnMut(&dyn AnyVarValue, &mut AnyVarModify) + Send + 'static,
923        modify_back: impl FnMut(&dyn AnyVarValue, &mut AnyVarModify) + Send + 'static,
924    ) -> VarHandles {
925        let self_cap = self.capabilities();
926        let other_cap = other.capabilities();
927        if self_cap.is_const() || other_cap.is_const() {
928            return VarHandles::dummy();
929        }
930        if self_cap.is_always_read_only() {
931            return self.bind_modify_any(other, modify).into();
932        }
933        if other_cap.is_always_read_only() {
934            return other.bind_modify_any(self, modify_back).into();
935        }
936
937        let mut self_ = Cow::Borrowed(self);
938        if self_cap.is_contextual() {
939            self_ = Cow::Owned(self.current_context());
940        }
941
942        let a = if other_cap.is_contextual() {
943            self_.bind_modify_impl(&other.current_context(), modify)
944        } else {
945            self_.bind_modify_impl(other, modify)
946        };
947        let b = other.bind_modify_impl(&self_, modify_back);
948
949        a.chain(b)
950    }
951
952    /// Bind `other` to be modified when this variable updates and this variable to be modified when `other` updates.
953    ///
954    /// See [`bind_modify_bidi`] for more details about modify bindings.
955    ///
956    /// [`bind_modify_bidi`]: Var::bind_modify_bidi
957    pub fn bind_modify_bidi<O: VarValue>(
958        &self,
959        other: &Var<O>,
960        mut modify: impl FnMut(&dyn AnyVarValue, &mut VarModify<O>) + Send + 'static,
961        mut modify_back: impl FnMut(&O, &mut AnyVarModify) + Send + 'static,
962    ) -> VarHandles {
963        self.bind_modify_bidi_any(
964            other,
965            move |v, m| modify(v, &mut m.downcast::<O>().unwrap()),
966            move |v, m| modify_back(v.downcast_ref::<O>().unwrap(), m),
967        )
968    }
969
970    /// Bind `other` to receive the new values filtered mapped from this variable.
971    ///
972    /// See [`bind_filter_map`] for more details about variable bindings.
973    ///
974    /// [`bind_filter_map`]: Var::bind_filter_map
975    pub fn bind_filter_map_any(
976        &self,
977        other: &AnyVar,
978        map: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
979    ) -> VarHandle {
980        if self.capabilities().is_const() || other.capabilities().is_always_read_only() {
981            return VarHandle::dummy();
982        }
983
984        self.bind_filter_map_impl(other, map)
985    }
986
987    /// Bind strongly typed `other` to receive the new values filtered mapped from this variable.
988    ///
989    /// See [`bind_filter_map`] for more details about variable bindings.
990    ///
991    /// [`bind_filter_map`]: Var::bind_filter_map
992    pub fn bind_filter_map<O: VarValue>(
993        &self,
994        other: &AnyVar,
995        mut map: impl FnMut(&dyn AnyVarValue) -> Option<O> + Send + 'static,
996    ) -> VarHandle {
997        self.bind_filter_map_any(other, move |v| map(v).map(BoxAnyVarValue::new))
998    }
999
1000    /// Bind `other` to receive the new filtered mapped values from this variable and this variable to receive
1001    /// new filtered mapped values from `other`.
1002    ///
1003    /// See [`bind_filter_map_bidi`] for more details about variable bindings.
1004    ///
1005    /// [`bind_filter_map_bidi`]: Var::bind_filter_map_bidi
1006    pub fn bind_filter_map_bidi_any(
1007        &self,
1008        other: &AnyVar,
1009        map: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
1010        map_back: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
1011    ) -> VarHandles {
1012        let self_cap = self.capabilities();
1013        let other_cap = other.capabilities();
1014        if self_cap.is_const() || other_cap.is_const() {
1015            return VarHandles::dummy();
1016        }
1017        if self_cap.is_always_read_only() {
1018            return self.bind_filter_map_any(other, map).into();
1019        }
1020        if other_cap.is_always_read_only() {
1021            return other.bind_filter_map_any(self, map_back).into();
1022        }
1023
1024        let a = self.bind_filter_map_impl(other, map);
1025        let b = other.bind_filter_map_impl(self, map_back);
1026
1027        a.chain(b)
1028    }
1029
1030    /// Expects `other` to be contextualized
1031    fn bind_impl(&self, other: &AnyVar, mut map: impl FnMut(&dyn AnyVarValue) -> BoxAnyVarValue + Send + 'static) -> VarHandle {
1032        let weak_other = other.downgrade();
1033        self.hook(move |args| {
1034            if let Some(other) = weak_other.upgrade() {
1035                if args.contains_tag(&other.var_instance_tag()) {
1036                    // skip circular update
1037                    return true;
1038                }
1039                let self_tag = args.var_instance_tag();
1040
1041                let new_value = map(args.value());
1042                let update = args.update();
1043                other.modify(move |v| {
1044                    if v.set(new_value) || update {
1045                        // tag to avoid circular update
1046                        v.push_tag(self_tag);
1047                    }
1048                    if update {
1049                        // propagate explicit update requests
1050                        v.update();
1051                    }
1052                });
1053                true
1054            } else {
1055                false
1056            }
1057        })
1058    }
1059
1060    /// Expects `self` and `other` to be contextualized
1061    fn bind_modify_impl(&self, other: &AnyVar, modify: impl FnMut(&dyn AnyVarValue, &mut AnyVarModify) + Send + 'static) -> VarHandle {
1062        let weak_other = other.downgrade();
1063        let weak_self = self.downgrade();
1064        let modify = Arc::new(Mutex::new(modify));
1065        self.hook(move |args| {
1066            if let Some(other) = weak_other.upgrade() {
1067                if args.contains_tag(&other.var_instance_tag()) {
1068                    // skip circular update
1069                    return true;
1070                }
1071
1072                let self_ = weak_self.upgrade().unwrap();
1073                let update = args.update();
1074                other.modify(clmv!(modify, |v| {
1075                    let prev_update = mem::replace(&mut v.update, VarModifyUpdate::empty());
1076                    self_.with(|source| {
1077                        modify.lock()(source, v);
1078                    });
1079
1080                    if !v.update.is_empty() || update {
1081                        // tag to avoid circular update
1082                        v.push_tag(self_.var_instance_tag());
1083                    }
1084                    if update {
1085                        // propagate explicit update requests
1086                        v.update();
1087                    }
1088                    v.update |= prev_update;
1089                }));
1090                true
1091            } else {
1092                false
1093            }
1094        })
1095    }
1096
1097    fn bind_filter_map_impl(
1098        &self,
1099        other: &AnyVar,
1100        mut map: impl FnMut(&dyn AnyVarValue) -> Option<BoxAnyVarValue> + Send + 'static,
1101    ) -> VarHandle {
1102        let weak_other = other.downgrade();
1103        self.hook(move |args| {
1104            if let Some(other) = weak_other.upgrade() {
1105                if args.contains_tag(&other.var_instance_tag()) {
1106                    // skip circular update
1107                    return true;
1108                }
1109                let self_tag = args.var_instance_tag();
1110                let update = args.update();
1111                if let Some(new_value) = map(args.value()) {
1112                    other.modify(move |v| {
1113                        if v.set(new_value) || update {
1114                            // tag to avoid circular update
1115                            v.push_tag(self_tag);
1116                        }
1117                        if update {
1118                            // propagate explicit update requests
1119                            v.update();
1120                        }
1121                    });
1122                } else if update {
1123                    other.modify(move |v| {
1124                        v.update();
1125                        v.push_tag(self_tag);
1126                    });
1127                }
1128
1129                true
1130            } else {
1131                false
1132            }
1133        })
1134    }
1135}
1136/// Animation
1137impl AnyVar {
1138    /// Schedule an animation that targets this variable.
1139    ///
1140    /// See [`animate`] for more details.
1141    ///
1142    /// [`animate`]: Var::animate
1143    pub fn animate(&self, animate: impl FnMut(&Animation, &mut AnyVarModify) + Send + 'static) -> AnimationHandle {
1144        if !self.capabilities().is_always_read_only() {
1145            let target = self.current_context();
1146            if !target.capabilities().is_always_read_only() {
1147                // target var can be animated.
1148
1149                let wk_target = target.downgrade();
1150                let animate = Arc::new(Mutex::new(animate));
1151
1152                return VARS.animate(move |args| {
1153                    // animation
1154
1155                    if let Some(target) = wk_target.upgrade() {
1156                        // target still exists
1157
1158                        if target.modify_importance() > VARS.current_modify().importance {
1159                            // var modified by a more recent animation or directly, this animation cannot
1160                            // affect it anymore.
1161                            args.stop();
1162                            return;
1163                        }
1164
1165                        // try update
1166                        let r = target.try_modify(clmv!(animate, args, |value| {
1167                            (animate.lock())(&args, value);
1168                        }));
1169
1170                        if let Err(VarIsReadOnlyError { .. }) = r {
1171                            // var can maybe change to allow write again, but we wipe all animations anyway.
1172                            args.stop();
1173                        }
1174                    } else {
1175                        // target dropped.
1176                        args.stop();
1177                    }
1178                });
1179            }
1180        }
1181        AnimationHandle::dummy()
1182    }
1183
1184    /// Schedule animations started by `animate`, the closure is called once at the start to begin, then again every time
1185    /// the variable stops animating.
1186    ///
1187    /// See [`sequence`] for more details.
1188    ///
1189    /// [`sequence`]: Var::sequence
1190    pub fn sequence(&self, animate: impl FnMut(AnyVar) -> AnimationHandle + Send + 'static) -> VarHandle {
1191        if !self.capabilities().is_always_read_only() {
1192            let target = self.current_context();
1193            if !target.capabilities().is_always_read_only() {
1194                // target var can be animated.
1195
1196                let (handle_hook, handle) = VarHandle::new();
1197
1198                let wk_target = target.downgrade();
1199
1200                #[derive(Clone)]
1201                struct SequenceController(Arc<dyn Fn() + Send + Sync + 'static>);
1202                impl AnimationController for SequenceController {
1203                    fn on_stop(&self, _: &Animation) {
1204                        let ctrl = self.clone();
1205                        VARS.with_animation_controller(ctrl, || (self.0)());
1206                    }
1207                }
1208                let animate = Mutex::new(animate);
1209                let animate = Arc::new(move || {
1210                    if let Some(target) = wk_target.upgrade()
1211                        && target.modify_importance() <= VARS.current_modify().importance()
1212                        && handle_hook.is_alive()
1213                        && VARS.animations_enabled().get()
1214                    {
1215                        (animate.lock())(target).perm();
1216                    }
1217                });
1218                VARS.with_animation_controller(SequenceController(animate.clone()), || {
1219                    animate();
1220                });
1221
1222                return handle;
1223            }
1224        }
1225        VarHandle::dummy()
1226    }
1227
1228    /// If the variable current value was set by an active animation.
1229    ///
1230    /// The variable [`is_new`] when this changes to `true`, but it **may not be new** when the value changes to `false`.
1231    /// If the variable is not updated at the last frame of the animation that has last set it, it will not update
1232    /// just because that animation has ended. You can use [`hook_animation_stop`] to get a notification when the
1233    /// last animation stops, or use [`wait_animation`] to get a future that is ready when `is_animating` changes
1234    /// from `true` to `false`.
1235    ///
1236    /// [`is_new`]: AnyVar::is_new
1237    /// [`hook_animation_stop`]: AnyVar::hook_animation_stop
1238    /// [`wait_animation`]: AnyVar::wait_animation
1239    pub fn is_animating(&self) -> bool {
1240        self.0.is_animating()
1241    }
1242
1243    /// Gets the minimum *importance* clearance that is needed to modify this variable.
1244    ///
1245    /// Direct modify/set requests always apply, but requests made from inside an animation only apply if
1246    /// the animation *importance* is greater or equal this value.This is the mechanism that ensures that only
1247    /// the latest animation has *control* of the variable value.
1248    ///
1249    /// [`MODIFY`]: VarCapability::MODIFY
1250    /// [`VARS.current_modify`]: VARS::current_modify
1251    /// [`VARS.animate`]: VARS::animate
1252    pub fn modify_importance(&self) -> usize {
1253        self.0.modify_importance()
1254    }
1255
1256    /// Register a `handler` to be called when the current animation stops.
1257    ///
1258    /// Note that the `handler` is owned by the animation, not the variable, it will only be called/dropped when the
1259    /// animation stops.
1260    ///
1261    /// Returns the [`VarHandle::is_dummy`] if the variable is not animating. Note that if you are interacting
1262    /// with the variable from a non-UI thread the variable can stops animating between checking [`is_animating`]
1263    /// and registering the hook, in this case the dummy is returned as well.
1264    ///
1265    /// [`modify_importance`]: AnyVar::modify_importance
1266    /// [`is_animating`]: AnyVar::is_animating
1267    pub fn hook_animation_stop(&self, handler: impl FnOnce() + Send + 'static) -> VarHandle {
1268        let mut once = Some(handler);
1269        let handler: AnimationStopFn = smallbox!(move || { once.take().unwrap()() });
1270        self.0.hook_animation_stop(handler)
1271    }
1272
1273    /// Awaits for [`is_animating`] to change from `true` to `false`.
1274    ///
1275    /// If the variable is not animating at the moment of this call the future will await until the animation starts and stops.
1276    ///
1277    /// [`is_animating`]: Self::is_animating
1278    pub fn wait_animation(&self) -> impl Future<Output = ()> + Send + Sync {
1279        crate::future::WaitIsNotAnimatingFut::new(self)
1280    }
1281}
1282/// Value type.
1283impl AnyVar {
1284    /// Returns the strongly typed variable, if its of of value type `T`.
1285    pub fn downcast<T: VarValue>(self) -> Result<Var<T>, AnyVar> {
1286        if self.value_is::<T>() { Ok(Var::new_any(self)) } else { Err(self) }
1287    }
1288
1289    /// Returns [`downcast`] or `fallback_var`.
1290    ///
1291    /// [`downcast`]: Self::downcast
1292    pub fn downcast_or<T: VarValue, F: Into<Var<T>>>(self, fallback_var: impl FnOnce(AnyVar) -> F) -> Var<T> {
1293        match self.downcast() {
1294            Ok(tv) => tv,
1295            Err(av) => fallback_var(av).into(),
1296        }
1297    }
1298
1299    /// Gets the value type.
1300    pub fn value_type(&self) -> TypeId {
1301        self.0.value_type()
1302    }
1303
1304    /// Gets the value type name.
1305    ///
1306    /// Note that this string is not stable and should be used for debug only.
1307    #[cfg(feature = "type_names")]
1308    pub fn value_type_name(&self) -> &'static str {
1309        self.0.value_type_name()
1310    }
1311
1312    /// Gets if the value type is `T`.
1313    pub fn value_is<T: VarValue>(&self) -> bool {
1314        self.value_type() == TypeId::of::<T>()
1315    }
1316}
1317/// Variable type.
1318impl AnyVar {
1319    /// Flags that indicate what operations the variable is capable of in this update.
1320    pub fn capabilities(&self) -> VarCapability {
1321        self.0.capabilities()
1322    }
1323
1324    /// Current count of strong references to this variable.
1325    ///
1326    /// If this variable is [`SHARE`] cloning the variable only clones a reference to the variable.
1327    /// If this variable is local this is always `1` as it clones the value.
1328    ///
1329    /// [`SHARE`]: VarCapability::SHARE
1330    pub fn strong_count(&self) -> usize {
1331        self.0.strong_count()
1332    }
1333
1334    /// Create a weak reference to this variable.
1335    ///
1336    /// If this variable is [`SHARE`] returns a weak reference to the variable that can be upgraded to the variable it
1337    /// it is still alive. If this variable is local returns a dummy weak reference that cannot upgrade.
1338    ///
1339    /// [`SHARE`]: VarCapability::SHARE
1340    pub fn downgrade(&self) -> WeakAnyVar {
1341        WeakAnyVar(self.0.downgrade())
1342    }
1343
1344    /// Gets if this variable is the same as `other`.
1345    ///
1346    /// If this variable is [`SHARE`] compares the *pointer*. If this variable is local this is always `false`.
1347    ///
1348    /// [`SHARE`]: VarCapability::SHARE
1349    pub fn var_eq(&self, other: &AnyVar) -> bool {
1350        self.0.var_eq(&other.0)
1351    }
1352
1353    /// Copy ID that identifies this variable instance.
1354    ///
1355    /// The ID is only unique if this variable is [`SHARE`] and only while the variable is alive.
1356    /// This can be used with [`VarModify::push_tag`] and [`AnyVarHookArgs::contains_tag`] to avoid cyclic updates in custom
1357    /// bidirectional bindings.
1358    ///
1359    /// [`SHARE`]: VarCapability::SHARE
1360    pub fn var_instance_tag(&self) -> VarInstanceTag {
1361        self.0.var_instance_tag()
1362    }
1363
1364    /// Gets a clone of the var that is always read-only.
1365    ///
1366    /// The returned variable can still update if `self` is modified, but it does not have the [`MODIFY`] capability.
1367    ///
1368    /// [`MODIFY`]: VarCapability::MODIFY
1369    pub fn read_only(&self) -> AnyVar {
1370        AnyVar(self.0.clone_dyn().into_read_only())
1371    }
1372
1373    /// Create a var that redirects to this variable until the first value update, then it disconnects as a separate variable.
1374    ///
1375    /// The return variable is *clone-on-write* and has the `MODIFY` capability independent of the source capabilities, when
1376    /// a modify request is made the source value is cloned and offered for modification, if modified the source variable is dropped,
1377    /// if the modify closure does not update the source variable is retained.
1378    pub fn cow(&self) -> AnyVar {
1379        AnyVar(crate::DynAnyVar::Cow(crate::cow_var::CowVar::new(self.clone())))
1380    }
1381
1382    /// Hold the variable in memory until the app exit.
1383    ///
1384    /// Note that this is different from [`std::mem::forget`], if the app is compiled with `"multi_app"` feature
1385    /// the variable will be dropped before the new app instance in the same process.
1386    pub fn perm(&self) {
1387        VARS.perm(self.clone());
1388    }
1389
1390    /// Hold arbitrary `thing` for the lifetime of this variable or the return handle.
1391    pub fn hold(&self, thing: impl Any + Send) -> VarHandle {
1392        self.hold_impl(smallbox!(thing))
1393    }
1394    fn hold_impl(&self, thing: SmallBox<dyn Any + Send, smallbox::space::S2>) -> VarHandle {
1395        self.hook(move |_| {
1396            let _hold = &thing;
1397            true
1398        })
1399    }
1400
1401    /// Register a closure to be called when all strong references to this variable are dropped.
1402    ///
1403    /// If the return handle is dropped, the hook is unregistered without calling.
1404    pub fn hook_drop(&self, on_drop: impl FnOnce() + Send + 'static) -> VarHandle {
1405        self.hook_drop_impl(Box::new(on_drop))
1406    }
1407    fn hook_drop_impl(&self, on_drop: Box<dyn FnOnce() + Send + 'static>) -> VarHandle {
1408        let (handler_owner, handle) = VarHandle::new();
1409
1410        struct CallOnDrop(Option<Box<dyn FnOnce() + Send + 'static>>, crate::VarHandlerOwner);
1411        impl Drop for CallOnDrop {
1412            fn drop(&mut self) {
1413                if let Some(f) = self.0.take()
1414                    && self.1.is_alive()
1415                {
1416                    f();
1417                }
1418            }
1419        }
1420        let hold = CallOnDrop(Some(on_drop), handler_owner);
1421
1422        self.hook(move |_| hold.1.is_alive()).perm();
1423
1424        handle
1425    }
1426
1427    /// Gets the underlying var in the current calling context.
1428    ///
1429    /// If this variable is [`CONTEXT`] returns a clone of the inner variable,
1430    /// otherwise returns a clone of this variable.
1431    ///
1432    /// [`CONTEXT`]: VarCapability::CONTEXT
1433    pub fn current_context(&self) -> AnyVar {
1434        if self.capabilities().is_contextual() {
1435            AnyVar(self.0.current_context())
1436        } else {
1437            self.clone()
1438        }
1439    }
1440}
1441
1442/// Weak reference to a [`AnyVar`].
1443pub struct WeakAnyVar(pub(crate) crate::var_impl::DynWeakAnyVar);
1444impl fmt::Debug for WeakAnyVar {
1445    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1446        f.debug_tuple("WeakAnyVar").field(&self.0).finish()
1447    }
1448}
1449impl Clone for WeakAnyVar {
1450    fn clone(&self) -> Self {
1451        Self(self.0.clone_dyn())
1452    }
1453}
1454impl WeakAnyVar {
1455    /// Current count of strong references to the variable.
1456    pub fn strong_count(&self) -> usize {
1457        self.0.strong_count()
1458    }
1459
1460    /// Attempt to create a strong reference to the variable.
1461    pub fn upgrade(&self) -> Option<AnyVar> {
1462        self.0.upgrade().map(AnyVar)
1463    }
1464
1465    /// New weak var that does not upgrade.
1466    pub const fn new() -> Self {
1467        Self(crate::var_impl::DynWeakAnyVar::Const(crate::var_impl::const_var::WeakConstVar))
1468    }
1469
1470    /// Gets if this and `other` are a weak reference to the same var.
1471    pub fn var_eq(&self, other: &Self) -> bool {
1472        self.0.var_eq(&other.0)
1473    }
1474}
1475impl Default for WeakAnyVar {
1476    fn default() -> Self {
1477        Self::new()
1478    }
1479}
1480
1481/// Arguments for [`AnyVar::hook`].
1482pub struct AnyVarHookArgs<'a> {
1483    pub(super) var_instance_tag: VarInstanceTag,
1484    pub(super) value: &'a dyn AnyVarValue,
1485    pub(super) update: bool,
1486    pub(super) tags: &'a [BoxAnyVarValue],
1487}
1488impl<'a> AnyVarHookArgs<'a> {
1489    /// New from updated value and custom tag.
1490    pub fn new(var_instance_tag: VarInstanceTag, value: &'a dyn AnyVarValue, update: bool, tags: &'a [BoxAnyVarValue]) -> Self {
1491        Self {
1492            var_instance_tag,
1493            value,
1494            update,
1495            tags,
1496        }
1497    }
1498
1499    /// Tag that represents the viable.
1500    pub fn var_instance_tag(&self) -> VarInstanceTag {
1501        self.var_instance_tag
1502    }
1503
1504    /// Reference the updated value.
1505    pub fn value(&self) -> &'a dyn AnyVarValue {
1506        self.value
1507    }
1508
1509    /// If update was explicitly requested.
1510    ///
1511    /// Note that bindings/mappings propagate this update request.
1512    pub fn update(&self) -> bool {
1513        self.update
1514    }
1515
1516    /// Value type ID.
1517    pub fn value_type(&self) -> TypeId {
1518        self.value.type_id()
1519    }
1520
1521    /// Custom tag objects.
1522    pub fn tags(&self) -> &[BoxAnyVarValue] {
1523        self.tags
1524    }
1525
1526    /// Clone the custom tag objects set by the code that updated the value.
1527    pub fn tags_vec(&self) -> Vec<BoxAnyVarValue> {
1528        self.tags.iter().map(|t| (*t).clone_boxed()).collect()
1529    }
1530
1531    /// Reference the value, if it is of type `T`.
1532    pub fn downcast_value<T: VarValue>(&self) -> Option<&T> {
1533        self.value.downcast_ref()
1534    }
1535
1536    /// Reference all custom tag values of type `T`.
1537    pub fn downcast_tags<T: VarValue>(&self) -> impl Iterator<Item = &T> + '_ {
1538        self.tags.iter().filter_map(|t| (*t).downcast_ref::<T>())
1539    }
1540
1541    /// Gets if the `tag` is in [`tags`].
1542    ///
1543    /// [`tags`]: Self::tags
1544    pub fn contains_tag<T: VarValue>(&self, tag: &T) -> bool {
1545        self.downcast_tags::<T>().any(|t| t == tag)
1546    }
1547
1548    /// Try cast to strongly typed args.
1549    pub fn downcast<T: VarValue>(&self) -> Option<crate::VarHookArgs<'_, T>> {
1550        if TypeId::of::<T>() == self.value_type() {
1551            Some(crate::VarHookArgs {
1552                any: self,
1553                _t: PhantomData,
1554            })
1555        } else {
1556            None
1557        }
1558    }
1559}
1560
1561/// Unique identifier of a share variable, while it is alive.
1562///
1563/// See [`AnyVar::var_instance_tag`] for more details
1564#[derive(Clone, Copy, PartialEq, Eq)]
1565pub struct VarInstanceTag(pub(crate) usize);
1566impl fmt::Debug for VarInstanceTag {
1567    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1568        if *self == Self::NOT_SHARED {
1569            write!(f, "NOT_SHARED")
1570        } else {
1571            write!(f, "0x{:X})", self.0)
1572        }
1573    }
1574}
1575impl VarInstanceTag {
1576    /// ID for variables that are not [`SHARE`].
1577    ///
1578    /// [`SHARE`]: VarCapability::SHARE
1579    pub const NOT_SHARED: VarInstanceTag = VarInstanceTag(0);
1580}