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