1use std::sync::{Arc, Weak};
2
3use crate::animation::AnimationHandle;
4
5use super::*;
6
7#[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#[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 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 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 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
120pub struct AnyWhenVarBuilder {
122 default: BoxedAnyVar,
123 conditions: Vec<(BoxedVar<bool>, BoxedAnyVar)>,
124}
125impl AnyWhenVarBuilder {
126 pub fn new<O: VarValue>(default: impl IntoVar<O>) -> Self {
128 Self::new_any(default.into_var().boxed_any())
129 }
130
131 pub fn new_any(default: BoxedAnyVar) -> AnyWhenVarBuilder {
133 Self {
134 default,
135 conditions: vec![],
136 }
137 }
138
139 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 pub fn condition_count(&self) -> usize {
158 self.conditions.len()
159 }
160
161 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 pub fn set_default_any(&mut self, default: BoxedAnyVar) {
168 self.default = default;
169 }
170
171 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 pub fn push_any(&mut self, condition: BoxedVar<bool>, value: BoxedAnyVar) {
183 self.conditions.push((condition, value));
184 }
185
186 pub fn replace_extend(&mut self, other: &Self) {
188 self.default = other.default.clone_any();
189 self.extend(other);
190 }
191
192 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 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
244pub struct ArcWhenVar<T>(Arc<Data>, PhantomData<T>);
246
247pub 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 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 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 pub fn default(&self) -> BoxedVar<T> {
401 *self.0.default.clone().double_boxed_any().downcast::<BoxedVar<T>>().unwrap()
402 }
403
404 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 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 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}