zng_var/
when.rs

1use std::sync::{Arc, Weak};
2
3use crate::animation::AnimationHandle;
4
5use super::*;
6
7///<span data-del-macro-root></span> Initializes a new conditional var.
8///
9/// A condition var updates when the first `true` condition changes or the mapped var for the current condition changes.
10///
11/// # Syntax
12///
13/// The macro expects a list of `condition-var => condition-value-var`, the list is separated by comma.
14/// The last condition must be the `_` token that maps to the value for when none of the conditions are `true`.
15///
16/// The `condition-var` must be an expression that evaluates to an `impl Var<bool>` type. The `condition-value-var` must
17/// by any type that implements `IntoVar`. All condition values must be of the same [`VarValue`] type.
18///
19/// # Examples
20///
21/// ```
22/// # use zng_var::*;
23/// # use zng_txt::ToTxt;
24/// # macro_rules! Text { ($($tt:tt)*) => { () } }
25/// let condition = var(true);
26/// let when_false = var("condition: false".to_txt());
27///
28/// let t = Text!(when_var! {
29///     condition.clone() => "condition: true".to_txt(),
30///     _ => when_false.clone(),
31/// });
32/// ```
33///
34/// In the example if `condition` or `when_false` are modified the text updates.
35///
36/// # `cfg`
37///
38/// Every condition can be annotated with attributes, including `#[cfg(..)]`.
39///
40/// ```
41/// # use zng_var::*;
42/// # use zng_txt::*;
43/// # macro_rules! Text { ($($tt:tt)*) => { () } }
44/// # let condition0 = var(true);
45/// # let condition1 = var(true);
46/// let t = Text!(when_var! {
47///     #[cfg(some_flag)]
48///     condition0 => "is condition 0".to_txt(),
49///     #[cfg(not(some_flag))]
50///     condition1 => "is condition 1".to_txt(),
51///     _ => "is default".to_txt(),
52/// });
53/// ```
54///
55/// In the example above only one of the conditions will be compiled, the generated variable is the same
56/// type as if you had written a single condition.
57///
58/// # Contextualized
59///
60/// The when var is contextualized when needed, meaning if any input [`is_contextual`] at the moment the var is created it
61/// is also contextual. The full output type of this macro is a `BoxedVar<T>` that is either an `ArcWhenVar<T>` or
62/// a `ContextualizedVar<T, ArcWhenVar<T>>`.
63///
64/// [`is_contextual`]: AnyVar::is_contextual
65#[macro_export]
66macro_rules! when_var {
67    ($($tt:tt)*) => {
68        $crate::types::__when_var! {
69            $crate
70            $($tt)*
71        }
72    }
73}
74
75use parking_lot::Mutex;
76#[doc(hidden)]
77pub use zng_var_proc_macros::when_var as __when_var;
78
79#[doc(hidden)]
80pub type ContextualizedArcWhenVar<T> = types::ContextualizedVar<T>;
81
82/// Manually build a [`ArcWhenVar<T>`].
83#[derive(Clone)]
84pub struct WhenVarBuilder<T: VarValue> {
85    default: BoxedAnyVar,
86    conditions: Vec<(BoxedVar<bool>, BoxedAnyVar)>,
87    _t: PhantomData<T>,
88}
89impl<T: VarValue> WhenVarBuilder<T> {
90    /// Start building with the default value.
91    pub fn new(default: impl IntoVar<T>) -> Self {
92        Self {
93            default: default.into_var().boxed_any(),
94            conditions: vec![],
95            _t: PhantomData,
96        }
97    }
98
99    /// Push a condition and value.
100    pub fn push(&mut self, condition: impl IntoVar<bool>, value: impl IntoVar<T>) {
101        self.conditions.push((condition.into_var().boxed(), value.into_var().boxed_any()));
102    }
103
104    /// Finish the build.
105    pub fn build(self) -> BoxedVar<T> {
106        if self.default.is_contextual() || self.conditions.iter().any(|(c, v)| c.is_contextual() || v.is_contextual()) {
107            types::ContextualizedVar::new(move || self.clone().build_impl()).boxed()
108        } else {
109            self.build_impl().boxed()
110        }
111    }
112    fn build_impl(self) -> ArcWhenVar<T> {
113        ArcWhenVar(
114            build_impl_any(self.default, self.conditions, std::any::type_name::<T>()),
115            PhantomData,
116        )
117    }
118}
119
120/// Manually build a [`ArcWhenVar<T>`] from type erased parts.
121pub struct AnyWhenVarBuilder {
122    default: BoxedAnyVar,
123    conditions: Vec<(BoxedVar<bool>, BoxedAnyVar)>,
124}
125impl AnyWhenVarBuilder {
126    /// Start building with only the default value.
127    pub fn new<O: VarValue>(default: impl IntoVar<O>) -> Self {
128        Self::new_any(default.into_var().boxed_any())
129    }
130
131    /// Start building with already boxed var.
132    pub fn new_any(default: BoxedAnyVar) -> AnyWhenVarBuilder {
133        Self {
134            default,
135            conditions: vec![],
136        }
137    }
138
139    /// Create a builder from the parts of a formed [`when_var!`].
140    ///
141    /// # Panics
142    ///
143    /// Panics if called not called with a contextualized var produced by [`when_var!`].
144    pub fn from_var<O: VarValue>(var: &types::ContextualizedVar<O>) -> Self {
145        let g = var.borrow_init();
146        let var = g
147            .as_any()
148            .downcast_ref::<ArcWhenVar<O>>()
149            .expect("expected `when_var!` contextualized var");
150        Self {
151            default: var.0.default.clone_any(),
152            conditions: var.0.conditions.iter().map(|(c, v)| (c.clone(), v.clone_any())).collect(),
153        }
154    }
155
156    /// Returns the number of conditions set.
157    pub fn condition_count(&self) -> usize {
158        self.conditions.len()
159    }
160
161    /// Set/replace the default value.
162    pub fn set_default<O: VarValue>(&mut self, default: impl IntoVar<O>) {
163        self.set_default_any(default.into_var().boxed_any());
164    }
165
166    /// Set/replace the default value with an already typed erased var.
167    pub fn set_default_any(&mut self, default: BoxedAnyVar) {
168        self.default = default;
169    }
170
171    /// Push a when condition.
172    pub fn push<C, O, V>(&mut self, condition: C, value: V)
173    where
174        C: Var<bool>,
175        O: VarValue,
176        V: IntoVar<O>,
177    {
178        self.push_any(condition.boxed(), value.into_var().boxed_any())
179    }
180
181    /// Push a when condition already boxed and type erased.
182    pub fn push_any(&mut self, condition: BoxedVar<bool>, value: BoxedAnyVar) {
183        self.conditions.push((condition, value));
184    }
185
186    /// Replace the default value if `other` has default and extend the conditions with clones of `other`.
187    pub fn replace_extend(&mut self, other: &Self) {
188        self.default = other.default.clone_any();
189        self.extend(other);
190    }
191
192    /// Extend the conditions with clones of `other`.
193    pub fn extend(&mut self, other: &Self) {
194        for (c, v) in other.conditions.iter() {
195            self.conditions.push((c.clone(), v.clone_any()));
196        }
197    }
198
199    /// Build the when var if all value variables are of type [`BoxedVar<T>`].
200    pub fn build<T: VarValue>(&self) -> Option<BoxedVar<T>> {
201        let t = self.default.var_type_id();
202        for (_, v) in &self.conditions {
203            if v.var_type_id() != t {
204                return None;
205            }
206        }
207        let when = WhenVarBuilder {
208            default: self.default.clone(),
209            conditions: self.conditions.clone(),
210            _t: PhantomData,
211        };
212        Some(when.build())
213    }
214}
215impl fmt::Debug for AnyWhenVarBuilder {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        f.debug_struct("AnyWhenVarBuilder")
218            .field("condition_count", &self.condition_count())
219            .finish_non_exhaustive()
220    }
221}
222impl Clone for AnyWhenVarBuilder {
223    fn clone(&self) -> Self {
224        Self {
225            default: self.default.clone_any(),
226            conditions: self.conditions.iter().map(|(c, v)| (c.clone(), v.clone_any())).collect(),
227        }
228    }
229}
230
231struct WhenData {
232    input_handles: Box<[VarHandle]>,
233    hooks: Vec<VarHook>,
234    last_update: VarUpdateId,
235    active: usize,
236}
237
238struct Data {
239    default: BoxedAnyVar,
240    conditions: Vec<(BoxedVar<bool>, BoxedAnyVar)>,
241    w: Mutex<WhenData>,
242}
243
244/// See [`when_var!`].
245pub struct ArcWhenVar<T>(Arc<Data>, PhantomData<T>);
246
247/// Weak reference to a [`ArcWhenVar<T>`].
248pub struct WeakWhenVar<T>(Weak<Data>, PhantomData<T>);
249
250fn build_impl_any(default: BoxedAnyVar, mut conditions: Vec<(BoxedVar<bool>, BoxedAnyVar)>, type_name: &'static str) -> Arc<Data> {
251    conditions.shrink_to_fit();
252    for (c, v) in conditions.iter_mut() {
253        #[expect(unreachable_code)]
254        fn panic_placeholder() -> BoxedVar<bool> {
255            types::ContextualizedVar::<bool>::new(|| LocalVar(unreachable!())).boxed()
256        }
257
258        take_mut::take_or_recover(c, panic_placeholder, Var::actual_var);
259        *v = v.actual_var_any();
260    }
261
262    let rc_when = Arc::new(Data {
263        default: default.actual_var_any(),
264        conditions,
265        w: Mutex::new(WhenData {
266            input_handles: Box::new([]),
267            hooks: vec![],
268            last_update: VarUpdateId::never(),
269            active: usize::MAX,
270        }),
271    });
272    let wk_when = Arc::downgrade(&rc_when);
273
274    {
275        let mut data = rc_when.w.lock();
276        let data = &mut *data;
277
278        // capacity can be n*2+1, but we only bet on conditions being `NEW`.
279        let mut input_handles = Vec::with_capacity(rc_when.conditions.len());
280        if rc_when.default.capabilities().contains(VarCapability::NEW) {
281            input_handles.push(rc_when.default.hook_any(handle_value(wk_when.clone(), usize::MAX, type_name)));
282        }
283        for (i, (c, v)) in rc_when.conditions.iter().enumerate() {
284            if c.get() && data.active > i {
285                data.active = i;
286            }
287
288            if c.capabilities().contains(VarCapability::NEW) {
289                input_handles.push(c.hook_any(handle_condition(wk_when.clone(), i, type_name)));
290            }
291            if v.capabilities().contains(VarCapability::NEW) {
292                input_handles.push(v.hook_any(handle_value(wk_when.clone(), i, type_name)));
293            }
294        }
295
296        data.input_handles = input_handles.into_boxed_slice();
297    }
298    rc_when
299}
300
301fn handle_condition(wk_when: Weak<Data>, i: usize, type_name: &'static str) -> Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync> {
302    Box::new(move |args| {
303        if let Some(rc_when) = wk_when.upgrade() {
304            let data = rc_when.w.lock();
305            let mut update = false;
306
307            match data.active.cmp(&i) {
308                std::cmp::Ordering::Equal => {
309                    if let Some(&false) = args.downcast_value::<bool>() {
310                        update = true;
311                    }
312                }
313                std::cmp::Ordering::Greater => {
314                    if let Some(&true) = args.downcast_value::<bool>() {
315                        update = true;
316                    }
317                }
318                std::cmp::Ordering::Less => {}
319            }
320
321            if update {
322                drop(data);
323                VARS.schedule_update(apply_update(rc_when, false, args.tags_vec()), type_name);
324            }
325
326            true
327        } else {
328            false
329        }
330    })
331}
332
333fn handle_value(wk_when: Weak<Data>, i: usize, type_name: &'static str) -> Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync> {
334    Box::new(move |args| {
335        if let Some(rc_when) = wk_when.upgrade() {
336            let data = rc_when.w.lock();
337            if data.active == i {
338                drop(data);
339                VARS.schedule_update(apply_update(rc_when, args.update(), args.tags_vec()), type_name);
340            }
341            true
342        } else {
343            false
344        }
345    })
346}
347
348fn apply_update(rc_merge: Arc<Data>, update: bool, tags: Vec<Box<dyn AnyVarValue>>) -> VarUpdateFn {
349    Box::new(move || {
350        let mut data = rc_merge.w.lock();
351        let data = &mut *data;
352
353        data.active = usize::MAX;
354        for (i, (c, _)) in rc_merge.conditions.iter().enumerate() {
355            if c.get() {
356                data.active = i;
357                break;
358            }
359        }
360        data.last_update = VARS.update_id();
361
362        let active = if data.active == usize::MAX {
363            &rc_merge.default
364        } else {
365            &rc_merge.conditions[data.active].1
366        };
367
368        active.with_any(&mut |value| {
369            let args = AnyVarHookArgs::new(value, update, &tags);
370            data.hooks.retain(|h| h.call(&args));
371        });
372        VARS.wake_app();
373    })
374}
375
376impl<T: VarValue> ArcWhenVar<T> {
377    fn active(&self) -> &BoxedAnyVar {
378        let active = self.0.w.lock().active;
379        if active == usize::MAX {
380            &self.0.default
381        } else {
382            &self.0.conditions[active].1
383        }
384    }
385
386    /// Reference condition, value pairs.
387    ///
388    /// The active condition is the first `true`.
389    pub fn conditions(&self) -> Vec<(BoxedVar<bool>, BoxedVar<T>)> {
390        self.0
391            .conditions
392            .iter()
393            .map(|(c, v)| (c.clone(), *v.clone().double_boxed_any().downcast::<BoxedVar<T>>().unwrap()))
394            .collect()
395    }
396
397    /// The default value var.
398    ///
399    /// When no condition is active this is the backing var.
400    pub fn default(&self) -> BoxedVar<T> {
401        *self.0.default.clone().double_boxed_any().downcast::<BoxedVar<T>>().unwrap()
402    }
403
404    /// Create a variable similar to [`Var::easing`], but with different duration and easing functions for each condition.
405    ///
406    /// The `condition_easing` must contain one entry for each when condition, entries can be `None`, the easing used
407    /// is the first entry that corresponds to a `true` condition, or falls back to the `default_easing`.
408    pub fn easing_when(
409        &self,
410        condition_easing: Vec<Option<(Duration, Arc<dyn Fn(EasingTime) -> EasingStep + Send + Sync>)>>,
411        default_easing: (Duration, Arc<dyn Fn(EasingTime) -> EasingStep + Send + Sync>),
412    ) -> types::ContextualizedVar<T>
413    where
414        T: Transitionable,
415    {
416        let source = self.clone();
417        types::ContextualizedVar::new(move || {
418            debug_assert_eq!(source.0.conditions.len(), condition_easing.len());
419
420            let source_wk = source.downgrade();
421            let easing_var = super::var(source.get());
422
423            let condition_easing = condition_easing.clone();
424            let default_easing = default_easing.clone();
425            let mut _anim_handle = AnimationHandle::dummy();
426            var_bind(&source, &easing_var, move |value, _, easing_var| {
427                let source = source_wk.upgrade().unwrap();
428                for ((c, _), easing) in source.0.conditions.iter().zip(&condition_easing) {
429                    if let Some((duration, func)) = easing {
430                        if c.get() {
431                            let func = func.clone();
432                            _anim_handle = easing_var.ease(value.clone(), *duration, move |t| func(t));
433                            return;
434                        }
435                    }
436                }
437
438                let (duration, func) = &default_easing;
439                let func = func.clone();
440                _anim_handle = easing_var.ease(value.clone(), *duration, move |t| func(t));
441            })
442            .perm();
443            easing_var.read_only()
444        })
445    }
446}
447
448impl<T> Clone for ArcWhenVar<T> {
449    fn clone(&self) -> Self {
450        Self(self.0.clone(), PhantomData)
451    }
452}
453impl<T> Clone for WeakWhenVar<T> {
454    fn clone(&self) -> Self {
455        Self(self.0.clone(), PhantomData)
456    }
457}
458
459impl<T: VarValue> crate::private::Sealed for ArcWhenVar<T> {}
460impl<T: VarValue> crate::private::Sealed for WeakWhenVar<T> {}
461
462impl<T: VarValue> AnyVar for ArcWhenVar<T> {
463    fn clone_any(&self) -> BoxedAnyVar {
464        Box::new(self.clone())
465    }
466
467    fn as_any(&self) -> &dyn Any {
468        self
469    }
470
471    fn as_unboxed_any(&self) -> &dyn Any {
472        self
473    }
474
475    fn double_boxed_any(self: Box<Self>) -> Box<dyn Any> {
476        let me: BoxedVar<T> = self;
477        Box::new(me)
478    }
479
480    fn var_type_id(&self) -> TypeId {
481        TypeId::of::<T>()
482    }
483
484    fn get_any(&self) -> Box<dyn AnyVarValue> {
485        Box::new(self.get())
486    }
487
488    fn with_any(&self, read: &mut dyn FnMut(&dyn AnyVarValue)) {
489        self.with(|v| read(v))
490    }
491
492    fn with_new_any(&self, read: &mut dyn FnMut(&dyn AnyVarValue)) -> bool {
493        self.with_new(|v| read(v)).is_some()
494    }
495
496    fn set_any(&self, value: Box<dyn AnyVarValue>) -> Result<(), VarIsReadOnlyError> {
497        self.active().set_any(value)
498    }
499
500    fn last_update(&self) -> VarUpdateId {
501        self.0.w.lock().last_update
502    }
503
504    fn is_contextual(&self) -> bool {
505        if self.0.conditions.is_empty() {
506            self.0.default.is_contextual()
507        } else {
508            self.active().is_contextual()
509        }
510    }
511
512    fn capabilities(&self) -> VarCapability {
513        if self.0.conditions.is_empty() {
514            self.0.default.capabilities()
515        } else {
516            self.active().capabilities() | VarCapability::NEW | VarCapability::CAPS_CHANGE
517        }
518    }
519
520    fn hook_any(&self, pos_modify_action: Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync>) -> VarHandle {
521        let (handle, hook) = VarHandle::new(pos_modify_action);
522        self.0.w.lock().hooks.push(hook);
523        handle
524    }
525
526    fn hook_animation_stop(&self, handler: Box<dyn FnOnce() + Send>) -> Result<(), Box<dyn FnOnce() + Send>> {
527        self.active().hook_animation_stop(handler)
528    }
529
530    fn strong_count(&self) -> usize {
531        Arc::strong_count(&self.0)
532    }
533
534    fn weak_count(&self) -> usize {
535        Arc::weak_count(&self.0)
536    }
537
538    fn actual_var_any(&self) -> BoxedAnyVar {
539        self.clone_any()
540    }
541
542    fn downgrade_any(&self) -> BoxedAnyWeakVar {
543        Box::new(WeakWhenVar(Arc::downgrade(&self.0), PhantomData::<T>))
544    }
545
546    fn is_animating(&self) -> bool {
547        self.active().is_animating()
548    }
549
550    fn modify_importance(&self) -> usize {
551        self.active().modify_importance()
552    }
553
554    fn var_ptr(&self) -> VarPtr {
555        VarPtr::new_arc(&self.0)
556    }
557
558    fn get_debug(&self) -> Txt {
559        self.with(var_debug)
560    }
561
562    fn update(&self) -> Result<(), VarIsReadOnlyError> {
563        Var::modify(self, var_update)
564    }
565
566    fn map_debug(&self) -> BoxedVar<Txt> {
567        Var::map(self, var_debug).boxed()
568    }
569}
570
571impl<T: VarValue> AnyWeakVar for WeakWhenVar<T> {
572    fn clone_any(&self) -> BoxedAnyWeakVar {
573        Box::new(self.clone())
574    }
575
576    fn strong_count(&self) -> usize {
577        self.0.strong_count()
578    }
579
580    fn weak_count(&self) -> usize {
581        self.0.weak_count()
582    }
583
584    fn upgrade_any(&self) -> Option<BoxedAnyVar> {
585        self.0.upgrade().map(|rc| Box::new(ArcWhenVar(rc, PhantomData::<T>)) as _)
586    }
587
588    fn as_any(&self) -> &dyn Any {
589        self
590    }
591}
592
593impl<T: VarValue> IntoVar<T> for ArcWhenVar<T> {
594    type Var = Self;
595
596    fn into_var(self) -> Self::Var {
597        self
598    }
599}
600
601impl<T: VarValue> Var<T> for ArcWhenVar<T> {
602    type ReadOnly = types::ReadOnlyVar<T, Self>;
603
604    type ActualVar = Self;
605
606    type Downgrade = WeakWhenVar<T>;
607
608    type Map<O: VarValue> = contextualized::ContextualizedVar<O>;
609    type MapBidi<O: VarValue> = contextualized::ContextualizedVar<O>;
610
611    type FlatMap<O: VarValue, V: Var<O>> = contextualized::ContextualizedVar<O>;
612
613    type FilterMap<O: VarValue> = contextualized::ContextualizedVar<O>;
614    type FilterMapBidi<O: VarValue> = contextualized::ContextualizedVar<O>;
615
616    type MapRef<O: VarValue> = types::MapRef<T, O, Self>;
617    type MapRefBidi<O: VarValue> = types::MapRefBidi<T, O, Self>;
618
619    type Easing = types::ContextualizedVar<T>;
620
621    fn with<R, F>(&self, read: F) -> R
622    where
623        F: FnOnce(&T) -> R,
624    {
625        let mut read = Some(read);
626        let mut rsp = None;
627        self.active().with_any(&mut |v| {
628            let read = read.take().unwrap();
629            let r = read(v.as_any().downcast_ref::<T>().unwrap());
630            rsp = Some(r);
631        });
632        rsp.unwrap()
633    }
634
635    fn modify<F>(&self, modify: F) -> Result<(), VarIsReadOnlyError>
636    where
637        F: FnOnce(&mut VarModify<T>) + Send + 'static,
638    {
639        self.active()
640            .clone()
641            .double_boxed_any()
642            .downcast::<BoxedVar<T>>()
643            .unwrap()
644            .modify(modify)
645    }
646
647    fn set<I>(&self, value: I) -> Result<(), VarIsReadOnlyError>
648    where
649        I: Into<T>,
650    {
651        self.active().set_any(Box::new(value.into()))
652    }
653
654    fn actual_var(self) -> Self {
655        // inputs already actualized on ctor
656        self
657    }
658
659    fn downgrade(&self) -> WeakWhenVar<T> {
660        WeakWhenVar(Arc::downgrade(&self.0), PhantomData)
661    }
662
663    fn into_value(self) -> T {
664        // need to clone the value anyway because of type erased internals
665        self.get()
666    }
667
668    fn read_only(&self) -> Self::ReadOnly {
669        types::ReadOnlyVar::new(self.clone())
670    }
671
672    fn map<O, M>(&self, map: M) -> Self::Map<O>
673    where
674        O: VarValue,
675        M: FnMut(&T) -> O + Send + 'static,
676    {
677        var_map_ctx(self, map)
678    }
679
680    fn map_bidi<O, M, B>(&self, map: M, map_back: B) -> Self::MapBidi<O>
681    where
682        O: VarValue,
683        M: FnMut(&T) -> O + Send + 'static,
684        B: FnMut(&O) -> T + Send + 'static,
685    {
686        var_map_bidi_ctx(self, map, map_back)
687    }
688
689    fn flat_map<O, V, M>(&self, map: M) -> Self::FlatMap<O, V>
690    where
691        O: VarValue,
692        V: Var<O>,
693        M: FnMut(&T) -> V + Send + 'static,
694    {
695        var_flat_map_ctx(self, map)
696    }
697
698    fn filter_map<O, M, I>(&self, map: M, fallback: I) -> Self::FilterMap<O>
699    where
700        O: VarValue,
701        M: FnMut(&T) -> Option<O> + Send + 'static,
702        I: Fn() -> O + Send + Sync + 'static,
703    {
704        var_filter_map_ctx(self, map, fallback)
705    }
706
707    fn filter_map_bidi<O, M, B, I>(&self, map: M, map_back: B, fallback: I) -> Self::FilterMapBidi<O>
708    where
709        O: VarValue,
710        M: FnMut(&T) -> Option<O> + Send + 'static,
711        B: FnMut(&O) -> Option<T> + Send + 'static,
712        I: Fn() -> O + Send + Sync + 'static,
713    {
714        var_filter_map_bidi_ctx(self, map, map_back, fallback)
715    }
716
717    fn map_ref<O, M>(&self, map: M) -> Self::MapRef<O>
718    where
719        O: VarValue,
720        M: Fn(&T) -> &O + Send + Sync + 'static,
721    {
722        var_map_ref(self, map)
723    }
724
725    fn map_ref_bidi<O, M, B>(&self, map: M, map_mut: B) -> Self::MapRefBidi<O>
726    where
727        O: VarValue,
728        M: Fn(&T) -> &O + Send + Sync + 'static,
729        B: Fn(&mut T) -> &mut O + Send + Sync + 'static,
730    {
731        var_map_ref_bidi(self, map, map_mut)
732    }
733
734    fn easing<F>(&self, duration: Duration, easing: F) -> Self::Easing
735    where
736        T: Transitionable,
737        F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
738    {
739        var_easing_ctx(self, duration, easing)
740    }
741
742    fn easing_with<F, S>(&self, duration: Duration, easing: F, sampler: S) -> Self::Easing
743    where
744        T: Transitionable,
745        F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
746        S: Fn(&animation::Transition<T>, EasingStep) -> T + Send + Sync + 'static,
747    {
748        var_easing_with_ctx(self, duration, easing, sampler)
749    }
750}
751
752impl<T: VarValue> WeakVar<T> for WeakWhenVar<T> {
753    type Upgrade = ArcWhenVar<T>;
754
755    fn upgrade(&self) -> Option<ArcWhenVar<T>> {
756        self.0.upgrade().map(|rc| ArcWhenVar(rc, PhantomData))
757    }
758}