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