zng_app/widget/node/
arc.rs

1use std::sync::{Arc, Weak};
2
3use crate::{
4    event::{Event, EventArgs},
5    update::UPDATES,
6    var::*,
7    widget::{WidgetHandlesCtx, WidgetId, WidgetUpdateMode},
8};
9
10type SlotId = usize;
11
12struct SlotData<U> {
13    item: Mutex<U>,
14    slots: Mutex<SlotsData<U>>,
15}
16struct SlotsData<U> {
17    // id of the next slot created.
18    next_slot: SlotId,
19
20    // slot and context where the node is inited.
21    owner: Option<(SlotId, WidgetId)>,
22    // slot and context that has requested ownership.
23    move_request: Option<(SlotId, WidgetId)>,
24
25    // node instance that must replace the current in the active slot.
26    replacement: Option<U>,
27}
28impl<U> SlotsData<U> {
29    fn next_slot(&mut self) -> SlotId {
30        let r = self.next_slot;
31        self.next_slot = self.next_slot.wrapping_add(1);
32        r
33    }
34}
35impl<U> Default for SlotsData<U> {
36    fn default() -> Self {
37        Self {
38            next_slot: Default::default(),
39            owner: Default::default(),
40            move_request: Default::default(),
41            replacement: Default::default(),
42        }
43    }
44}
45
46/// A reference counted [`UiNode`].
47///
48/// Nodes can only be used in one place at a time, this `struct` allows the
49/// creation of ***slots*** that are [`UiNode`] implementers that can ***exclusive take*** the
50/// referenced node as its child.
51///
52/// When a slot takes the node it is deinited in the previous place and reinited in the slot place.
53///
54/// Slots hold a strong reference to the node when they have it as their child and a weak reference when they don't.
55pub struct ArcNode<U: UiNode>(Arc<SlotData<U>>);
56impl<U: UiNode> Clone for ArcNode<U> {
57    fn clone(&self) -> Self {
58        Self(self.0.clone())
59    }
60}
61impl<U: UiNode> ArcNode<U> {
62    /// New node.
63    pub fn new(node: U) -> Self {
64        ArcNode(Arc::new(SlotData {
65            item: Mutex::new(node),
66            slots: Mutex::default(),
67        }))
68    }
69
70    /// New node that contains a weak reference to itself.
71    ///
72    /// Note that the weak reference cannot be [upgraded](WeakNode::upgrade) during the call to `node`.
73    pub fn new_cyclic(node: impl FnOnce(WeakNode<U>) -> U) -> Self {
74        Self(Arc::new_cyclic(|wk| {
75            let node = node(WeakNode(wk.clone()));
76            SlotData {
77                item: Mutex::new(node),
78                slots: Mutex::default(),
79            }
80        }))
81    }
82
83    /// Creates a [`WeakNode<U>`] reference to this node.
84    pub fn downgrade(&self) -> WeakNode<U> {
85        WeakNode(Arc::downgrade(&self.0))
86    }
87
88    /// Replace the current node with the `new_node` in the current slot.
89    ///
90    /// The previous node is deinited and the `new_node` is inited.
91    pub fn set(&self, new_node: U) {
92        let mut slots = self.0.slots.lock();
93        let slots = &mut *slots;
94        if let Some((_, id)) = &slots.owner {
95            // current node inited on a slot, signal it to replace.
96            slots.replacement = Some(new_node);
97            let _ = UPDATES.update(*id);
98        } else {
99            // node already not inited, just replace.
100            *self.0.item.lock() = new_node;
101        }
102    }
103
104    /// Create a slot node that takes ownership of this node when `var` updates to `true`.
105    ///
106    /// The slot node also takes ownership on init if the `var` is already `true`.
107    pub fn take_when<I>(&self, var: I) -> TakeSlot<U, impls::TakeWhenVar<I::Var>>
108    where
109        I: IntoVar<bool>,
110    {
111        impls::TakeSlot {
112            slot: self.0.slots.lock().next_slot(),
113            rc: self.0.clone(),
114            take: impls::TakeWhenVar { var: var.into_var() },
115            delegate_init: |n| n.init(),
116            delegate_deinit: |n| n.deinit(),
117            wgt_handles: WidgetHandlesCtx::new(),
118        }
119    }
120
121    /// Create a slot node that takes ownership of this node when `event` updates and `filter` returns `true`.
122    ///
123    /// The slot node also takes ownership on init if `take_on_init` is `true`.
124    pub fn take_on<A, F>(&self, event: Event<A>, filter: F, take_on_init: bool) -> TakeSlot<U, impls::TakeOnEvent<A, F>>
125    where
126        A: EventArgs,
127        F: FnMut(&A) -> bool + Send + 'static,
128    {
129        impls::TakeSlot {
130            slot: self.0.slots.lock().next_slot(),
131            rc: self.0.clone(),
132            take: impls::TakeOnEvent {
133                event,
134                filter,
135                take_on_init,
136            },
137            delegate_init: |n| n.init(),
138            delegate_deinit: |n| n.deinit(),
139            wgt_handles: WidgetHandlesCtx::new(),
140        }
141    }
142
143    /// Create a slot node that takes ownership of this node as soon as the node is inited.
144    ///
145    /// This is equivalent to `self.take_when(true)`.
146    pub fn take_on_init(&self) -> TakeSlot<U, impls::TakeWhenVar<zng_var::LocalVar<bool>>> {
147        self.take_when(true)
148    }
149
150    /// Calls `f` in the context of the node, if it can be locked and is a full widget.
151    pub fn try_context<R>(&self, update_mode: WidgetUpdateMode, f: impl FnOnce() -> R) -> Option<R> {
152        self.0.item.try_lock()?.with_context(update_mode, f)
153    }
154}
155
156/// Weak reference to a [`ArcNode<U>`].
157pub struct WeakNode<U: UiNode>(Weak<SlotData<U>>);
158impl<U: UiNode> Clone for WeakNode<U> {
159    fn clone(&self) -> Self {
160        Self(Weak::clone(&self.0))
161    }
162}
163impl<U: UiNode> WeakNode<U> {
164    /// Attempts to upgrade to a [`ArcNode<U>`].
165    pub fn upgrade(&self) -> Option<ArcNode<U>> {
166        self.0.upgrade().map(ArcNode)
167    }
168}
169
170/// A reference counted [`UiNodeList`].
171///
172/// Nodes can only be used in one place at a time, this `struct` allows the
173/// creation of ***slots*** that are [`UiNodeList`] implementers that can ***exclusive take*** the
174/// referenced list as the children.
175///
176/// When a slot takes the list it is deinited in the previous place and reinited in the slot place.
177///
178/// Slots hold a strong reference to the list when they have it as their child and a weak reference when they don't.
179pub struct ArcNodeList<L: UiNodeList>(Arc<SlotData<L>>);
180impl<L: UiNodeList> Clone for ArcNodeList<L> {
181    fn clone(&self) -> Self {
182        Self(self.0.clone())
183    }
184}
185impl<L: UiNodeList> ArcNodeList<L> {
186    /// New list.
187    pub fn new(list: L) -> Self {
188        ArcNodeList(Arc::new(SlotData {
189            item: Mutex::new(list),
190            slots: Mutex::default(),
191        }))
192    }
193
194    /// New rc list that contains a weak reference to itself.
195    ///
196    /// Note that the weak reference cannot be [upgraded](WeakNodeList::upgrade) during the call to `list`.
197    pub fn new_cyclic(list: impl FnOnce(WeakNodeList<L>) -> L) -> Self {
198        Self(Arc::new_cyclic(|wk| {
199            let list = list(WeakNodeList(wk.clone()));
200            SlotData {
201                item: Mutex::new(list),
202                slots: Mutex::default(),
203            }
204        }))
205    }
206
207    /// Creates a [`WeakNodeList<L>`] reference to this list.
208    pub fn downgrade(&self) -> WeakNodeList<L> {
209        WeakNodeList(Arc::downgrade(&self.0))
210    }
211
212    /// Replace the current list with the `new_list` in the current slot.
213    ///
214    /// The previous list is deinited and the `new_list` is inited.
215    pub fn set(&self, new_list: L) {
216        let mut slots = self.0.slots.lock();
217        let slots = &mut *slots;
218        if let Some((_, id)) = &slots.owner {
219            // current node inited on a slot, signal it to replace.
220            slots.replacement = Some(new_list);
221            UPDATES.update(*id);
222        } else {
223            // node already not inited, just replace.
224            *self.0.item.lock() = new_list;
225        }
226    }
227
228    /// Create a slot list that takes ownership of this list when `var` updates to `true`.
229    ///
230    /// The slot node also takes ownership on init if the `var` is already `true`.
231    ///
232    /// The return type implements [`UiNodeList`].
233    pub fn take_when(&self, var: impl IntoVar<bool>) -> TakeSlot<L, impl TakeOn> {
234        impls::TakeSlot {
235            slot: self.0.slots.lock().next_slot(),
236            rc: self.0.clone(),
237            take: impls::TakeWhenVar { var: var.into_var() },
238            delegate_init: |n| n.init_all(),
239            delegate_deinit: |n| n.deinit_all(),
240            wgt_handles: WidgetHandlesCtx::new(),
241        }
242    }
243
244    /// Create a slot list that takes ownership of this list when `event` updates and `filter` returns `true`.
245    ///
246    /// The slot list also takes ownership on init if `take_on_init` is `true`.
247    ///
248    /// The return type implements [`UiNodeList`].
249    pub fn take_on<A: EventArgs>(
250        &self,
251        event: Event<A>,
252        filter: impl FnMut(&A) -> bool + Send + 'static,
253        take_on_init: bool,
254    ) -> TakeSlot<L, impl TakeOn> {
255        impls::TakeSlot {
256            slot: self.0.slots.lock().next_slot(),
257            rc: self.0.clone(),
258            take: impls::TakeOnEvent {
259                event,
260                filter,
261                take_on_init,
262            },
263            delegate_init: |n| n.init_all(),
264            delegate_deinit: |n| n.deinit_all(),
265            wgt_handles: WidgetHandlesCtx::new(),
266        }
267    }
268
269    /// Create a slot node list that takes ownership of this list as soon as the node is inited.
270    ///
271    /// This is equivalent to `self.take_when(true)`.
272    pub fn take_on_init(&self) -> TakeSlot<L, impl TakeOn> {
273        self.take_when(true)
274    }
275
276    /// Iterate over widget contexts.
277    pub fn for_each_ctx(&self, update_mode: WidgetUpdateMode, mut f: impl FnMut(usize)) {
278        self.0.item.lock().for_each(|i, n| {
279            n.with_context(update_mode, || f(i));
280        })
281    }
282}
283
284/// Weak reference to a [`ArcNodeList<U>`].
285pub struct WeakNodeList<L: UiNodeList>(Weak<SlotData<L>>);
286impl<L: UiNodeList> Clone for WeakNodeList<L> {
287    fn clone(&self) -> Self {
288        Self(Weak::clone(&self.0))
289    }
290}
291impl<L: UiNodeList> WeakNodeList<L> {
292    /// Attempts to upgrade to a [`ArcNodeList<U>`].
293    pub fn upgrade(&self) -> Option<ArcNodeList<L>> {
294        self.0.upgrade().map(ArcNodeList)
295    }
296}
297
298pub use impls::*;
299use parking_lot::Mutex;
300
301use super::{UiNode, UiNodeList};
302
303mod impls {
304    use std::sync::Arc;
305
306    use zng_layout::unit::PxSize;
307    use zng_var::Var;
308
309    use crate::{
310        event::{Event, EventArgs},
311        render::{FrameBuilder, FrameUpdate},
312        update::{EventUpdate, UPDATES, WidgetUpdates},
313        widget::{
314            WIDGET, WidgetHandlesCtx, WidgetUpdateMode,
315            info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
316            node::{BoxedUiNode, BoxedUiNodeList, UiNode, UiNodeList, UiNodeListObserver},
317        },
318    };
319
320    use super::{SlotData, SlotId};
321
322    #[doc(hidden)]
323    pub trait TakeOn: Send + 'static {
324        fn take_on_init(&mut self) -> bool {
325            false
326        }
327
328        fn take_on_event(&mut self, update: &EventUpdate) -> bool {
329            let _ = update;
330            false
331        }
332
333        fn take_on_update(&mut self, updates: &WidgetUpdates) -> bool {
334            let _ = updates;
335            false
336        }
337    }
338
339    #[doc(hidden)]
340    pub struct TakeWhenVar<V: Var<bool>> {
341        pub(super) var: V,
342    }
343    impl<V: Var<bool>> TakeOn for TakeWhenVar<V> {
344        fn take_on_init(&mut self) -> bool {
345            WIDGET.sub_var(&self.var);
346            self.var.get()
347        }
348
349        fn take_on_update(&mut self, _: &WidgetUpdates) -> bool {
350            self.var.get_new().unwrap_or(false)
351        }
352    }
353
354    #[doc(hidden)]
355    pub struct TakeOnEvent<A: EventArgs, F: FnMut(&A) -> bool + Send + 'static> {
356        pub(super) event: Event<A>,
357        pub(super) filter: F,
358        pub(super) take_on_init: bool,
359    }
360    impl<A: EventArgs, F: FnMut(&A) -> bool + Send + Send + 'static> TakeOn for TakeOnEvent<A, F> {
361        fn take_on_init(&mut self) -> bool {
362            WIDGET.sub_event(&self.event);
363            self.take_on_init
364        }
365
366        fn take_on_event(&mut self, update: &EventUpdate) -> bool {
367            if let Some(args) = self.event.on(update) {
368                (self.filter)(args)
369            } else {
370                false
371            }
372        }
373    }
374
375    #[doc(hidden)]
376    pub struct TakeSlot<U, T: TakeOn> {
377        pub(super) slot: SlotId,
378        pub(super) rc: Arc<SlotData<U>>,
379        pub(super) take: T,
380
381        pub(super) delegate_init: fn(&mut U),
382        pub(super) delegate_deinit: fn(&mut U),
383        pub(super) wgt_handles: WidgetHandlesCtx,
384    }
385    impl<U, T: TakeOn> TakeSlot<U, T> {
386        fn on_init(&mut self) {
387            if self.take.take_on_init() {
388                self.take();
389            }
390        }
391
392        fn on_deinit(&mut self) {
393            let mut was_owner = false;
394            {
395                let mut slots = self.rc.slots.lock();
396                let slots = &mut *slots;
397                if let Some((slot, _)) = &slots.owner {
398                    if *slot == self.slot {
399                        slots.owner = None;
400                        was_owner = true;
401                    }
402                }
403            }
404
405            if was_owner {
406                WIDGET.with_handles(&mut self.wgt_handles, || (self.delegate_deinit)(&mut *self.rc.item.lock()));
407            }
408
409            self.wgt_handles.clear();
410        }
411
412        fn on_event(&mut self, update: &EventUpdate) {
413            if !self.is_owner() && self.take.take_on_event(update) {
414                // request ownership.
415                self.take();
416            }
417        }
418
419        fn on_update(&mut self, updates: &WidgetUpdates) {
420            if self.is_owner() {
421                let mut slots = self.rc.slots.lock();
422                if let Some((_, id)) = slots.move_request {
423                    // deinit to move to other slot.
424
425                    let replacement = slots.replacement.take();
426                    slots.owner = None;
427
428                    drop(slots);
429
430                    let mut node = self.rc.item.lock();
431                    (self.delegate_deinit)(&mut node);
432
433                    WIDGET.update_info().layout().render();
434
435                    if let Some(new) = replacement {
436                        *node = new;
437                    }
438
439                    UPDATES.update(id);
440                } else if let Some(mut new) = slots.replacement.take() {
441                    // apply replacement.
442
443                    drop(slots);
444
445                    let mut node = self.rc.item.lock();
446                    WIDGET.with_handles(&mut self.wgt_handles, || {
447                        (self.delegate_deinit)(&mut node);
448                    });
449                    self.wgt_handles.clear();
450
451                    WIDGET.with_handles(&mut self.wgt_handles, || {
452                        (self.delegate_init)(&mut new);
453                    });
454                    *node = new;
455
456                    WIDGET.update_info().layout().render();
457                }
458            } else if self.take.take_on_update(updates) {
459                // request ownership.
460                self.take();
461            } else {
462                let mut slots = self.rc.slots.lock();
463                if let Some((slot, _)) = &slots.move_request {
464                    if *slot == self.slot && slots.owner.is_none() {
465                        slots.move_request = None;
466                        // requested move in prev update, now can take ownership.
467                        drop(slots);
468                        self.take();
469                    }
470                }
471            }
472        }
473
474        fn take(&mut self) {
475            {
476                let mut slots = self.rc.slots.lock();
477                let slots = &mut *slots;
478                if let Some((sl, id)) = &slots.owner {
479                    if *sl != self.slot {
480                        // currently inited in another slot, signal it to deinit.
481                        slots.move_request = Some((self.slot, WIDGET.id()));
482                        UPDATES.update(*id);
483                    }
484                } else {
485                    // no current owner, take ownership immediately.
486                    slots.owner = Some((self.slot, WIDGET.id()));
487                }
488            }
489
490            if self.is_owner() {
491                WIDGET.with_handles(&mut self.wgt_handles, || {
492                    (self.delegate_init)(&mut *self.rc.item.lock());
493                });
494                WIDGET.update_info().layout().render();
495            }
496        }
497
498        fn is_owner(&self) -> bool {
499            self.rc.slots.lock().owner.as_ref().map(|(sl, _)| *sl == self.slot).unwrap_or(false)
500        }
501
502        fn delegate_owned<R>(&self, del: impl FnOnce(&U) -> R) -> Option<R> {
503            if self.is_owner() { Some(del(&*self.rc.item.lock())) } else { None }
504        }
505        fn delegate_owned_mut<R>(&mut self, del: impl FnOnce(&mut U) -> R) -> Option<R> {
506            if self.is_owner() {
507                Some(del(&mut *self.rc.item.lock()))
508            } else {
509                None
510            }
511        }
512
513        fn delegate_owned_mut_with_handles<R>(&mut self, del: impl FnOnce(&mut U) -> R) -> Option<R> {
514            if self.is_owner() {
515                WIDGET.with_handles(&mut self.wgt_handles, || Some(del(&mut *self.rc.item.lock())))
516            } else {
517                None
518            }
519        }
520    }
521
522    impl<U: UiNode, T: TakeOn> UiNode for TakeSlot<U, T> {
523        fn init(&mut self) {
524            self.on_init();
525        }
526
527        fn deinit(&mut self) {
528            self.on_deinit();
529        }
530
531        fn info(&mut self, info: &mut WidgetInfoBuilder) {
532            self.delegate_owned_mut(|n| n.info(info));
533        }
534
535        fn event(&mut self, update: &EventUpdate) {
536            self.delegate_owned_mut_with_handles(|n| n.event(update));
537            self.on_event(update);
538        }
539
540        fn update(&mut self, updates: &WidgetUpdates) {
541            self.delegate_owned_mut_with_handles(|n| n.update(updates));
542            self.on_update(updates);
543        }
544
545        fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
546            self.delegate_owned_mut(|n| n.measure(wm)).unwrap_or_default()
547        }
548
549        fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
550            self.delegate_owned_mut(|n| n.layout(wl)).unwrap_or_default()
551        }
552
553        fn render(&mut self, frame: &mut FrameBuilder) {
554            self.delegate_owned_mut(|n| n.render(frame));
555        }
556
557        fn render_update(&mut self, update: &mut FrameUpdate) {
558            self.delegate_owned_mut(|n| n.render_update(update));
559        }
560
561        fn is_widget(&self) -> bool {
562            self.delegate_owned(UiNode::is_widget).unwrap_or(false)
563        }
564
565        fn with_context<R, F>(&mut self, update_mode: WidgetUpdateMode, f: F) -> Option<R>
566        where
567            F: FnOnce() -> R,
568        {
569            self.delegate_owned_mut(|n| n.with_context(update_mode, f)).flatten()
570        }
571    }
572
573    impl<U: UiNodeList, T: TakeOn> UiNodeList for TakeSlot<U, T> {
574        fn with_node<R, F>(&mut self, index: usize, f: F) -> R
575        where
576            F: FnOnce(&mut BoxedUiNode) -> R,
577        {
578            self.delegate_owned_mut(move |l| l.with_node(index, f))
579                .unwrap_or_else(|| panic!("index `{index}` is >= len `0`"))
580        }
581
582        fn for_each<F>(&mut self, f: F)
583        where
584            F: FnMut(usize, &mut BoxedUiNode),
585        {
586            self.delegate_owned_mut(|l| l.for_each(f));
587        }
588
589        fn par_each<F>(&mut self, f: F)
590        where
591            F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
592        {
593            self.delegate_owned_mut(|l| l.par_each(f));
594        }
595
596        fn par_fold_reduce<TF, I, F, R>(&mut self, identity: I, fold: F, reduce: R) -> TF
597        where
598            TF: Send + 'static,
599            I: Fn() -> TF + Send + Sync,
600            F: Fn(TF, usize, &mut BoxedUiNode) -> TF + Send + Sync,
601            R: Fn(TF, TF) -> TF + Send + Sync,
602        {
603            self.delegate_owned_mut(|l| l.par_fold_reduce(&identity, fold, reduce))
604                .unwrap_or_else(identity)
605        }
606
607        fn len(&self) -> usize {
608            self.delegate_owned(UiNodeList::len).unwrap_or(0)
609        }
610
611        fn boxed(self) -> BoxedUiNodeList {
612            Box::new(self)
613        }
614
615        fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
616            self.delegate_owned_mut(|l| l.drain_into(vec));
617        }
618
619        fn init_all(&mut self) {
620            self.on_init();
621            // delegation done in the handler
622        }
623
624        fn deinit_all(&mut self) {
625            self.on_deinit();
626            // delegation done in the handler
627        }
628
629        fn info_all(&mut self, info: &mut WidgetInfoBuilder) {
630            self.delegate_owned_mut_with_handles(|l| l.info_all(info));
631        }
632
633        fn event_all(&mut self, update: &EventUpdate) {
634            self.delegate_owned_mut_with_handles(|l| l.event_all(update));
635            self.on_event(update);
636        }
637
638        fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
639            let _ = observer;
640            self.delegate_owned_mut_with_handles(|l| l.update_all(updates, observer));
641            self.on_update(updates);
642        }
643
644        fn render_all(&mut self, frame: &mut FrameBuilder) {
645            self.delegate_owned_mut(|l| l.render_all(frame));
646        }
647
648        fn render_update_all(&mut self, update: &mut FrameUpdate) {
649            self.delegate_owned_mut(|l| l.render_update_all(update));
650        }
651    }
652}