zng_var/var.rs
1use core::fmt;
2use std::{any::TypeId, marker::PhantomData, ops, sync::Arc, time::Duration};
3
4use crate::{
5 AnyVar, AnyVarHookArgs, BoxAnyVarValue, VarHandle, VarHandles, VarImpl, VarIsReadOnlyError, VarModify, VarValue, WeakAnyVar,
6 animation::{
7 Animation, AnimationHandle, ChaseAnimation, Transition, TransitionKeyed, Transitionable,
8 easing::{EasingStep, EasingTime},
9 },
10 contextual_var,
11};
12
13use zng_clone_move::clmv;
14use zng_txt::{ToTxt, Txt};
15use zng_unit::{Factor, FactorUnits as _};
16
17/// Variable of type `T`.
18pub struct Var<T: VarValue> {
19 pub(crate) any: AnyVar,
20 _t: PhantomData<fn() -> T>,
21}
22impl<T: VarValue> Clone for Var<T> {
23 fn clone(&self) -> Self {
24 Self {
25 any: self.any.clone(),
26 _t: PhantomData,
27 }
28 }
29}
30impl<T: VarValue> From<Var<T>> for AnyVar {
31 fn from(var: Var<T>) -> Self {
32 var.any
33 }
34}
35impl<T: VarValue> TryFrom<AnyVar> for Var<T> {
36 type Error = AnyVar;
37
38 fn try_from(var: AnyVar) -> Result<Self, Self::Error> {
39 var.downcast()
40 }
41}
42impl<T: VarValue> ops::Deref for Var<T> {
43 type Target = AnyVar;
44
45 fn deref(&self) -> &Self::Target {
46 self.as_any()
47 }
48}
49impl<T: VarValue> Var<T> {
50 pub(crate) fn new_any(any: AnyVar) -> Self {
51 Var { any, _t: PhantomData }
52 }
53}
54impl<T: VarValue> fmt::Debug for Var<T> {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 f.debug_tuple("Var").field(&self.any.0).finish()
57 }
58}
59
60/// Value.
61impl<T: VarValue> Var<T> {
62 /// Visit a reference to the current value.
63 pub fn with<O>(&self, visitor: impl FnOnce(&T) -> O) -> O {
64 let mut once = Some(visitor);
65 let mut output = None;
66 self.0.with(&mut |v| {
67 output = Some(once.take().unwrap()(v.downcast_ref().unwrap()));
68 });
69 output.unwrap()
70 }
71
72 /// Get a clone of the current value.
73 pub fn get(&self) -> T {
74 self.with(|v| v.clone())
75 }
76
77 /// Get a clone of the current value into `value`.
78 ///
79 /// This uses [`Clone::clone_from`] to reuse the `value` memory if supported.
80 pub fn get_into(&self, value: &mut T) {
81 self.with(|v| value.clone_from(v));
82 }
83
84 /// Visit a reference to the current value if it [`is_new`].
85 ///
86 /// [`is_new`]: AnyVar::is_new
87 pub fn with_new<O>(&self, visitor: impl FnOnce(&T) -> O) -> Option<O> {
88 if self.is_new() { Some(self.with(visitor)) } else { None }
89 }
90
91 /// Gets a clone of the current value if it [`is_new`].
92 ///
93 /// [`is_new`]: AnyVar::is_new
94 pub fn get_new(&self) -> Option<T> {
95 if self.is_new() { Some(self.get()) } else { None }
96 }
97
98 /// Gets a clone of the current value into `value` if it [`is_new`].
99 ///
100 /// This uses [`Clone::clone_from`] to reuse the `value` memory if supported.
101 ///
102 /// [`is_new`]: AnyVar::is_new
103 pub fn get_new_into(&self, value: &mut T) -> bool {
104 self.with_new(|v| value.clone_from(v)).is_some()
105 }
106
107 /// Schedule `new_value` to be assigned next update.
108 pub fn try_set(&self, new_value: impl Into<T>) -> Result<(), VarIsReadOnlyError> {
109 self.any.try_set(BoxAnyVarValue::new(new_value.into()))
110 }
111
112 /// Schedule `new_value` to be assigned next update.
113 ///
114 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
115 /// Use [`try_set`] to get an error for read-only vars.
116 ///
117 /// [`try_set`]: Self::try_set
118 pub fn set(&self, new_value: impl Into<T>) {
119 trace_debug_error!(self.try_set(new_value))
120 }
121
122 /// Schedule `modify` to be called on the value for the next update.
123 ///
124 /// If the [`VarModify`] value is deref mut the variable will notify an update.
125 pub fn try_modify(&self, modify: impl FnOnce(&mut VarModify<T>) + Send + 'static) -> Result<(), VarIsReadOnlyError> {
126 self.any.try_modify(move |value| {
127 modify(&mut value.downcast::<T>().unwrap());
128 })
129 }
130
131 /// Schedule `modify` to be called on the value for the next update.
132 ///
133 /// If the [`VarModify`] value is deref mut the variable will notify an update.
134 ///
135 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
136 /// Use [`try_modify`] to get an error for read-only vars.
137 ///
138 /// [`try_modify`]: Self::try_modify
139 pub fn modify(&self, modify: impl FnOnce(&mut VarModify<T>) + Send + 'static) {
140 trace_debug_error!(self.try_modify(modify))
141 }
142
143 /// Schedule a new `value` for the variable, it will be set in the end of the current app update to the updated
144 /// value of `other`, so if the other var has already scheduled an update, the updated value will be used.
145 ///
146 /// This can be used just before creating a binding to start with synchronized values.
147 pub fn try_set_from(&self, other: &Var<T>) -> Result<(), VarIsReadOnlyError> {
148 self.any.try_set_from(other)
149 }
150
151 /// Schedule a new `value` for the variable, it will be set in the end of the current app update to the updated
152 /// value of `other`, so if the other var has already scheduled an update, the updated value will be used.
153 ///
154 /// This can be used just before creating a binding to start with synchronized values.
155 ///
156 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
157 /// Use [`try_set_from`] to get an error for read-only vars.
158 ///
159 /// [`try_set_from`]: Self::try_set_from
160 pub fn set_from(&self, other: &Var<T>) {
161 trace_debug_error!(self.try_set_from(other))
162 }
163
164 /// Like [`try_set_from`], but uses `map` to produce the new value from the updated value of `other`.
165 ///
166 /// [`try_set_from`]: Self::try_set_from
167 pub fn try_set_from_map<O: VarValue>(
168 &self,
169 other: &Var<O>,
170 map: impl FnOnce(&O) -> T + Send + 'static,
171 ) -> Result<(), VarIsReadOnlyError> {
172 self.any
173 .try_set_from_map(other, move |v| BoxAnyVarValue::new(map(v.downcast_ref::<O>().unwrap())))
174 }
175
176 /// Like [`set_from`], but uses `map` to produce the new value from the updated value of `other`.
177 ///
178 /// If the variable is read-only this is ignored and a DEBUG level log is recorded.
179 /// Use [`try_set_from_map`] to get an error for read-only vars.
180 ///
181 /// [`try_set_from_map`]: Self::try_set_from_map
182 /// [`set_from`]: Self::set_from
183 pub fn set_from_map<O: VarValue>(&self, other: &Var<O>, map: impl FnOnce(&O) -> T + Send + 'static) {
184 trace_debug_error!(self.try_set_from_map(other, map))
185 }
186
187 /// Setups a callback for just after the variable value update is applied, the closure runs in the root app context, just like
188 /// the `modify` closure. The closure must return `true` to be retained and `false` to be dropped.
189 ///
190 /// If you modify another variable in the closure modification applies in the same update, variable mapping and
191 /// binding is implemented using hooks.
192 ///
193 /// The variable store a weak reference to the callback if it has the `MODIFY` or `CAPS_CHANGE` capabilities, otherwise
194 /// the callback is discarded and [`VarHandle::dummy`] returned.
195 pub fn hook(&self, mut on_update: impl FnMut(&VarHookArgs<T>) -> bool + Send + 'static) -> VarHandle {
196 self.any
197 .hook(move |args: &AnyVarHookArgs| -> bool { on_update(&args.downcast().unwrap()) })
198 }
199
200 ///Awaits for a value that passes the `predicate`, including the current value.
201 #[allow(clippy::manual_async_fn)] // false positive, async fn futures are not Send + Sync
202 pub fn wait_match(&self, predicate: impl Fn(&T) -> bool + Send + Sync) -> impl Future<Output = ()> + Send + Sync {
203 self.any.wait_match(move |v| predicate(v.downcast_ref::<T>().unwrap()))
204 }
205
206 /// Awaits for an update them [`get`] the value.
207 ///
208 /// [`get`]: Self::get
209 #[allow(clippy::manual_async_fn)] // false positive, async fn futures are not Send + Sync
210 pub fn wait_next(&self) -> impl Future<Output = T> + Send + Sync {
211 async {
212 self.wait_update().await;
213 self.get()
214 }
215 }
216
217 /// Debug helper for tracing the lifetime of a value in this variable.
218 ///
219 /// The `enter_value` closure is called every time the variable updates, it can return
220 /// an implementation agnostic *scope* or *span* `S` that is only dropped when the variable updates again.
221 ///
222 /// The `enter_value` is also called immediately when this method is called to start tracking the first value.
223 ///
224 /// Returns a [`VarHandle`] that can be used to stop tracing.
225 ///
226 /// If this variable can never update the span is immediately dropped and a dummy handle is returned.
227 pub fn trace_value<S: Send + 'static>(&self, mut enter_value: impl FnMut(&VarHookArgs<T>) -> S + Send + 'static) -> VarHandle {
228 self.any.trace_value(move |args| enter_value(&args.downcast::<T>().unwrap()))
229 }
230}
231/// Value mapping.
232impl<T: VarValue> Var<T> {
233 /// Create a read-only mapping variable.
234 ///
235 /// The `map` closure must produce a mapped value from this variable's value.
236 ///
237 /// # Examples
238 ///
239 /// Basic usage:
240 ///
241 /// ```
242 /// # use zng_var::*;
243 /// # use zng_txt::*;
244 /// let n_var = var(0u32);
245 /// let n_10_var = n_var.map(|n| *n * 10);
246 /// let txt_var = n_10_var.map(|n| if *n < 100 { formatx!("{n}!") } else { formatx!("Done!") });
247 /// ```
248 ///
249 /// In the example above the `txt_var` will update every time the `n_var` updates.
250 ///
251 /// # Capabilities
252 ///
253 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static.
254 ///
255 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable and
256 /// is called again for every update of this variable. The mapping variable is another shared reference and it holds
257 /// a strong reference to this variable.
258 ///
259 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
260 /// mapping variable is also contextual and will init for every context it is used in.
261 ///
262 /// The mapping variable is read-only, see [`map_bidi`] for read-write mapping.
263 ///
264 /// If the `map` closure produce an equal value the mapping variable will not update, see also [`filter_map`]
265 /// to skip updating for some input values.
266 ///
267 /// [`map_bidi`]: Self::map_bidi
268 /// [`filter_map`]: Self::filter_map
269 pub fn map<O: VarValue>(&self, mut map: impl FnMut(&T) -> O + Send + 'static) -> Var<O> {
270 self.any.map(move |v| map(v.downcast_ref::<T>().unwrap()))
271 }
272
273 /// Create a [`map`] that converts from `T` to `O` using [`Into<O>`].
274 ///
275 /// [`map`]: Var::map
276 pub fn map_into<O>(&self) -> Var<O>
277 where
278 O: VarValue,
279 T: Into<O>,
280 {
281 self.map(|v| v.clone().into())
282 }
283
284 /// Create a [`map`] that converts from `T` to [`Txt`] using [`ToTxt`].
285 ///
286 /// [`map`]: Var::map
287 /// [`Txt`]: Txt
288 /// [`ToTxt`]: ToTxt
289 pub fn map_to_txt(&self) -> Var<Txt>
290 where
291 T: ToTxt,
292 {
293 self.map(ToTxt::to_txt)
294 }
295
296 /// Create a [`map`] that references and clones `O` from `T` using `std::ops::Deref<Target = O>`.
297 ///
298 /// The mapping variable is read-only, see [`map_deref_mut`] for mutable referencing.
299 ///
300 /// [`map`]: Self::map
301 /// [`map_deref_mut`]: Self::map_deref_mut
302 pub fn map_deref<O>(&self) -> Var<O>
303 where
304 O: VarValue,
305 T: ops::Deref<Target = O>,
306 {
307 self.map(|v| ops::Deref::deref(v).clone())
308 }
309
310 /// Create a mapping variable that can skip updates.
311 ///
312 /// The `map` closure is called for every update this variable and if it returns a new value the mapping variable updates.
313 ///
314 /// If the `map` closure does not produce a value on init the `fallback_init` closure is called.
315 ///
316 /// # Examples
317 ///
318 /// Basic usage:
319 ///
320 /// ```
321 /// # use zng_var::*;
322 /// # use zng_txt::*;
323 /// let n_var = var(100u32);
324 /// let txt_var = n_var.filter_map(|n| if *n < 100 { Some(formatx!("{n}!")) } else { None }, || "starting...".into());
325 /// ```
326 ///
327 /// In the example above the `txt_var` will update every time the `n_var` updates with value `n < 100`. Because
328 /// the `n_var` initial value does not match the filter the fallback value `"starting..."` is used.
329 ///
330 /// # Capabilities
331 ///
332 /// If this variable is static the closures are called immediately and dropped, the mapping variable is also static.
333 ///
334 /// If this variable is a shared reference the closures are called immediately to init the mapping variable and
335 /// are called again for every update of this variable. The mapping variable is another shared reference and it holds
336 /// a strong reference to this variable.
337 ///
338 /// If this variable is contextual the initial closures call is deferred until first usage of the mapping variable. The
339 /// mapping variable is also contextual and will init for every context it is used in.
340 ///
341 /// The mapping variable is read-only, see [`filter_map_bidi`] for read-write mapping.
342 ///
343 /// [`filter_map_bidi`]: Self::filter_map_bidi
344 pub fn filter_map<O: VarValue>(
345 &self,
346 mut map: impl FnMut(&T) -> Option<O> + Send + 'static,
347 fallback_init: impl Fn() -> O + Send + 'static,
348 ) -> Var<O> {
349 self.any.filter_map(move |v| map(v.downcast_ref::<T>().unwrap()), fallback_init)
350 }
351
352 /// Create a [`filter_map`] that tries to convert from `T` to `O` using [`TryInto<O>`].
353 ///
354 /// [`filter_map`]: Var::filter_map
355 pub fn filter_try_into<O, I>(&self, fallback_init: I) -> Var<O>
356 where
357 O: VarValue,
358 T: TryInto<O>,
359 I: Fn() -> O + Send + Sync + 'static,
360 {
361 self.filter_map(|v| v.clone().try_into().ok(), fallback_init)
362 }
363
364 /// Create a [`filter_map`] that tries to convert from `T` to `O` using [`FromStr`].
365 ///
366 /// [`filter_map`]: Var::filter_map
367 /// [`FromStr`]: std::str::FromStr
368 pub fn filter_parse<O, I>(&self, fallback_init: I) -> Var<O>
369 where
370 O: VarValue + std::str::FromStr,
371 T: AsRef<str>,
372 I: Fn() -> O + Send + Sync + 'static,
373 {
374 self.filter_map(|v| v.as_ref().parse().ok(), fallback_init)
375 }
376
377 /// Create a bidirectional mapping variable.
378 ///
379 /// # Examples
380 ///
381 /// Basic usage:
382 ///
383 /// ```
384 /// # use zng_var::*;
385 /// # use zng_txt::*;
386 /// let n_var = var(0u32);
387 /// let n_100_var = n_var.map_bidi(|n| n * 100, |n_100| n_100 / 100);
388 /// ```
389 ///
390 /// In the example above the `n_100_var` will update every time the `n_var` updates and the `n_var` will
391 /// update every time the `n_100_var` updates.
392 ///
393 /// # Capabilities
394 ///
395 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static,
396 /// the `map_back` closure is ignored.
397 ///
398 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable.
399 /// The mapping variable is another shared reference and it holds a strong reference to this variable.
400 /// The `map` closure is called again for every update of this variable that is not caused by the mapping variable.
401 /// The `map_back` closure is called for every update of the mapping variable that was not caused by this variable.
402 ///
403 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
404 /// mapping variable is also contextual and will init for every context it is used in.
405 pub fn map_bidi<O: VarValue>(
406 &self,
407 mut map: impl FnMut(&T) -> O + Send + 'static,
408 mut map_back: impl FnMut(&O) -> T + Send + 'static,
409 ) -> Var<O> {
410 let mapping = self.map_bidi_any(
411 move |input| BoxAnyVarValue::new(map(input.downcast_ref::<T>().unwrap())),
412 move |output| BoxAnyVarValue::new(map_back(output.downcast_ref::<O>().unwrap())),
413 TypeId::of::<O>(),
414 );
415 Var::new_any(mapping)
416 }
417
418 /// Create a bidirectional mapping variable that modifies back instead of mapping back.
419 ///
420 /// # Examples
421 ///
422 /// Basic usage:
423 ///
424 /// ```
425 /// # use zng_var::*;
426 /// # use zng_txt::*;
427 /// let list_var = var(vec!['a', 'b', 'c']);
428 /// let first_var = list_var.map_bidi_modify(
429 /// // map:
430 /// |l| l.first().copied().unwrap_or('_'),
431 /// // modify_back:
432 /// |c, l| if l.is_empty() { l.push(*c) } else { l[0] = *c },
433 /// );
434 /// ```
435 ///
436 /// In the example above the `first_var` represents the first item on the vector in `list_var`. Note that the `map` closure
437 /// works the same as in [`map_bidi`], but the `modify_back` closure modifies the list. This is not a mapping that can be declared
438 /// with [`map_bidi`] as the mapping variable does not have the full list to map back.
439 ///
440 /// # Capabilities
441 ///
442 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static,
443 /// the `modify_back` closure is ignored.
444 ///
445 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable.
446 /// The mapping variable is another shared reference and it holds a strong reference to this variable.
447 /// The `map` closure is called again for every update of this variable that is not caused by the mapping variable.
448 /// The `modify_back` closure is called for every update of the mapping variable that was not caused by this variable.
449 ///
450 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
451 /// mapping variable is also contextual and will init for every context it is used in.
452 ///
453 /// Like other mappings and bindings cyclic updates are avoided automatically, if the `modify_back` closure touches/updates the value
454 /// a var instance tag is inserted after the closure returns, you do not need to mark it manually.
455 ///
456 /// [`map_bidi`]: Self::map_bidi
457 pub fn map_bidi_modify<O: VarValue>(
458 &self,
459 mut map: impl FnMut(&T) -> O + Send + 'static,
460 mut modify_back: impl FnMut(&O, &mut VarModify<T>) + Send + 'static,
461 ) -> Var<O> {
462 let mapping = self.map_bidi_modify_any(
463 move |input| BoxAnyVarValue::new(map(input.downcast_ref::<T>().unwrap())),
464 move |v, m| modify_back(v.downcast_ref::<O>().unwrap(), &mut m.downcast::<T>().unwrap()),
465 TypeId::of::<O>(),
466 );
467 Var::new_any(mapping)
468 }
469
470 /// Create a [`map_bidi`] that converts between `T` and `O` using [`Into`].
471 ///
472 /// [`map_bidi`]: Var::map_bidi
473 pub fn map_into_bidi<O>(&self) -> Var<O>
474 where
475 O: VarValue + Into<T>,
476 T: Into<O>,
477 {
478 self.map_bidi(|t| t.clone().into(), |o| o.clone().into())
479 }
480
481 /// Create a [`map_bidi_modify`] that references and clones `O` from `T` using `std::ops::Deref<Target = O>` and
482 /// modifies back using `std::ops::DerefMut<Target = O>`.
483 ///
484 /// [`map_bidi_modify`]: Self::map_bidi_modify
485 pub fn map_deref_mut<O>(&self) -> Var<O>
486 where
487 O: VarValue,
488 T: ops::Deref<Target = O>,
489 T: ops::DerefMut<Target = O>,
490 {
491 self.map_bidi_modify(
492 |input| T::deref(input).clone(),
493 |output, modify| *T::deref_mut(modify) = output.clone(),
494 )
495 }
496
497 /// Create a bidirectional mapping variable that can skip updates.
498 ///
499 /// If the `map` closure does not produce a value on init the `fallback_init` closure is called.
500 ///
501 /// # Examples
502 ///
503 /// Basic usage:
504 ///
505 /// ```
506 /// # use zng_var::*;
507 /// # use zng_txt::*;
508 /// let n_var = var(0u32);
509 /// let n_100_var = n_var.filter_map_bidi(
510 /// |n| Some(n * 100),
511 /// |n_100| {
512 /// let r = n_100 / 100;
513 /// if r < 100 { Some(r) } else { None }
514 /// },
515 /// || 0,
516 /// );
517 /// ```
518 ///
519 /// In the example above the `n_100_var` will update every time the `n_var` updates with any value and the `n_var` will
520 /// update every time the `n_100_var` updates with a value that `(n_100 / 100) < 100`.
521 ///
522 /// # Capabilities
523 ///
524 /// If this variable is static the `map` closure is called immediately and dropped, the mapping variable is also static,
525 /// the `map_back` closure is ignored.
526 ///
527 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable.
528 /// The mapping variable is another shared reference and it holds a strong reference to this variable.
529 /// The `map` closure is called again for every update of this variable that is not caused by the mapping variable.
530 /// The `map_back` closure is called for every update of the mapping variable that was not caused by this variable.
531 ///
532 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
533 /// mapping variable is also contextual and will init for every context it is used in.
534 pub fn filter_map_bidi<O: VarValue>(
535 &self,
536 mut map: impl FnMut(&T) -> Option<O> + Send + 'static,
537 mut map_back: impl FnMut(&O) -> Option<T> + Send + 'static,
538 fallback_init: impl Fn() -> O + Send + 'static,
539 ) -> Var<O> {
540 let mapping = self.filter_map_bidi_any(
541 move |t| map(t.downcast_ref::<T>().unwrap()).map(BoxAnyVarValue::new),
542 move |o| map_back(o.downcast_ref::<O>().unwrap()).map(BoxAnyVarValue::new),
543 move || BoxAnyVarValue::new(fallback_init()),
544 TypeId::of::<O>(),
545 );
546 Var::new_any(mapping)
547 }
548
549 /// Create a [`filter_map_bidi`] that tries to convert between `T` to `O` using [`TryInto`].
550 ///
551 /// [`filter_map_bidi`]: Var::filter_map_bidi
552 pub fn filter_try_into_bidi<O, I>(&self, fallback_init: I) -> Var<O>
553 where
554 O: VarValue,
555 T: TryInto<O>,
556 O: TryInto<T>,
557 I: Fn() -> O + Send + Sync + 'static,
558 {
559 self.filter_map_bidi(|v| v.clone().try_into().ok(), |o| o.clone().try_into().ok(), fallback_init)
560 }
561
562 /// Create a flat mapping variable that *unwraps* an inner variable stored in the the value of this variable.
563 ///
564 /// # Capabilities
565 ///
566 /// If this variable is static the `map` closure is called immediately and dropped and the inner variable is returned.
567 ///
568 /// If this variable is a shared reference the `map` closure is called immediately to init the mapping variable and
569 /// is called again for every update of this variable. The mapping variable is another shared reference and it holds
570 /// a strong reference to this variable and to the inner variable.
571 ///
572 /// If this variable is contextual the initial `map` call is deferred until first usage of the mapping variable. The
573 /// mapping variable is also contextual and will init for every context it is used in.
574 ///
575 /// The mapping variable has the same capabilities of the inner variable, plus [`MODIFY_CHANGES`]. When the inner variable
576 /// is writeable the return variable is too.
577 ///
578 /// [`map`]: Var::map
579 /// [`MODIFY_CHANGES`]: crate::VarCapability::MODIFY_CHANGES
580 pub fn flat_map<O: VarValue>(&self, mut map: impl FnMut(&T) -> Var<O> + Send + 'static) -> Var<O> {
581 self.any.flat_map(move |v| map(v.downcast_ref::<T>().unwrap()))
582 }
583}
584impl<T: VarValue> Var<crate::VarEq<T>> {
585 /// Create a [`flat_map`] to the inner variable.
586 ///
587 /// [`flat_map`]: Self::flat_map
588 pub fn flatten(&self) -> Var<T> {
589 self.flat_map(|v| v.0.clone())
590 }
591}
592/// Binding
593impl<T: VarValue> Var<T> {
594 /// Bind `other` to receive the new values from this variable.
595 ///
596 /// # Examples
597 ///
598 /// Basic usage:
599 ///
600 /// ```
601 /// # use zng_var::*;
602 /// #
603 /// let a = var(10);
604 /// let b = var(0);
605 ///
606 /// a.bind(&b).perm();
607 /// ```
608 ///
609 /// In the example above the variable `b` will be set every time the variable `a` updates. Note that the current
610 /// value is not propagated, only updates. You can use [`set_bind`] to assign the current value and bind.
611 ///
612 /// # Capabilities
613 ///
614 /// If this variable is const or the other variable is always read-only does nothing and returns a dummy handle.
615 ///
616 /// If any variable is contextual the binding is set on the current context inner variable.
617 ///
618 /// Neither variable holds the other, only a weak reference is used, if either variable or the handle is dropped the binding
619 /// is dropped.
620 ///
621 /// [`set_bind`]: Self::set_bind
622 pub fn bind(&self, other: &Var<T>) -> VarHandle {
623 self.any.bind(other)
624 }
625
626 /// Like [`bind`] but also sets `other` to the current value.
627 ///
628 /// Basic usage:
629 ///
630 /// ```
631 /// # fn demo() {
632 /// # use zng_var::*;
633 /// #
634 /// let a = var(10);
635 /// let b = var(0);
636 ///
637 /// a.set_bind(&b).perm();
638 /// # }
639 /// ```
640 ///
641 /// In the example above the variable `b` will be set to the current value of `a` and every time the variable `a` updates.
642 ///
643 /// # Capabilities
644 ///
645 /// If this variable is const or the other variable is always read-only does nothing and returns a dummy handle.
646 ///
647 /// If any variable is contextual the binding is set on the current context inner variable.
648 ///
649 /// Neither variable holds the other, only a weak reference is used, if either variable or the handle is dropped the binding
650 /// is dropped.
651 ///
652 /// [`bind`]: Self::bind
653 pub fn set_bind(&self, other: &Var<T>) -> VarHandle {
654 self.any.set_bind(other)
655 }
656
657 /// Bind `other` to receive the new values mapped from this variable.
658 ///
659 /// This has the same capabilities as [`bind`], but the `map` closure is called to produce the new value for `other`.
660 ///
661 /// # Examples
662 ///
663 /// Basic usage:
664 ///
665 /// ```
666 /// # use zng_var::*;
667 /// # use zng_txt::*;
668 /// let a = var(10);
669 /// let b = var(Txt::from(""));
670 ///
671 /// a.bind_map(&b, |&a| formatx!("{:?}", a * 2)).perm();
672 /// ```
673 ///
674 /// In the example above every time the variable `a` updates the variable `b` will be set to the text representation of the value times two.
675 ///
676 /// [`bind`]: Self::bind
677 pub fn bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> O + Send + 'static) -> VarHandle {
678 self.any.bind_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
679 }
680
681 /// Like [`bind_map`] but also sets `other` to the current value.
682 ///
683 /// This has the same capabilities as [`set_bind`], but the `map` closure is called to produce the new value for `other`.
684 ///
685 /// [`bind_map`]: Self::bind_map
686 /// [`set_bind`]: Self::set_bind
687 pub fn set_bind_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> O + Send + 'static) -> VarHandle {
688 self.any.set_bind_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
689 }
690
691 /// Bind `other` to be modified when this variable updates.
692 ///
693 /// This has the same capabilities as [`bind`], but the `modify` closure is called to modify `other` using a reference to the new value.
694 ///
695 /// # Examples
696 ///
697 /// Basic usage:
698 ///
699 /// ```
700 /// # use zng_var::*;
701 /// #
702 /// let a = var(10);
703 /// let b = var(vec![1, 2, 3]);
704 /// a.bind_modify(&b, |&a, b| {
705 /// if b.is_empty() {
706 /// b.push(a);
707 /// } else {
708 /// b[0] = a;
709 /// }
710 /// })
711 /// .perm();
712 /// ```
713 ///
714 /// In the example above the variable `b` first element is set to the updated value of `a`.
715 ///
716 /// [`bind`]: Self::bind
717 pub fn bind_modify<O: VarValue>(&self, other: &Var<O>, mut modify: impl FnMut(&T, &mut VarModify<O>) + Send + 'static) -> VarHandle {
718 self.any.bind_modify(other, move |v, m| modify(v.downcast_ref::<T>().unwrap(), m))
719 }
720
721 /// Bind `other` to receive the new values from this variable and this variable to receive new values from `other`.
722 ///
723 /// # Capabilities
724 ///
725 /// This has the same capabilities as [`bind`], it is equivalent of setting two bindings.
726 ///
727 /// The bindings are protected against cyclic updates, like all other mappings and bindings.
728 ///
729 /// [`bind`]: Self::bind
730 pub fn bind_bidi(&self, other: &Var<T>) -> VarHandles {
731 self.any.bind_bidi(other)
732 }
733
734 /// Bind `other` to receive the new mapped values from this variable and this variable to receive new mapped values from `other`.
735 ///
736 /// This has the same capabilities as [`bind_bidi`], but the `map` closure is called to produce the new value for `other`
737 /// and `map_back` is called to produce the new value for this variable.
738 ///
739 /// [`bind_bidi`]: Self::bind_bidi
740 pub fn bind_map_bidi<O: VarValue>(
741 &self,
742 other: &Var<O>,
743 mut map: impl FnMut(&T) -> O + Send + 'static,
744 mut map_back: impl FnMut(&O) -> T + Send + 'static,
745 ) -> VarHandles {
746 self.any.bind_map_bidi_any(
747 other,
748 move |v| BoxAnyVarValue::new(map(v.downcast_ref::<T>().unwrap())),
749 move |v| BoxAnyVarValue::new(map_back(v.downcast_ref::<O>().unwrap())),
750 )
751 }
752
753 /// Bind `other` to be modified when this variable updates and this variable to be modified when `other` updates.
754 ///
755 /// This has the same capabilities as [`bind_bidi`], but the `modify` closure is called to modify `other`
756 /// and `modify_back` is called to modify this variable.
757 ///
758 /// [`bind_bidi`]: Self::bind_bidi
759 pub fn bind_modify_bidi<O: VarValue>(
760 &self,
761 other: &Var<O>,
762 mut modify: impl FnMut(&T, &mut VarModify<O>) + Send + 'static,
763 mut modify_back: impl FnMut(&O, &mut VarModify<T>) + Send + 'static,
764 ) -> VarHandles {
765 self.any.bind_modify_bidi(
766 other,
767 move |v, m| modify(v.downcast_ref::<T>().unwrap(), m),
768 move |v, m| modify_back(v, &mut m.downcast::<T>().unwrap()),
769 )
770 }
771
772 /// Bind `other` to receive the new values filtered mapped from this variable.
773 ///
774 /// This has the same capabilities as [`bind_map`], except that `other` will only receive a new value if `map` returns a value.
775 ///
776 /// [`bind_map`]: Self::bind_map
777 pub fn bind_filter_map<O: VarValue>(&self, other: &Var<O>, mut map: impl FnMut(&T) -> Option<O> + Send + 'static) -> VarHandle {
778 self.any.bind_filter_map(other, move |v| map(v.downcast_ref::<T>().unwrap()))
779 }
780
781 /// Bind `other` to receive the new filtered mapped values from this variable and this variable to receive
782 /// new filtered mapped values from `other`.
783 pub fn bind_filter_map_bidi<O: VarValue>(
784 &self,
785 other: &Var<O>,
786 mut map: impl FnMut(&T) -> Option<O> + Send + 'static,
787 mut map_back: impl FnMut(&O) -> Option<T> + Send + 'static,
788 ) -> VarHandles {
789 self.any.bind_filter_map_bidi_any(
790 other,
791 move |v| map(v.downcast_ref::<T>().unwrap()).map(BoxAnyVarValue::new),
792 move |v| map_back(v.downcast_ref::<O>().unwrap()).map(BoxAnyVarValue::new),
793 )
794 }
795}
796/// Animation
797impl<T: VarValue> Var<T> {
798 /// Schedule a custom animation that targets this variable.
799 ///
800 /// The `animate` closure is called every frame, starting after next frame, the closure inputs are
801 /// the [`Animation`] args and *modify* access to the variable value, the args
802 /// can be used to calculate the new variable value and to control or stop the animation.
803 ///
804 /// # Examples
805 ///
806 /// Customs animation that displays the animation elapsed time:
807 ///
808 /// ```
809 /// # fn demo() {
810 /// # use zng_var::*;
811 /// # use zng_txt::*;
812 /// # use zng_unit::*;
813 /// let status = var(Txt::from("not animating"));
814 ///
815 /// status
816 /// .animate(|animation, value| {
817 /// let elapsed = animation.elapsed_dur();
818 /// if elapsed < 5.secs() {
819 /// value.set(formatx!("animating: elapsed {}ms", elapsed.as_millis()));
820 /// } else {
821 /// animation.stop();
822 /// value.set("not animating");
823 /// }
824 /// })
825 /// .perm();
826 /// # }
827 /// ```
828 ///
829 /// # Capabilities
830 ///
831 /// If the variable is always read-only no animation is created and a dummy handle returned.
832 ///
833 /// If this var is contextual the animation targets the current context var.
834 ///
835 /// The animation is stopped if this variable is dropped.
836 ///
837 /// [`Animation`]: Animation
838 pub fn animate(&self, mut animate: impl FnMut(&Animation, &mut VarModify<T>) + Send + 'static) -> AnimationHandle {
839 self.any.animate(move |a, v| animate(a, &mut v.downcast::<T>().unwrap()))
840 }
841
842 /// Schedule animations started by `animate`, the closure is called once at the start to begin, then again every time
843 /// the variable stops animating.
844 ///
845 /// This can be used to create a sequence of animations or to repeat an animation.
846 ///
847 /// # Examples
848 ///
849 /// Running multiple animations in sequence:
850 ///
851 /// ```
852 /// # fn demo() {
853 /// # use zng_var::{*, animation::*};
854 /// # use zng_txt::*;
855 /// # use zng_unit::*;
856 /// let status = var(Txt::from("not animating"));
857 ///
858 /// let mut stage = 0;
859 /// status
860 /// .sequence(move |status| {
861 /// stage += 1;
862 /// if stage < 5 {
863 /// status.animate(move |animation, value| {
864 /// let elapsed = animation.elapsed_stop(5.secs());
865 /// value.set(formatx!("animation {stage}: {}", elapsed.pct()));
866 /// })
867 /// } else {
868 /// status.set("not animating");
869 /// AnimationHandle::dummy()
870 /// }
871 /// })
872 /// .perm();
873 /// # }
874 /// ```
875 ///
876 /// # Capabilities
877 ///
878 /// The sequence stops when `animate` returns a dummy handle, or the variable is modified outside of `animate`,
879 /// or animations are disabled, or the returned handle is dropped.
880 pub fn sequence(&self, mut animate: impl FnMut(Var<T>) -> AnimationHandle + Send + 'static) -> VarHandle {
881 self.any.sequence(move |v| animate(Var::new_any(v)))
882 }
883
884 /// Schedule an easing transition from the `start_value` to `end_value`.
885 ///
886 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
887 ///
888 /// # Examples
889 ///
890 /// Basic usage:
891 ///
892 /// ```
893 /// # fn demo() {
894 /// # use zng_var::{*, animation::easing};
895 /// # use zng_unit::*;
896 /// let progress = var(0.pct());
897 ///
898 /// progress.set_ease(0.pct(), 100.pct(), 5.secs(), easing::linear).perm();
899 /// # }
900 /// ```
901 ///
902 /// Variable is reset to 0% at the start and them transition to 100% in 5 seconds with linear progression.
903 ///
904 /// # Capabilities
905 ///
906 /// See [`animate`] for details about animation capabilities.
907 ///
908 /// [`animate`]: Self::animate
909 pub fn set_ease(
910 &self,
911 start_value: impl Into<T>,
912 end_value: impl Into<T>,
913 duration: Duration,
914 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
915 ) -> AnimationHandle
916 where
917 T: Transitionable,
918 {
919 self.set_ease_with(start_value, end_value, duration, easing, Transition::sample)
920 }
921
922 /// Oscillate between `start_value` to `end_value` with an easing transition.
923 ///
924 /// The `duration` defines the easing duration between the two values. The animation will continue running
925 /// until the handle or the variable is dropped.
926 ///
927 /// Note that you can use [`sequence`] to create more complex looping animations.
928 ///
929 /// [`sequence`]: Var::sequence
930 pub fn set_ease_oci(
931 &self,
932 start_value: impl Into<T>,
933 end_value: impl Into<T>,
934 duration: Duration,
935 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
936 ) -> AnimationHandle
937 where
938 T: Transitionable,
939 {
940 self.set_ease_oci_with(start_value, end_value, duration, easing, Transition::sample)
941 }
942
943 /// Schedule an easing transition from the `start_value` to `end_value` using a custom value sampler.
944 ///
945 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
946 ///
947 /// See [`animate`] for details about animation capabilities.
948 ///
949 /// [`animate`]: Self::animate
950 pub fn set_ease_with(
951 &self,
952 start_value: impl Into<T>,
953 end_value: impl Into<T>,
954 duration: Duration,
955 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
956 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
957 ) -> AnimationHandle
958 where
959 T: Transitionable,
960 {
961 self.ease_impl(start_value.into(), end_value.into(), duration, easing, 999.fct(), sampler)
962 }
963
964 /// Oscillate between `start_value` to `end_value` with an easing transition using a custom value sampler.
965 ///
966 /// The `duration` defines the easing duration between the two values.
967 ///
968 /// Note that you can use [`sequence`] to create more complex looping animations.
969 ///
970 /// [`sequence`]: Self::sequence
971 pub fn set_ease_oci_with(
972 &self,
973 start_value: impl Into<T>,
974 end_value: impl Into<T>,
975 duration: Duration,
976 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
977 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
978 ) -> AnimationHandle
979 where
980 T: Transitionable,
981 {
982 self.ease_oci_impl(start_value.into(), end_value.into(), duration, easing, 999.fct(), sampler)
983 }
984
985 /// Schedule an easing transition from the current value to `new_value`.
986 ///
987 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
988 ///
989 /// See [`animate`] for details about animation capabilities.
990 ///
991 /// [`animate`]: Var::animate
992 pub fn ease(
993 &self,
994 new_value: impl Into<T>,
995 duration: Duration,
996 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
997 ) -> AnimationHandle
998 where
999 T: Transitionable,
1000 {
1001 self.ease_with(new_value, duration, easing, Transition::sample)
1002 }
1003
1004 /// Oscillate between the current value and `new_value` with an easing transition.
1005 ///
1006 /// The `duration` defines the easing duration between the two values.
1007 ///
1008 /// Note that you can use [`sequence`] to create more complex looping animations.
1009 ///
1010 /// [`sequence`]: Var::sequence
1011 pub fn ease_oci(
1012 &self,
1013 new_value: impl Into<T>,
1014 duration: Duration,
1015 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1016 ) -> AnimationHandle
1017 where
1018 T: Transitionable,
1019 {
1020 self.ease_oci_with(new_value, duration, easing, Transition::sample)
1021 }
1022
1023 /// Schedule an easing transition from the current value to `new_value` using a custom value sampler.
1024 ///
1025 /// The variable updates every time the [`EasingStep`] for each frame changes and a different value is sampled.
1026 ///
1027 /// See [`animate`] for details about animation capabilities.
1028 ///
1029 /// [`animate`]: Var::animate
1030 pub fn ease_with(
1031 &self,
1032 new_value: impl Into<T>,
1033 duration: Duration,
1034 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1035 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1036 ) -> AnimationHandle
1037 where
1038 T: Transitionable,
1039 {
1040 self.ease_impl(self.get(), new_value.into(), duration, easing, 0.fct(), sampler)
1041 }
1042
1043 /// Oscillate between the current value and `new_value` with an easing transition and a custom value sampler.
1044 ///
1045 /// The `duration` defines the easing duration between the two values.
1046 ///
1047 /// Note that you can use [`sequence`] to create more complex looping animations.
1048 ///
1049 /// [`sequence`]: Self::sequence
1050 pub fn ease_oci_with(
1051 &self,
1052 new_value: impl Into<T>,
1053 duration: Duration,
1054 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1055 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1056 ) -> AnimationHandle
1057 where
1058 T: Transitionable,
1059 {
1060 self.ease_oci_impl(self.get(), new_value.into(), duration, easing, 0.fct(), sampler)
1061 }
1062
1063 /// Schedule a keyframed transition animation for the variable, starting from the first key.
1064 ///
1065 /// The variable will be set to the first keyframe, then animated across all other keys.
1066 ///
1067 /// See [`animate`] for details about animations.
1068 ///
1069 /// [`animate`]: Self::animate
1070 pub fn set_ease_keyed(
1071 &self,
1072 keys: Vec<(Factor, T)>,
1073 duration: Duration,
1074 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1075 ) -> AnimationHandle
1076 where
1077 T: Transitionable,
1078 {
1079 self.set_ease_keyed_with(keys, duration, easing, TransitionKeyed::sample)
1080 }
1081
1082 /// Schedule a keyframed transition animation for the variable, starting from the first key, using a custom value sampler.
1083 ///
1084 /// The variable will be set to the first keyframe, then animated across all other keys.
1085 ///
1086 /// See [`animate`] for details about animations.
1087 ///
1088 /// [`animate`]: Self::animate
1089 pub fn set_ease_keyed_with(
1090 &self,
1091 keys: Vec<(Factor, T)>,
1092 duration: Duration,
1093 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1094 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1095 ) -> AnimationHandle
1096 where
1097 T: Transitionable,
1098 {
1099 if let Some(transition) = TransitionKeyed::new(keys) {
1100 self.ease_keyed_impl(transition, duration, easing, 999.fct(), sampler)
1101 } else {
1102 AnimationHandle::dummy()
1103 }
1104 }
1105
1106 /// Schedule a keyframed transition animation for the variable, starting from the current value.
1107 ///
1108 /// The variable will be set to the first keyframe, then animated across all other keys.
1109 ///
1110 /// See [`animate`] for details about animations.
1111 ///
1112 /// [`animate`]: Self::animate
1113 pub fn ease_keyed(
1114 &self,
1115 keys: Vec<(Factor, T)>,
1116 duration: Duration,
1117 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1118 ) -> AnimationHandle
1119 where
1120 T: Transitionable,
1121 {
1122 self.ease_keyed_with(keys, duration, easing, TransitionKeyed::sample)
1123 }
1124
1125 /// Schedule a keyframed transition animation for the variable, starting from the current value, using a custom value sampler.
1126 ///
1127 /// The variable will be set to the first keyframe, then animated across all other keys.
1128 ///
1129 /// See [`animate`] for details about animations.
1130 ///
1131 /// [`animate`]: Self::animate
1132 pub fn ease_keyed_with(
1133 &self,
1134 mut keys: Vec<(Factor, T)>,
1135 duration: Duration,
1136 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1137 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1138 ) -> AnimationHandle
1139 where
1140 T: Transitionable,
1141 {
1142 keys.insert(0, (0.fct(), self.get()));
1143
1144 let transition = TransitionKeyed::new(keys).unwrap();
1145 self.ease_keyed_impl(transition, duration, easing, 0.fct(), sampler)
1146 }
1147
1148 /// Set the variable to `new_value` after a `delay`.
1149 ///
1150 /// The variable [`is_animating`] until the delay elapses and the value is set.
1151 ///
1152 /// See [`animate`] for details about animations.
1153 ///
1154 /// [`is_animating`]: AnyVar::is_animating
1155 /// [`animate`]: Self::animate
1156 pub fn step(&self, new_value: impl Into<T>, delay: Duration) -> AnimationHandle {
1157 self.step_impl(new_value.into(), delay)
1158 }
1159
1160 /// Oscillate between the current value and `new_value`, every time the `delay` elapses the variable is set to the next value.
1161 pub fn step_oci(&self, new_value: impl Into<T>, delay: Duration) -> AnimationHandle {
1162 self.step_oci_impl([self.get(), new_value.into()], delay, false)
1163 }
1164
1165 /// Oscillate between `from` and `to`, the variable is set to `from` to start and every time the `delay` elapses
1166 /// the variable is set to the next value.
1167 pub fn set_step_oci(&self, from: impl Into<T>, to: impl Into<T>, delay: Duration) -> AnimationHandle {
1168 self.step_oci_impl([from.into(), to.into()], delay, true)
1169 }
1170
1171 /// Set the variable to a sequence of values as a time `duration` elapses.
1172 ///
1173 /// An animation curve is used to find the first factor in `steps` above or at the curve line at the current time,
1174 /// the variable is set to this step value, continuing animating across the next steps until the last or the animation end.
1175 /// The variable [`is_animating`] from the start, even if no step applies and stays *animating* until the last *step* applies
1176 /// or the duration is reached.
1177 ///
1178 /// # Examples
1179 ///
1180 /// Creates a variable that outputs text every 5% of a 5 seconds animation, advanced linearly.
1181 ///
1182 /// ```
1183 /// # use zng_var::{*, animation::easing};
1184 /// # use zng_txt::*;
1185 /// # use zng_unit::*;
1186 /// # fn demo(text_var: Var<Txt>) {
1187 /// let steps = (0..=100).step_by(5).map(|i| (i.pct().fct(), formatx!("{i}%"))).collect();
1188 /// # let _ =
1189 /// text_var.steps(steps, 5.secs(), easing::linear)
1190 /// # ;}
1191 /// ```
1192 ///
1193 /// The variable is set to `"0%"`, after 5% of the `duration` elapses it is set to `"5%"` and so on
1194 /// until the value is set to `"100%` at the end of the animation.
1195 ///
1196 /// Returns an [`AnimationHandle`]. See [`Var::animate`] for details about animations.
1197 ///
1198 /// [`is_animating`]: AnyVar::is_animating
1199 /// [`AnimationHandle`]: crate::animation::AnimationHandle
1200 pub fn steps(
1201 &self,
1202 steps: Vec<(Factor, T)>,
1203 duration: Duration,
1204 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1205 ) -> AnimationHandle {
1206 let mut prev_step = 999.fct();
1207 self.animate(move |a, vm| {
1208 let step = easing(a.elapsed_stop(duration));
1209 if step != prev_step {
1210 prev_step = step;
1211 if let Some(val) = steps.iter().find(|(f, _)| *f >= step).map(|(_, step)| step.clone()) {
1212 vm.set(val);
1213 }
1214 }
1215 })
1216 }
1217
1218 /// Starts an easing animation that *chases* a target value that can be changed using the [`ChaseAnimation<T>`] handle.
1219 pub fn chase(
1220 &self,
1221 first_target: impl Into<T>,
1222 duration: Duration,
1223 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1224 ) -> ChaseAnimation<T>
1225 where
1226 T: Transitionable,
1227 {
1228 self.chase_impl(first_target.into(), duration, easing)
1229 }
1230 fn chase_impl(
1231 &self,
1232 first_target: T,
1233 duration: Duration,
1234 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1235 ) -> ChaseAnimation<T>
1236 where
1237 T: Transitionable,
1238 {
1239 ChaseAnimation {
1240 handle: self.ease(first_target.clone(), duration, easing),
1241 target: first_target,
1242 var: self.current_context(),
1243 }
1244 }
1245
1246 /// Create a vars that [`ease`] to each new value of `self`.
1247 ///
1248 /// Note that the mapping var can be [contextualized], see [`map`] for more details.
1249 ///
1250 /// If `self` can change the output variable will keep it alive.
1251 ///
1252 /// [contextualized]: crate::contextual_var
1253 /// [`ease`]: Var::ease
1254 /// [`map`]: Var::map
1255 pub fn easing(&self, duration: Duration, easing: impl Fn(EasingTime) -> EasingStep + Send + Sync + 'static) -> Var<T>
1256 where
1257 T: Transitionable,
1258 {
1259 self.easing_with(duration, easing, Transition::sample)
1260 }
1261
1262 /// Create a vars that [`ease_with`] to each new value of `self`.
1263 ///
1264 /// Note that the mapping var can be contextualized, see [`map`] for more details.
1265 /// If `self` is shared the output variable will hold a strong reference to it.
1266 ///
1267 /// [`ease_with`]: Var::ease_with
1268 /// [`map`]: Var::map
1269 pub fn easing_with(
1270 &self,
1271 duration: Duration,
1272 easing: impl Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
1273 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + Sync + 'static,
1274 ) -> Var<T>
1275 where
1276 T: Transitionable,
1277 {
1278 let caps = self.capabilities();
1279 if caps.is_const() {
1280 return self.clone();
1281 }
1282
1283 let fns = Arc::new((easing, sampler));
1284
1285 if caps.is_contextual() {
1286 let me = self.clone();
1287 return contextual_var(move || me.clone().easing_with_tail(duration, fns.clone()));
1288 }
1289
1290 self.easing_with_tail(duration, fns)
1291 }
1292 // to avoid infinite closure type (contextual case)
1293 fn easing_with_tail(
1294 &self,
1295 duration: Duration,
1296 fns: Arc<(
1297 impl Fn(EasingTime) -> Factor + Send + Sync + 'static,
1298 impl Fn(&Transition<T>, Factor) -> T + Send + Sync + 'static,
1299 )>,
1300 ) -> Var<T>
1301 where
1302 T: Transitionable,
1303 {
1304 let me = self.current_context();
1305
1306 let output = crate::var(me.get());
1307
1308 let weak_output = output.downgrade();
1309 let mut _ease_handle = AnimationHandle::dummy();
1310 me.hook(move |args| {
1311 if let Some(output) = weak_output.upgrade() {
1312 _ease_handle = output.ease_with(
1313 args.value().clone(),
1314 duration,
1315 clmv!(fns, |t| fns.0(t)),
1316 clmv!(fns, |t, s| fns.1(t, s)),
1317 );
1318 true
1319 } else {
1320 false
1321 }
1322 })
1323 .perm();
1324 output.hold(me).perm();
1325
1326 output.read_only()
1327 }
1328
1329 fn ease_impl(
1330 &self,
1331 start_value: T,
1332 end_value: T,
1333 duration: Duration,
1334 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1335 init_step: Factor, // set to 0 skips first frame, set to 999 includes first frame.
1336 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1337 ) -> AnimationHandle
1338 where
1339 T: Transitionable,
1340 {
1341 let transition = Transition::new(start_value, end_value);
1342 let mut prev_step = init_step;
1343 self.animate(move |a, vm| {
1344 let step = easing(a.elapsed_stop(duration));
1345
1346 if prev_step != step {
1347 vm.set(sampler(&transition, step));
1348 prev_step = step;
1349 }
1350 })
1351 }
1352
1353 fn ease_oci_impl(
1354 &self,
1355 start_value: T,
1356 end_value: T,
1357 duration: Duration,
1358 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1359 init_step: EasingStep, // set to 0 skips first frame, set to 999 includes first frame.
1360 sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
1361 ) -> AnimationHandle
1362 where
1363 T: Transitionable,
1364 {
1365 let transition = Transition::new(start_value, end_value);
1366 let mut prev_step = init_step;
1367 self.animate(move |a, vm| {
1368 let t = a.elapsed(duration);
1369 let mut step = easing(t);
1370 if a.restart_count() % 2 != 0 {
1371 step = step.flip()
1372 }
1373 if t.is_end() {
1374 a.restart();
1375 }
1376
1377 if prev_step != step {
1378 vm.set(sampler(&transition, step));
1379 prev_step = step;
1380 }
1381 })
1382 }
1383
1384 fn ease_keyed_impl(
1385 &self,
1386 transition: TransitionKeyed<T>,
1387 duration: Duration,
1388 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
1389 init_step: EasingStep,
1390 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
1391 ) -> AnimationHandle
1392 where
1393 T: Transitionable,
1394 {
1395 let mut prev_step = init_step;
1396 self.animate(move |a, value| {
1397 let step = easing(a.elapsed_stop(duration));
1398
1399 if prev_step != step {
1400 value.set(sampler(&transition, step));
1401 prev_step = step;
1402 }
1403 })
1404 }
1405
1406 fn step_impl(&self, new_value: T, delay: Duration) -> AnimationHandle {
1407 let mut new_value = Some(new_value);
1408 self.animate(move |a, vm| {
1409 if !a.animations_enabled() || a.elapsed_dur() >= delay {
1410 a.stop();
1411 if let Some(nv) = new_value.take() {
1412 vm.set(nv);
1413 }
1414 } else {
1415 a.sleep(delay);
1416 }
1417 })
1418 }
1419
1420 fn step_oci_impl(&self, values: [T; 2], delay: Duration, mut set: bool) -> AnimationHandle {
1421 let mut first = false;
1422 self.animate(move |a, vm| {
1423 if !a.animations_enabled() || std::mem::take(&mut set) {
1424 vm.set(values[0].clone());
1425 } else if a.elapsed_dur() >= delay {
1426 if first {
1427 vm.set(values[0].clone());
1428 } else {
1429 vm.set(values[1].clone());
1430 }
1431 first = !first;
1432 }
1433 a.sleep(delay);
1434 })
1435 }
1436}
1437/// Transition animations
1438impl<T: VarValue + Transitionable> Var<T> {}
1439/// Value type.
1440impl<T: VarValue> Var<T> {
1441 /// Reference the variable without the strong value type.
1442 pub fn as_any(&self) -> &AnyVar {
1443 &self.any
1444 }
1445}
1446/// Variable type.
1447impl<T: VarValue> Var<T> {
1448 /// Create a weak reference to this variable.
1449 pub fn downgrade(&self) -> WeakVar<T> {
1450 WeakVar {
1451 any: self.any.downgrade(),
1452 _t: PhantomData,
1453 }
1454 }
1455
1456 /// Gets a clone of the var that is always read-only.
1457 ///
1458 /// The returned variable can still update if `self` is modified, but it does not have the `MODIFY` capability.
1459 pub fn read_only(&self) -> Var<T> {
1460 Var::new_any(self.any.read_only())
1461 }
1462
1463 /// Create a var that redirects to this variable until the first value update, then it disconnects as a separate variable.
1464 ///
1465 /// The return variable is *clone-on-write* and has the `MODIFY` capability independent of the source capabilities, when
1466 /// a modify request is made the source value is cloned and offered for modification, if modified the source variable is dropped,
1467 /// if the modify closure does not update the source variable is retained.
1468 pub fn cow(&self) -> Var<T> {
1469 Var::new_any(self.any.cow())
1470 }
1471
1472 /// Gets the underlying var in the current calling context.
1473 ///
1474 /// If this variable is [`CONTEXT`] returns a clone of the inner variable,
1475 /// otherwise returns a clone of this variable.
1476 ///
1477 /// [`CONTEXT`]: crate::VarCapability::CONTEXT
1478 pub fn current_context(&self) -> Var<T> {
1479 Var::new_any(self.any.current_context())
1480 }
1481
1482 /// Gets if this variable is the same as `other`.
1483 ///
1484 /// If this variable is [`SHARE`] compares the *pointer*. If this variable is local this is always `false`.
1485 ///
1486 /// [`SHARE`]: crate::VarCapability::SHARE
1487 pub fn var_eq(&self, other: &Self) -> bool {
1488 self.any.var_eq(&other.any)
1489 }
1490}
1491
1492/// Weak reference to a [`Var<T>`].
1493pub struct WeakVar<T: VarValue> {
1494 any: WeakAnyVar,
1495 _t: PhantomData<T>,
1496}
1497impl<T: VarValue> fmt::Debug for WeakVar<T> {
1498 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1499 f.debug_tuple("WeakVar").field(&self.any.0).finish()
1500 }
1501}
1502impl<T: VarValue> Clone for WeakVar<T> {
1503 fn clone(&self) -> Self {
1504 Self {
1505 any: self.any.clone(),
1506 _t: PhantomData,
1507 }
1508 }
1509}
1510impl<T: VarValue> From<WeakVar<T>> for WeakAnyVar {
1511 fn from(var: WeakVar<T>) -> Self {
1512 var.any
1513 }
1514}
1515impl<T: VarValue> ops::Deref for WeakVar<T> {
1516 type Target = WeakAnyVar;
1517
1518 fn deref(&self) -> &Self::Target {
1519 self.as_any()
1520 }
1521}
1522impl<T: VarValue> WeakVar<T> {
1523 /// Reference the weak variable without the strong value type.
1524 pub fn as_any(&self) -> &WeakAnyVar {
1525 &self.any
1526 }
1527
1528 /// Attempt to create a strong reference to the variable.
1529 pub fn upgrade(&self) -> Option<Var<T>> {
1530 self.any.upgrade().map(Var::new_any)
1531 }
1532}
1533
1534/// New read/write shared reference variable from any type that can convert into it.
1535pub fn var_from<T: VarValue>(initial_value: impl Into<T>) -> Var<T> {
1536 crate::var(initial_value.into())
1537}
1538
1539/// New read/write shared reference variable with default initial value.
1540pub fn var_default<T: VarValue + Default>() -> Var<T> {
1541 crate::var(T::default())
1542}
1543
1544/// New immutable variable that stores the `value` directly.
1545///
1546/// Cloning this variable clones the value.
1547pub fn const_var<T: VarValue>(value: T) -> Var<T> {
1548 Var::new_any(any_const_var(BoxAnyVarValue::new(value)))
1549}
1550
1551/// Type erased [`const_var`].
1552pub fn any_const_var(value: BoxAnyVarValue) -> AnyVar {
1553 AnyVar(crate::DynAnyVar::Const(crate::var_impl::const_var::ConstVar::new(value)))
1554}
1555
1556/// Weak variable that never upgrades.
1557pub fn weak_var<T: VarValue>() -> WeakVar<T> {
1558 WeakVar {
1559 any: weak_var_any(),
1560 _t: PhantomData,
1561 }
1562}
1563
1564/// Weak variable that never upgrades.
1565pub fn weak_var_any() -> WeakAnyVar {
1566 WeakAnyVar(crate::DynWeakAnyVar::Const(crate::var_impl::const_var::WeakConstVar))
1567}
1568
1569/// Arguments for [`Var::hook`].
1570pub struct VarHookArgs<'a, T: VarValue> {
1571 pub(super) any: &'a AnyVarHookArgs<'a>,
1572 pub(super) _t: PhantomData<&'a T>,
1573}
1574impl<'a, T: VarValue> VarHookArgs<'a, T> {
1575 /// Reference the updated value.
1576 pub fn value(&self) -> &'a T {
1577 self.any.value.downcast_ref::<T>().unwrap()
1578 }
1579}
1580impl<'a, T: VarValue> ops::Deref for VarHookArgs<'a, T> {
1581 type Target = AnyVarHookArgs<'a>;
1582
1583 fn deref(&self) -> &Self::Target {
1584 self.any
1585 }
1586}