1use std::{
2 any::{Any, TypeId},
3 fmt,
4 marker::PhantomData,
5 ops,
6 sync::{Arc, atomic::AtomicBool},
7};
8
9use crate::{
10 AnyVarHookArgs, AnyVarValue, BoxAnyVarValue, VarInstanceTag, VarUpdateId, VarValue,
11 animation::{AnimationStopFn, ModifyInfo},
12 read_only_var::ReadOnlyImpl,
13};
14use bitflags::bitflags;
15use smallbox::{SmallBox, smallbox};
16
17pub(crate) mod shared_var;
18pub use shared_var::{any_var, any_var_derived, var, var_derived, var_getter, var_state};
19
20pub(crate) mod const_var;
21pub(crate) mod cow_var;
22pub use const_var::IntoVar;
23pub(crate) mod flat_map_var;
24pub(crate) mod read_only_var;
25
26pub(crate) mod contextual_var;
27pub use contextual_var::{ContextInitHandle, WeakContextInitHandle, any_contextual_var, contextual_var};
28
29pub(crate) mod context_var;
30pub use context_var::{__context_var_local, ContextVar, context_var_init};
31
32pub(crate) mod merge_var;
33pub use merge_var::{
34 __merge_var, MergeInput, MergeVarBuilder, VarMergeInputs, merge_var, merge_var_input, merge_var_output, merge_var_with,
35};
36
37pub(crate) mod response_var;
38pub use response_var::{ResponderVar, Response, ResponseVar, response_done_var, response_var};
39
40pub(crate) mod when_var;
41pub use when_var::{__when_var, AnyWhenVarBuilder, WhenVarBuilder};
42
43pub(crate) mod expr_var;
44pub use expr_var::{__expr_var, expr_var_as, expr_var_into, expr_var_map};
45
46pub(crate) enum DynAnyVar {
47 Const(const_var::ConstVar),
48 Merge(merge_var::MergeVar),
49 When(when_var::WhenVar),
50
51 Shared(shared_var::SharedVar),
52 Context(context_var::ContextVarImpl),
53 FlatMap(flat_map_var::FlatMapVar),
54 Cow(cow_var::CowVar),
55 Contextual(contextual_var::ContextualVar),
56
57 ReadOnlyShared(ReadOnlyImpl<shared_var::SharedVar>),
58 ReadOnlyFlatMap(ReadOnlyImpl<flat_map_var::FlatMapVar>),
59 ReadOnlyContext(ReadOnlyImpl<context_var::ContextVarImpl>),
60 ReadOnlyCow(ReadOnlyImpl<cow_var::CowVar>),
61 ReadOnlyContextual(ReadOnlyImpl<contextual_var::ContextualVar>),
62}
63macro_rules! dispatch {
64 ($self:ident, $var:ident => $($tt:tt)+) => {
65 match $self {
66 DynAnyVar::Const($var) => $($tt)+,
67 DynAnyVar::Merge($var) => $($tt)+,
68 DynAnyVar::FlatMap($var) => $($tt)+,
69 DynAnyVar::When($var) => $($tt)+,
70
71 DynAnyVar::Shared($var) => $($tt)+,
72 DynAnyVar::Context($var) => $($tt)+,
73 DynAnyVar::Cow($var) => $($tt)+,
74 DynAnyVar::Contextual($var) => $($tt)+,
75
76 DynAnyVar::ReadOnlyShared($var) => $($tt)+,
77 DynAnyVar::ReadOnlyFlatMap($var) => $($tt)+,
78 DynAnyVar::ReadOnlyContext($var) => $($tt)+,
79 DynAnyVar::ReadOnlyCow($var) => $($tt)+,
80 DynAnyVar::ReadOnlyContextual($var) => $($tt)+,
81 }
82 };
83}
84impl fmt::Debug for DynAnyVar {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 dispatch!(self, v => fmt::Debug::fmt(v, f))
87 }
88}
89
90pub(crate) enum DynWeakAnyVar {
91 Const(const_var::WeakConstVar),
92 Merge(merge_var::WeakMergeVar),
93 When(when_var::WeakWhenVar),
94
95 Shared(shared_var::WeakSharedVar),
96 Context(context_var::ContextVarImpl),
97 FlatMap(flat_map_var::WeakFlatMapVar),
98 Cow(cow_var::WeakCowVar),
99 Contextual(contextual_var::WeakContextualVar),
100
101 ReadOnlyShared(ReadOnlyImpl<shared_var::WeakSharedVar>),
102 ReadOnlyContext(ReadOnlyImpl<context_var::ContextVarImpl>),
103 ReadOnlyCow(ReadOnlyImpl<cow_var::WeakCowVar>),
104 ReadOnlyContextual(ReadOnlyImpl<contextual_var::WeakContextualVar>),
105 ReadOnlyFlatMap(ReadOnlyImpl<flat_map_var::WeakFlatMapVar>),
106}
107macro_rules! dispatch_weak {
108 ($self:ident, $var:ident => $($tt:tt)+) => {
109 match $self {
110 DynWeakAnyVar::Const($var) => $($tt)+,
111 DynWeakAnyVar::Shared($var) => $($tt)+,
112 DynWeakAnyVar::Context($var) => $($tt)+,
113 DynWeakAnyVar::Cow($var) => $($tt)+,
114 DynWeakAnyVar::Contextual($var) => $($tt)+,
115 DynWeakAnyVar::FlatMap($var) => $($tt)+,
116 DynWeakAnyVar::Merge($var) => $($tt)+,
117 DynWeakAnyVar::When($var) => $($tt)+,
118 DynWeakAnyVar::ReadOnlyShared($var) => $($tt)+,
119 DynWeakAnyVar::ReadOnlyContext($var) => $($tt)+,
120 DynWeakAnyVar::ReadOnlyCow($var) => $($tt)+,
121 DynWeakAnyVar::ReadOnlyContextual($var) => $($tt)+,
122 DynWeakAnyVar::ReadOnlyFlatMap($var) => $($tt)+,
123
124 }
125 };
126}
127impl fmt::Debug for DynWeakAnyVar {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 dispatch_weak!(self, v => fmt::Debug::fmt(v, f))
130 }
131}
132
133macro_rules! declare {
134 ($(
135 $(#[$meta:meta])*
136 fn $method:ident(&self $(, $arg:ident : $Input:ty)*) $(-> $Output:ty)?;
137 )+) => {
138 pub(crate) trait VarImpl: fmt::Debug + Any + Send + Sync {
139 $(
140 $(#[$meta])*
141 fn $method(&self $(, $arg: $Input)*) $(-> $Output)?;
142 )+
143 }
144
145 impl VarImpl for DynAnyVar {
146 $(
147 $(#[$meta])*
148 fn $method(&self $(, $arg: $Input)*) $(-> $Output)? {
149 dispatch!(self, v => VarImpl::$method(v$(, $arg)*))
150 }
151 )+
152 }
153 };
154}
155declare! {
156 fn clone_dyn(&self) -> DynAnyVar;
157 fn value_type(&self) -> TypeId;
158 #[cfg(feature = "type_names")]
159 fn value_type_name(&self) -> &'static str;
160 fn strong_count(&self) -> usize;
161 fn var_eq(&self, other: &DynAnyVar) -> bool;
162 fn var_instance_tag(&self) -> VarInstanceTag;
163 fn downgrade(&self) -> DynWeakAnyVar;
164 fn capabilities(&self) -> VarCapability;
165 fn with(&self, visitor: &mut dyn FnMut(&dyn AnyVarValue));
166 fn get(&self) -> BoxAnyVarValue;
167 fn set(&self, new_value: BoxAnyVarValue) -> bool;
168 fn update(&self) -> bool;
169 fn modify(&self, modify: SmallBox<dyn FnMut(&mut AnyVarModify) + Send + 'static, smallbox::space::S4>) -> bool;
170 fn hook(&self, on_new: SmallBox<dyn FnMut(&AnyVarHookArgs) -> bool + Send + 'static, smallbox::space::S4>) -> VarHandle;
171 fn last_update(&self) -> VarUpdateId;
172 fn modify_importance(&self) -> usize;
173 fn is_animating(&self) -> bool;
174 fn hook_animation_stop(&self, handler: AnimationStopFn) -> VarHandle;
175 fn current_context(&self) -> DynAnyVar;
176 fn modify_info(&self) -> ModifyInfo;
177}
178
179macro_rules! declare_weak {
180 ($(
181 fn $method:ident(&self $(, $arg:ident : $Input:ty)*) $(-> $Output:ty)?;
182 )+) => {
183 pub(crate) trait WeakVarImpl: fmt::Debug + Any + Send + Sync {
184 $(
185 fn $method(&self $(, $arg: $Input)*) $(-> $Output)?;
186 )+
187 }
188
189 impl WeakVarImpl for DynWeakAnyVar {
190 $(
191 fn $method(&self $(, $arg: $Input)*) $(-> $Output)? {
192 dispatch_weak!(self, v => WeakVarImpl::$method(v$(, $arg)*))
193 }
194 )+
195 }
196 };
197}
198declare_weak! {
199 fn clone_dyn(&self) -> DynWeakAnyVar;
200 fn strong_count(&self) -> usize;
201 fn upgrade(&self) -> Option<DynAnyVar>;
202}
203
204#[derive(Debug, Clone, Copy)]
208#[non_exhaustive]
209pub struct VarIsReadOnlyError {}
210impl fmt::Display for VarIsReadOnlyError {
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 write!(f, "cannot modify read-only variable")
213 }
214}
215impl std::error::Error for VarIsReadOnlyError {}
216
217bitflags! {
218 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
225 pub struct VarCapability: u8 {
226 const NEW = 0b0000_0010;
233
234 const MODIFY = 0b0000_0011;
243
244 const CONTEXT = 0b1000_0000;
246
247 const MODIFY_CHANGES = 0b0100_0000;
249 const CONTEXT_CHANGES = 0b0010_0000;
251
252 const SHARE = 0b0001_0000;
255 }
256}
257impl VarCapability {
258 pub fn is_const(self) -> bool {
260 self.is_empty()
261 }
262
263 pub fn is_always_read_only(&self) -> bool {
265 !self.contains(Self::MODIFY) && !self.contains(Self::MODIFY_CHANGES)
266 }
267
268 pub fn is_read_only(self) -> bool {
270 !self.can_modify()
271 }
272
273 pub fn can_modify(self) -> bool {
275 self.contains(Self::MODIFY)
276 }
277
278 pub fn is_contextual(self) -> bool {
280 self.contains(Self::CONTEXT)
281 }
282
283 pub fn is_always_contextual(self) -> bool {
285 self.contains(Self::CONTEXT) && !self.contains(Self::CONTEXT_CHANGES)
286 }
287
288 pub fn is_share(&self) -> bool {
290 self.contains(Self::SHARE)
291 }
292
293 pub fn is_local(&self) -> bool {
297 !self.is_share()
298 }
299}
300impl VarCapability {
301 pub(crate) fn as_always_read_only(self) -> Self {
302 let mut out = self;
303
304 out.remove(Self::MODIFY & !Self::NEW);
306 out.remove(Self::MODIFY_CHANGES);
308
309 out
310 }
311}
312
313bitflags! {
314 #[derive(Clone, Copy)]
315 pub(crate) struct VarModifyUpdate: u8 {
316 const UPDATE = 0b001;
318 const REQUESTED = 0b011;
320 const TOUCHED = 0b101;
322 }
323}
324
325pub struct AnyVarModify<'a> {
329 pub(crate) value: &'a mut BoxAnyVarValue,
330 pub(crate) update: VarModifyUpdate,
331 pub(crate) tags: Vec<BoxAnyVarValue>,
332 pub(crate) custom_importance: Option<usize>,
333}
334impl<'a> AnyVarModify<'a> {
335 pub fn set(&mut self, mut new_value: BoxAnyVarValue) -> bool {
339 if **self.value != *new_value {
340 if !self.value.try_swap(&mut *new_value) {
341 #[cfg(feature = "type_names")]
342 panic!(
343 "cannot AnyVarModify::set `{}` on variable of type `{}`",
344 new_value.type_name(),
345 self.value.type_name()
346 );
347 #[cfg(not(feature = "type_names"))]
348 panic!("cannot modify set, type mismatch");
349 }
350 self.update |= VarModifyUpdate::TOUCHED;
351 true
352 } else {
353 false
354 }
355 }
356
357 pub fn update(&mut self) {
359 self.update |= VarModifyUpdate::REQUESTED;
360 }
361
362 pub fn tags(&self) -> &[BoxAnyVarValue] {
367 &self.tags
368 }
369
370 pub fn push_tag(&mut self, tag: impl AnyVarValue) {
372 self.tags.push(BoxAnyVarValue::new(tag));
373 }
374
375 pub fn set_modify_importance(&mut self, importance: usize) {
383 self.custom_importance = Some(importance);
384 }
385
386 pub fn downcast<'s, T: VarValue>(&'s mut self) -> Option<VarModify<'s, 'a, T>> {
388 if self.value.is::<T>() {
389 Some(VarModify {
390 inner: self,
391 _t: PhantomData,
392 })
393 } else {
394 None
395 }
396 }
397
398 pub fn value(&self) -> &dyn AnyVarValue {
402 &**self
403 }
404
405 pub fn value_mut(&mut self) -> &mut dyn AnyVarValue {
411 &mut **self
412 }
413}
414impl<'a> ops::Deref for AnyVarModify<'a> {
415 type Target = dyn AnyVarValue;
416
417 fn deref(&self) -> &Self::Target {
418 &**self.value
419 }
420}
421impl<'a> ops::DerefMut for AnyVarModify<'a> {
422 fn deref_mut(&mut self) -> &mut Self::Target {
423 self.update |= VarModifyUpdate::TOUCHED;
424 self.value.deref_mut()
425 }
426}
427
428pub struct VarModify<'s, 'a, T: VarValue> {
432 inner: &'s mut AnyVarModify<'a>,
433 _t: PhantomData<fn() -> &'a T>,
434}
435impl<'s, 'a, T: VarValue> VarModify<'s, 'a, T> {
436 pub fn set(&mut self, new_value: impl Into<T>) -> bool {
440 let new_value = new_value.into();
441 if **self != new_value {
442 **self = new_value;
443 true
444 } else {
445 false
446 }
447 }
448
449 pub fn update(&mut self) {
451 self.inner.update();
452 }
453
454 pub fn tags(&self) -> &[BoxAnyVarValue] {
459 self.inner.tags()
460 }
461
462 pub fn push_tag(&mut self, tag: impl AnyVarValue) {
464 self.inner.push_tag(tag);
465 }
466
467 pub fn set_modify_importance(&mut self, importance: usize) {
475 self.inner.set_modify_importance(importance);
476 }
477
478 pub fn as_any(&mut self) -> &mut AnyVarModify<'a> {
480 self.inner
481 }
482
483 pub fn value(&self) -> &T {
487 self
488 }
489
490 pub fn value_mut(&mut self) -> &mut T {
496 self
497 }
498}
499impl<'s, 'a, T: VarValue> ops::Deref for VarModify<'s, 'a, T> {
500 type Target = T;
501
502 fn deref(&self) -> &Self::Target {
503 self.inner.downcast_ref().unwrap()
504 }
505}
506impl<'s, 'a, T: VarValue> ops::DerefMut for VarModify<'s, 'a, T> {
507 fn deref_mut(&mut self) -> &mut Self::Target {
508 self.inner.downcast_mut().unwrap()
509 }
510}
511
512#[derive(Clone, Default)]
520#[must_use = "var handle stops the behavior it represents on drop"]
521pub struct VarHandle(Option<Arc<AtomicBool>>);
522impl PartialEq for VarHandle {
523 fn eq(&self, other: &Self) -> bool {
524 if let Some(a) = &self.0
525 && let Some(b) = &other.0
526 {
527 Arc::ptr_eq(a, b)
528 } else {
529 false
530 }
531 }
532}
533impl fmt::Debug for VarHandle {
534 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535 if self.is_dummy() {
536 write!(f, "VarHandle(<dummy>)")
537 } else {
538 f.debug_tuple("VarHandle").finish_non_exhaustive()
539 }
540 }
541}
542impl VarHandle {
543 pub const fn dummy() -> Self {
545 VarHandle(None)
546 }
547
548 pub(crate) fn new() -> (VarHandlerOwner, Self) {
549 let h = Arc::new(AtomicBool::new(false));
550 (VarHandlerOwner(h.clone()), Self(Some(h)))
551 }
552
553 pub fn is_dummy(&self) -> bool {
557 self.0.is_none()
558 }
559
560 pub fn perm(self) {
564 if let Some(c) = &self.0 {
565 c.store(true, std::sync::atomic::Ordering::Relaxed);
566 }
567 }
568
569 pub fn chain(self, other: Self) -> VarHandles {
571 VarHandles(smallvec::smallvec![self, other])
572 }
573}
574pub(crate) struct VarHandlerOwner(Arc<AtomicBool>);
575impl fmt::Debug for VarHandlerOwner {
576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577 write!(f, "{}", Arc::strong_count(&self.0) - 1)?;
578 if self.0.load(std::sync::atomic::Ordering::Relaxed) {
579 write!(f, " perm")
580 } else {
581 Ok(())
582 }
583 }
584}
585impl VarHandlerOwner {
586 pub fn is_alive(&self) -> bool {
587 Arc::strong_count(&self.0) > 1 || self.0.load(std::sync::atomic::Ordering::Relaxed)
588 }
589}
590
591#[must_use = "var handles stops the behavior they represents on drop"]
593#[derive(Clone, Default)]
594pub struct VarHandles(smallvec::SmallVec<[VarHandle; 2]>);
595impl VarHandles {
596 pub const fn dummy() -> Self {
598 VarHandles(smallvec::SmallVec::new_const())
599 }
600
601 pub fn is_dummy(&self) -> bool {
603 self.0.is_empty() || self.0.iter().all(VarHandle::is_dummy)
604 }
605
606 pub fn perm(self) {
608 for handle in self.0 {
609 handle.perm()
610 }
611 }
612
613 pub fn push(&mut self, other: VarHandle) -> &mut Self {
615 if !other.is_dummy() {
616 self.0.push(other);
617 }
618 self
619 }
620
621 pub fn clear(&mut self) {
623 self.0.clear()
624 }
625}
626impl FromIterator<VarHandle> for VarHandles {
627 fn from_iter<T: IntoIterator<Item = VarHandle>>(iter: T) -> Self {
628 VarHandles(iter.into_iter().filter(|h| !h.is_dummy()).collect())
629 }
630}
631impl<const N: usize> From<[VarHandle; N]> for VarHandles {
632 fn from(handles: [VarHandle; N]) -> Self {
633 handles.into_iter().collect()
634 }
635}
636impl Extend<VarHandle> for VarHandles {
637 fn extend<T: IntoIterator<Item = VarHandle>>(&mut self, iter: T) {
638 for handle in iter {
639 self.push(handle);
640 }
641 }
642}
643impl IntoIterator for VarHandles {
644 type Item = VarHandle;
645
646 type IntoIter = smallvec::IntoIter<[VarHandle; 2]>;
647
648 fn into_iter(self) -> Self::IntoIter {
649 self.0.into_iter()
650 }
651}
652impl ops::Deref for VarHandles {
653 type Target = smallvec::SmallVec<[VarHandle; 2]>;
654
655 fn deref(&self) -> &Self::Target {
656 &self.0
657 }
658}
659impl ops::DerefMut for VarHandles {
660 fn deref_mut(&mut self) -> &mut Self::Target {
661 &mut self.0
662 }
663}
664impl From<VarHandle> for VarHandles {
665 fn from(value: VarHandle) -> Self {
666 let mut r = VarHandles::dummy();
667 r.push(value);
668 r
669 }
670}
671
672#[cfg(feature = "type_names")]
673fn value_type_name(var: &dyn VarImpl) -> &'static str {
674 var.value_type_name()
675}
676#[cfg(not(feature = "type_names"))]
677#[inline(always)]
678fn value_type_name(_: &dyn VarImpl) -> &'static str {
679 ""
680}