1use std::{
2 marker::PhantomData,
3 sync::{Arc, Weak},
4};
5
6use parking_lot::{RwLock, RwLockReadGuard};
7
8use super::{types::WeakContextInitHandle, *};
9
10#[cfg(feature = "dyn_closure")]
11macro_rules! ActualLock {
12 ($T:ident) => {
13 parking_lot::RwLock<Vec<(WeakContextInitHandle, Box<dyn Any + Send + Sync>)>>
14 }
15}
16#[cfg(not(feature = "dyn_closure"))]
17macro_rules! ActualLock {
18 ($T:ident) => {
19 parking_lot::RwLock<Vec<(WeakContextInitHandle, BoxedVar<$T>)>>
20 }
21}
22
23#[cfg(feature = "dyn_closure")]
24macro_rules! ActualInit {
25 ($T:ident) => {
26 Arc<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>
27 }
28}
29#[cfg(not(feature = "dyn_closure"))]
30macro_rules! ActualInit {
31 ($T:ident) => {
32 Arc<dyn Fn() -> BoxedVar<$T> + Send + Sync>
33 }
34}
35
36#[cfg(feature = "dyn_closure")]
37macro_rules! ActualReadGuard {
38 ($a:tt, $T:ident) => {
39 parking_lot::MappedRwLockReadGuard<$a, Box<dyn Any + Send + Sync>>
40 }
41}
42#[cfg(not(feature = "dyn_closure"))]
43macro_rules! ActualReadGuard {
44 ($a:tt, $T:ident) => {
45 parking_lot::MappedRwLockReadGuard<$a, BoxedVar<$T>>
46 }
47}
48
49pub struct ContextualizedVar<T> {
73 _type: PhantomData<T>,
74
75 init: ActualInit![T],
76 actual: ActualLock![T],
77}
78
79#[expect(clippy::extra_unused_type_parameters)]
80fn borrow_init_impl<'a, T>(
81 actual: &'a ActualLock![T],
82 init: &ActualInit![T],
83 #[cfg(debug_assertions)] type_name: &'static str,
84) -> ActualReadGuard!['a, T] {
85 let current_ctx = ContextInitHandle::current();
86 let current_ctx = current_ctx.downgrade();
87
88 let act = actual.read_recursive();
89
90 if let Some(i) = act.iter().position(|(h, _)| h == ¤t_ctx) {
91 return RwLockReadGuard::map(act, move |m| &m[i].1);
92 }
93 drop(act);
94
95 let mut actual_mut = actual.write();
96 actual_mut.retain(|(h, _)| h.is_alive());
97 let i = actual_mut.len();
98
99 #[cfg(debug_assertions)]
100 if i == 200 {
101 tracing::debug!("variable of type `{type_name}` actualized >200 times");
102 }
103
104 if !actual_mut.iter().any(|(c, _)| c == ¤t_ctx) {
105 actual_mut.push((current_ctx.clone(), init()));
106 }
107 drop(actual_mut);
108
109 let actual = actual.read_recursive();
110 RwLockReadGuard::map(actual, move |m| {
111 if i < m.len() && m[i].0 == current_ctx {
112 &m[i].1
113 } else if let Some(i) = m.iter().position(|(h, _)| h == ¤t_ctx) {
114 &m[i].1
115 } else {
116 unreachable!()
117 }
118 })
119}
120
121impl<T: VarValue> ContextualizedVar<T> {
122 pub fn new<V: Var<T>>(init: impl Fn() -> V + Send + Sync + 'static) -> Self {
127 Self {
128 _type: PhantomData,
129
130 #[cfg(feature = "dyn_closure")]
131 init: Arc::new(move || Box::new(init().boxed())),
132 #[cfg(not(feature = "dyn_closure"))]
133 init: Arc::new(move || init().boxed()),
134
135 actual: RwLock::new(Vec::with_capacity(1)),
136 }
137 }
138
139 pub fn new_value(init: impl Fn() -> T + Send + Sync + 'static) -> Self {
144 Self::new(move || init().into_var())
145 }
146
147 pub fn borrow_init(&self) -> parking_lot::MappedRwLockReadGuard<BoxedVar<T>> {
149 #[cfg(feature = "dyn_closure")]
150 {
151 parking_lot::MappedRwLockReadGuard::map(
152 borrow_init_impl::<()>(
153 &self.actual,
154 &self.init,
155 #[cfg(debug_assertions)]
156 std::any::type_name::<T>(),
157 ),
158 |v| v.downcast_ref().unwrap(),
159 )
160 }
161 #[cfg(not(feature = "dyn_closure"))]
162 {
163 borrow_init_impl(
164 &self.actual,
165 &self.init,
166 #[cfg(debug_assertions)]
167 std::any::type_name::<T>(),
168 )
169 }
170 }
171
172 pub fn into_init(self) -> BoxedVar<T> {
174 let mut act = self.actual.into_inner();
175 let current_ctx = ContextInitHandle::current().downgrade();
176
177 if let Some(i) = act.iter().position(|(h, _)| h == ¤t_ctx) {
178 #[cfg(feature = "dyn_closure")]
179 {
180 *act.swap_remove(i).1.downcast().unwrap()
181 }
182 #[cfg(not(feature = "dyn_closure"))]
183 {
184 act.swap_remove(i).1
185 }
186 } else {
187 #[cfg(feature = "dyn_closure")]
188 {
189 *(self.init)().downcast().unwrap()
190 }
191 #[cfg(not(feature = "dyn_closure"))]
192 {
193 (self.init)()
194 }
195 }
196 }
197}
198
199pub struct WeakContextualizedVar<T> {
201 _type: PhantomData<T>,
202
203 #[cfg(feature = "dyn_closure")]
204 init: Weak<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>,
205
206 #[cfg(not(feature = "dyn_closure"))]
207 init: Weak<dyn Fn() -> BoxedVar<T> + Send + Sync>,
208}
209
210impl<T: VarValue> Clone for ContextualizedVar<T> {
211 fn clone(&self) -> Self {
212 let current_ctx_id = ContextInitHandle::current().downgrade();
213 let act = self.actual.read_recursive();
214 if let Some(i) = act.iter().position(|(id, _)| *id == current_ctx_id) {
215 return Self {
216 _type: PhantomData,
217 init: self.init.clone(),
218 #[cfg(feature = "dyn_closure")]
219 actual: RwLock::new(vec![(
220 act[i].0.clone(),
221 Box::new(act[i].1.downcast_ref::<BoxedVar<T>>().unwrap().clone()),
222 )]),
223 #[cfg(not(feature = "dyn_closure"))]
224 actual: RwLock::new(vec![act[i].clone()]),
225 };
226 }
227 Self {
228 _type: PhantomData,
229 init: self.init.clone(),
230 actual: RwLock::default(),
231 }
232 }
233}
234impl<T: VarValue> Clone for WeakContextualizedVar<T> {
235 fn clone(&self) -> Self {
236 Self {
237 _type: PhantomData,
238 init: self.init.clone(),
239 }
240 }
241}
242
243impl<T: VarValue> crate::private::Sealed for ContextualizedVar<T> {}
244impl<T: VarValue> crate::private::Sealed for WeakContextualizedVar<T> {}
245
246impl<T: VarValue> AnyVar for ContextualizedVar<T> {
247 fn clone_any(&self) -> BoxedAnyVar {
248 Box::new(self.clone())
249 }
250
251 fn as_any(&self) -> &dyn Any {
252 self
253 }
254
255 fn as_unboxed_any(&self) -> &dyn Any {
256 self
257 }
258
259 fn double_boxed_any(self: Box<Self>) -> Box<dyn Any> {
260 let me: BoxedVar<T> = self;
261 Box::new(me)
262 }
263
264 fn var_type_id(&self) -> TypeId {
265 TypeId::of::<T>()
266 }
267
268 fn get_any(&self) -> Box<dyn AnyVarValue> {
269 Box::new(self.get())
270 }
271
272 fn with_any(&self, read: &mut dyn FnMut(&dyn AnyVarValue)) {
273 self.borrow_init().with_any(read)
274 }
275
276 fn with_new_any(&self, read: &mut dyn FnMut(&dyn AnyVarValue)) -> bool {
277 self.borrow_init().with_new_any(read)
278 }
279
280 fn set_any(&self, value: Box<dyn AnyVarValue>) -> Result<(), VarIsReadOnlyError> {
281 self.modify(var_set_any(value))
282 }
283
284 fn last_update(&self) -> VarUpdateId {
285 self.borrow_init().last_update()
286 }
287
288 fn is_contextual(&self) -> bool {
289 true
290 }
291
292 fn capabilities(&self) -> VarCapability {
293 self.borrow_init().capabilities()
294 }
295
296 fn hook_any(&self, pos_modify_action: Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync>) -> VarHandle {
297 self.borrow_init().hook_any(pos_modify_action)
298 }
299
300 fn hook_animation_stop(&self, handler: Box<dyn FnOnce() + Send>) -> Result<(), Box<dyn FnOnce() + Send>> {
301 self.borrow_init().hook_animation_stop(handler)
302 }
303
304 fn strong_count(&self) -> usize {
305 Arc::strong_count(&self.init)
306 }
307
308 fn weak_count(&self) -> usize {
309 Arc::weak_count(&self.init)
310 }
311
312 fn actual_var_any(&self) -> BoxedAnyVar {
313 self.borrow_init().actual_var_any()
314 }
315
316 fn downgrade_any(&self) -> BoxedAnyWeakVar {
317 Box::new(self.downgrade())
318 }
319
320 fn is_animating(&self) -> bool {
321 self.borrow_init().is_animating()
322 }
323
324 fn modify_importance(&self) -> usize {
325 self.borrow_init().modify_importance()
326 }
327
328 fn var_ptr(&self) -> VarPtr {
329 VarPtr::new_arc(&self.init)
330 }
331
332 fn get_debug(&self) -> Txt {
333 self.with(var_debug)
334 }
335
336 fn update(&self) -> Result<(), VarIsReadOnlyError> {
337 Var::modify(self, var_update)
338 }
339
340 fn map_debug(&self) -> BoxedVar<Txt> {
341 Var::map(self, var_debug).boxed()
342 }
343}
344impl<T: VarValue> AnyWeakVar for WeakContextualizedVar<T> {
345 fn clone_any(&self) -> BoxedAnyWeakVar {
346 Box::new(self.clone())
347 }
348
349 fn strong_count(&self) -> usize {
350 self.init.strong_count()
351 }
352
353 fn weak_count(&self) -> usize {
354 self.init.weak_count()
355 }
356
357 fn upgrade_any(&self) -> Option<BoxedAnyVar> {
358 self.upgrade().map(|c| Box::new(c) as _)
359 }
360
361 fn as_any(&self) -> &dyn Any {
362 self
363 }
364}
365
366impl<T: VarValue> IntoVar<T> for ContextualizedVar<T> {
367 type Var = Self;
368
369 fn into_var(self) -> Self::Var {
370 self
371 }
372}
373
374impl<T: VarValue> Var<T> for ContextualizedVar<T> {
375 type ReadOnly = types::ReadOnlyVar<T, Self>;
376
377 type ActualVar = BoxedVar<T>;
378
379 type Downgrade = WeakContextualizedVar<T>;
380
381 type Map<O: VarValue> = contextualized::ContextualizedVar<O>;
382 type MapBidi<O: VarValue> = contextualized::ContextualizedVar<O>;
383
384 type FlatMap<O: VarValue, V: Var<O>> = contextualized::ContextualizedVar<O>;
385
386 type FilterMap<O: VarValue> = contextualized::ContextualizedVar<O>;
387 type FilterMapBidi<O: VarValue> = contextualized::ContextualizedVar<O>;
388
389 type MapRef<O: VarValue> = types::MapRef<T, O, Self>;
390 type MapRefBidi<O: VarValue> = types::MapRefBidi<T, O, Self>;
391
392 type Easing = types::ContextualizedVar<T>;
393
394 fn with<R, F>(&self, read: F) -> R
395 where
396 F: FnOnce(&T) -> R,
397 {
398 self.borrow_init().with(read)
399 }
400
401 fn modify<F>(&self, modify: F) -> Result<(), VarIsReadOnlyError>
402 where
403 F: FnOnce(&mut VarModify<T>) + Send + 'static,
404 {
405 self.borrow_init().modify(modify)
406 }
407
408 fn actual_var(self) -> Self::ActualVar {
409 self.into_init().actual_var()
410 }
411
412 fn downgrade(&self) -> Self::Downgrade {
413 WeakContextualizedVar {
414 _type: PhantomData,
415 init: Arc::downgrade(&self.init),
416 }
417 }
418
419 fn into_value(self) -> T {
420 self.into_init().into_value()
421 }
422
423 fn read_only(&self) -> Self::ReadOnly {
424 types::ReadOnlyVar::new(self.clone())
425 }
426
427 fn map<O, M>(&self, map: M) -> Self::Map<O>
428 where
429 O: VarValue,
430 M: FnMut(&T) -> O + Send + 'static,
431 {
432 var_map_ctx(self, map)
433 }
434
435 fn map_bidi<O, M, B>(&self, map: M, map_back: B) -> Self::MapBidi<O>
436 where
437 O: VarValue,
438 M: FnMut(&T) -> O + Send + 'static,
439 B: FnMut(&O) -> T + Send + 'static,
440 {
441 var_map_bidi_ctx(self, map, map_back)
442 }
443
444 fn flat_map<O, V, M>(&self, map: M) -> Self::FlatMap<O, V>
445 where
446 O: VarValue,
447 V: Var<O>,
448 M: FnMut(&T) -> V + Send + 'static,
449 {
450 var_flat_map_ctx(self, map)
451 }
452
453 fn filter_map<O, M, I>(&self, map: M, fallback: I) -> Self::FilterMap<O>
454 where
455 O: VarValue,
456 M: FnMut(&T) -> Option<O> + Send + 'static,
457 I: Fn() -> O + Send + Sync + 'static,
458 {
459 var_filter_map_ctx(self, map, fallback)
460 }
461
462 fn filter_map_bidi<O, M, B, I>(&self, map: M, map_back: B, fallback: I) -> Self::FilterMapBidi<O>
463 where
464 O: VarValue,
465 M: FnMut(&T) -> Option<O> + Send + 'static,
466 B: FnMut(&O) -> Option<T> + Send + 'static,
467 I: Fn() -> O + Send + Sync + 'static,
468 {
469 var_filter_map_bidi_ctx(self, map, map_back, fallback)
470 }
471
472 fn map_ref<O, M>(&self, map: M) -> Self::MapRef<O>
473 where
474 O: VarValue,
475 M: Fn(&T) -> &O + Send + Sync + 'static,
476 {
477 var_map_ref(self, map)
478 }
479
480 fn map_ref_bidi<O, M, B>(&self, map: M, map_mut: B) -> Self::MapRefBidi<O>
481 where
482 O: VarValue,
483 M: Fn(&T) -> &O + Send + Sync + 'static,
484 B: Fn(&mut T) -> &mut O + Send + Sync + 'static,
485 {
486 var_map_ref_bidi(self, map, map_mut)
487 }
488
489 fn easing<F>(&self, duration: Duration, easing: F) -> Self::Easing
490 where
491 T: Transitionable,
492 F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
493 {
494 var_easing_ctx(self, duration, easing)
495 }
496
497 fn easing_with<F, SE>(&self, duration: Duration, easing: F, sampler: SE) -> Self::Easing
498 where
499 T: Transitionable,
500 F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
501 SE: Fn(&animation::Transition<T>, EasingStep) -> T + Send + Sync + 'static,
502 {
503 var_easing_with_ctx(self, duration, easing, sampler)
504 }
505}
506impl<T: VarValue> WeakVar<T> for WeakContextualizedVar<T> {
507 type Upgrade = ContextualizedVar<T>;
508
509 fn upgrade(&self) -> Option<Self::Upgrade> {
510 Some(ContextualizedVar {
511 _type: PhantomData,
512 init: self.init.upgrade()?,
513 actual: RwLock::default(),
514 })
515 }
516}