Skip to main content

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