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, node::IntoUiNode},
8};
9
10type SlotId = usize;
11
12struct SlotData {
13    item: Mutex<UiNode>,
14    slots: Mutex<SlotsData>,
15}
16#[derive(Default)]
17struct SlotsData {
18    // id of the next slot created.
19    next_slot: SlotId,
20
21    // slot and context where the node is inited.
22    owner: Option<(SlotId, WidgetId)>,
23    // slot and context that has requested ownership.
24    move_request: Option<(SlotId, WidgetId)>,
25
26    // node instance that must replace the current in the active slot.
27    replacement: Option<UiNode>,
28}
29impl SlotsData {
30    fn next_slot(&mut self) -> SlotId {
31        let r = self.next_slot;
32        self.next_slot = self.next_slot.wrapping_add(1);
33        r
34    }
35}
36
37/// A reference counted [`UiNode`].
38///
39/// Nodes can only be used in one place at a time, this `struct` allows the
40/// creation of ***slots*** that are [`UiNode`] implementers that can ***exclusive take*** the
41/// referenced node as its child.
42///
43/// When a slot takes the node it is deinited in the previous place and reinited in the slot place.
44///
45/// Slots hold a strong reference to the node when they have it as their child and a weak reference when they don't.
46pub struct ArcNode(Arc<SlotData>);
47impl Clone for ArcNode {
48    fn clone(&self) -> Self {
49        Self(self.0.clone())
50    }
51}
52impl ArcNode {
53    /// New node.
54    pub fn new(node: impl IntoUiNode) -> Self {
55        Self::new_impl(node.into_node())
56    }
57    fn new_impl(node: UiNode) -> Self {
58        ArcNode(Arc::new(SlotData {
59            item: Mutex::new(node),
60            slots: Mutex::default(),
61        }))
62    }
63
64    /// New node that contains a weak reference to itself.
65    ///
66    /// Note that the weak reference cannot be [upgraded](WeakNode::upgrade) during the call to `node`.
67    pub fn new_cyclic(node: impl FnOnce(WeakNode) -> UiNode) -> Self {
68        Self(Arc::new_cyclic(|wk| {
69            let node = node(WeakNode(wk.clone()));
70            SlotData {
71                item: Mutex::new(node),
72                slots: Mutex::default(),
73            }
74        }))
75    }
76
77    /// Creates a [`WeakNode`] reference to this node.
78    pub fn downgrade(&self) -> WeakNode {
79        WeakNode(Arc::downgrade(&self.0))
80    }
81
82    /// Replace the current node with the `new_node` in the current slot.
83    ///
84    /// The previous node is deinited and the `new_node` is inited.
85    pub fn set(&self, new_node: impl IntoUiNode) {
86        self.set_impl(new_node.into_node())
87    }
88    fn set_impl(&self, new_node: UiNode) {
89        let mut slots = self.0.slots.lock();
90        let slots = &mut *slots;
91        if let Some((_, id)) = &slots.owner {
92            // current node inited on a slot, signal it to replace.
93            slots.replacement = Some(new_node);
94            let _ = UPDATES.update(*id);
95        } else {
96            // node already not inited, just replace.
97            *self.0.item.lock() = new_node;
98        }
99    }
100
101    /// Create a slot node that takes ownership of this node when `var` updates to `true`.
102    ///
103    /// The slot node also takes ownership on init if the `var` is already `true`.
104    pub fn take_when(&self, var: impl IntoVar<bool>) -> UiNode {
105        self.take_when_impl(var.into_var())
106    }
107    fn take_when_impl(&self, var: Var<bool>) -> UiNode {
108        impls::TakeSlot {
109            slot: self.0.slots.lock().next_slot(),
110            rc: self.0.clone(),
111            take: impls::TakeWhenVar { var: var.into_var() },
112            wgt_handles: WidgetHandlesCtx::new(),
113        }
114        .into_node()
115    }
116
117    /// Create a slot node that takes ownership of this node when `event` updates and `filter` returns `true`.
118    ///
119    /// The slot node also takes ownership on init if `take_on_init` is `true`.
120    pub fn take_on<A, F>(&self, event: Event<A>, filter: F, take_on_init: bool) -> UiNode
121    where
122        A: EventArgs,
123        F: FnMut(&A) -> bool + Send + 'static,
124    {
125        impls::TakeSlot {
126            slot: self.0.slots.lock().next_slot(),
127            rc: self.0.clone(),
128            take: impls::TakeOnEvent {
129                event,
130                filter,
131                take_on_init,
132            },
133            wgt_handles: WidgetHandlesCtx::new(),
134        }
135        .into_node()
136    }
137
138    /// Create a slot node that takes ownership of this node as soon as the node is inited.
139    ///
140    /// This is equivalent to `self.take_when(true)`.
141    pub fn take_on_init(&self) -> UiNode {
142        self.take_when(true)
143    }
144
145    /// Call `visitor` on a exclusive lock of the node.
146    ///
147    /// Note that the node is not visited in their current slot context, only use this to inspect state.
148    ///
149    /// Returns `None` if the node is locked, this will happen if calling from inside the node or an ancestor.
150    pub fn try_node<R>(&self, visitor: impl FnOnce(&mut UiNode) -> R) -> Option<R> {
151        Some(visitor(&mut *self.0.item.try_lock()?))
152    }
153
154    /// Calls `visitor` in the widget context of the node, if it is an widget.
155    ///
156    /// Note that only the widget context is loaded in `visitor`, not the full slot context.
157    ///
158    /// Returns `None` if the node is locked or is not an widget. The node will be locked if calling from inside the node or an ancestor.
159    pub fn try_context<R>(&self, update_mode: WidgetUpdateMode, visitor: impl FnOnce() -> R) -> Option<R> {
160        Some(self.0.item.try_lock()?.as_widget()?.with_context(update_mode, visitor))
161    }
162}
163
164/// Weak reference to a [`ArcNode`].
165pub struct WeakNode(Weak<SlotData>);
166impl Clone for WeakNode {
167    fn clone(&self) -> Self {
168        Self(Weak::clone(&self.0))
169    }
170}
171impl WeakNode {
172    /// Attempts to upgrade to a [`ArcNode`].
173    pub fn upgrade(&self) -> Option<ArcNode> {
174        self.0.upgrade().map(ArcNode)
175    }
176}
177
178use parking_lot::Mutex;
179
180use super::UiNode;
181
182mod impls {
183    use std::sync::Arc;
184
185    use zng_layout::unit::PxSize;
186    use zng_var::Var;
187
188    use crate::{
189        event::{Event, EventArgs},
190        render::{FrameBuilder, FrameUpdate},
191        update::{EventUpdate, UPDATES, WidgetUpdates},
192        widget::{
193            WIDGET, WidgetHandlesCtx,
194            info::{WidgetInfoBuilder, WidgetLayout, WidgetMeasure},
195            node::{UiNode, UiNodeImpl, WidgetUiNodeImpl},
196        },
197    };
198
199    use super::{SlotData, SlotId};
200
201    pub(super) trait TakeOn: Send + 'static {
202        fn take_on_init(&mut self) -> bool {
203            false
204        }
205
206        fn take_on_event(&mut self, update: &EventUpdate) -> bool {
207            let _ = update;
208            false
209        }
210
211        fn take_on_update(&mut self, updates: &WidgetUpdates) -> bool {
212            let _ = updates;
213            false
214        }
215    }
216
217    pub(super) struct TakeWhenVar {
218        pub(super) var: Var<bool>,
219    }
220    impl TakeOn for TakeWhenVar {
221        fn take_on_init(&mut self) -> bool {
222            WIDGET.sub_var(&self.var);
223            self.var.get()
224        }
225
226        fn take_on_update(&mut self, _: &WidgetUpdates) -> bool {
227            self.var.get_new().unwrap_or(false)
228        }
229    }
230
231    pub(super) struct TakeOnEvent<A: EventArgs, F: FnMut(&A) -> bool + Send + 'static> {
232        pub(super) event: Event<A>,
233        pub(super) filter: F,
234        pub(super) take_on_init: bool,
235    }
236    impl<A: EventArgs, F: FnMut(&A) -> bool + Send + Send + 'static> TakeOn for TakeOnEvent<A, F> {
237        fn take_on_init(&mut self) -> bool {
238            WIDGET.sub_event(&self.event);
239            self.take_on_init
240        }
241
242        fn take_on_event(&mut self, update: &EventUpdate) -> bool {
243            if let Some(args) = self.event.on(update) {
244                (self.filter)(args)
245            } else {
246                false
247            }
248        }
249    }
250
251    pub(super) struct TakeSlot<T: TakeOn> {
252        pub(super) slot: SlotId,
253        pub(super) rc: Arc<SlotData>,
254        pub(super) take: T,
255
256        pub(super) wgt_handles: WidgetHandlesCtx,
257    }
258    impl<T: TakeOn> TakeSlot<T> {
259        fn on_init(&mut self) {
260            if self.take.take_on_init() {
261                self.take();
262            }
263        }
264
265        fn on_deinit(&mut self) {
266            let mut was_owner = false;
267            {
268                let mut slots = self.rc.slots.lock();
269                let slots = &mut *slots;
270                if let Some((slot, _)) = &slots.owner
271                    && *slot == self.slot
272                {
273                    slots.owner = None;
274                    was_owner = true;
275                }
276            }
277
278            if was_owner {
279                WIDGET.with_handles(&mut self.wgt_handles, || self.rc.item.lock().deinit());
280            }
281
282            self.wgt_handles.clear();
283        }
284
285        fn on_event(&mut self, update: &EventUpdate) {
286            if !self.is_owner() && self.take.take_on_event(update) {
287                // request ownership.
288                self.take();
289            }
290        }
291
292        fn on_update(&mut self, updates: &WidgetUpdates) {
293            if self.is_owner() {
294                let mut slots = self.rc.slots.lock();
295                if let Some((_, id)) = slots.move_request {
296                    // deinit to move to other slot.
297
298                    let replacement = slots.replacement.take();
299                    slots.owner = None;
300
301                    drop(slots);
302
303                    let mut node = self.rc.item.lock();
304                    node.deinit();
305
306                    WIDGET.update_info().layout().render();
307
308                    if let Some(new) = replacement {
309                        *node = new;
310                    }
311
312                    UPDATES.update(id);
313                } else if let Some(mut new) = slots.replacement.take() {
314                    // apply replacement.
315
316                    drop(slots);
317
318                    let mut node = self.rc.item.lock();
319                    WIDGET.with_handles(&mut self.wgt_handles, || {
320                        node.deinit();
321                    });
322                    self.wgt_handles.clear();
323
324                    WIDGET.with_handles(&mut self.wgt_handles, || {
325                        new.init();
326                    });
327                    *node = new;
328
329                    WIDGET.update_info().layout().render();
330                }
331            } else if self.take.take_on_update(updates) {
332                // request ownership.
333                self.take();
334            } else {
335                let mut slots = self.rc.slots.lock();
336                if let Some((slot, _)) = &slots.move_request
337                    && *slot == self.slot
338                    && slots.owner.is_none()
339                {
340                    slots.move_request = None;
341                    // requested move in prev update, now can take ownership.
342                    drop(slots);
343                    self.take();
344                }
345            }
346        }
347
348        fn take(&mut self) {
349            {
350                let mut slots = self.rc.slots.lock();
351                let slots = &mut *slots;
352                if let Some((sl, id)) = &slots.owner {
353                    if *sl != self.slot {
354                        // currently inited in another slot, signal it to deinit.
355                        slots.move_request = Some((self.slot, WIDGET.id()));
356                        UPDATES.update(*id);
357                    }
358                } else {
359                    // no current owner, take ownership immediately.
360                    slots.owner = Some((self.slot, WIDGET.id()));
361                }
362            }
363
364            if self.is_owner() {
365                WIDGET.with_handles(&mut self.wgt_handles, || {
366                    self.rc.item.lock().init();
367                });
368                WIDGET.update_info().layout().render();
369            }
370        }
371
372        fn is_owner(&self) -> bool {
373            self.rc.slots.lock().owner.as_ref().map(|(sl, _)| *sl == self.slot).unwrap_or(false)
374        }
375
376        fn delegate_owned<R>(&self, del: impl FnOnce(&UiNode) -> R) -> Option<R> {
377            if self.is_owner() { Some(del(&self.rc.item.lock())) } else { None }
378        }
379        fn delegate_owned_mut<R>(&mut self, del: impl FnOnce(&mut UiNode) -> R) -> Option<R> {
380            if self.is_owner() {
381                Some(del(&mut self.rc.item.lock()))
382            } else {
383                None
384            }
385        }
386
387        fn delegate_owned_mut_with_handles<R>(&mut self, del: impl FnOnce(&mut UiNode) -> R) -> Option<R> {
388            if self.is_owner() {
389                WIDGET.with_handles(&mut self.wgt_handles, || Some(del(&mut self.rc.item.lock())))
390            } else {
391                None
392            }
393        }
394    }
395
396    impl<T: TakeOn> UiNodeImpl for TakeSlot<T> {
397        fn children_len(&self) -> usize {
398            self.delegate_owned(|n| n.0.children_len()).unwrap_or(0)
399        }
400
401        fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
402            self.delegate_owned_mut(|n| n.0.with_child(index, visitor));
403        }
404
405        fn init(&mut self) {
406            self.on_init();
407        }
408
409        fn deinit(&mut self) {
410            self.on_deinit();
411        }
412
413        fn info(&mut self, info: &mut WidgetInfoBuilder) {
414            self.delegate_owned_mut(|n| n.0.info(info));
415        }
416
417        fn event(&mut self, update: &EventUpdate) {
418            self.delegate_owned_mut_with_handles(|n| n.0.event(update));
419            self.on_event(update);
420        }
421
422        fn update(&mut self, updates: &WidgetUpdates) {
423            self.delegate_owned_mut_with_handles(|n| n.0.update(updates));
424            self.on_update(updates);
425        }
426        fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn crate::widget::node::UiNodeListObserver) {
427            self.delegate_owned_mut(|n| n.0.update_list(updates, observer));
428            self.on_update(updates);
429        }
430
431        fn measure(&mut self, wm: &mut WidgetMeasure) -> PxSize {
432            self.delegate_owned_mut(|n| n.0.measure(wm)).unwrap_or_default()
433        }
434        fn measure_list(
435            &mut self,
436            wm: &mut WidgetMeasure,
437            measure: &(dyn Fn(usize, &mut UiNode, &mut WidgetMeasure) -> PxSize + Sync),
438            fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
439        ) -> PxSize {
440            self.delegate_owned_mut(|n| n.0.measure_list(wm, measure, fold_size))
441                .unwrap_or_default()
442        }
443
444        fn layout(&mut self, wl: &mut WidgetLayout) -> PxSize {
445            self.delegate_owned_mut(|n| n.0.layout(wl)).unwrap_or_default()
446        }
447        fn layout_list(
448            &mut self,
449            wl: &mut WidgetLayout,
450            layout: &(dyn Fn(usize, &mut UiNode, &mut WidgetLayout) -> PxSize + Sync),
451            fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
452        ) -> PxSize {
453            self.delegate_owned_mut(|n| n.0.layout_list(wl, layout, fold_size))
454                .unwrap_or_default()
455        }
456
457        fn render(&mut self, frame: &mut FrameBuilder) {
458            self.delegate_owned_mut(|n| n.0.render(frame));
459        }
460        fn render_list(&mut self, frame: &mut FrameBuilder, render: &(dyn Fn(usize, &mut UiNode, &mut FrameBuilder) + Sync)) {
461            self.delegate_owned_mut(|n| n.0.render_list(frame, render));
462        }
463
464        fn render_update(&mut self, update: &mut FrameUpdate) {
465            self.delegate_owned_mut(|n| n.0.render_update(update));
466        }
467        fn render_update_list(&mut self, update: &mut FrameUpdate, render_update: &(dyn Fn(usize, &mut UiNode, &mut FrameUpdate) + Sync)) {
468            self.delegate_owned_mut(|n| n.0.render_update_list(update, render_update));
469        }
470
471        fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
472            self.delegate_owned_mut(|n| n.0.for_each_child(visitor));
473        }
474
475        fn try_for_each_child(
476            &mut self,
477            visitor: &mut dyn FnMut(usize, &mut UiNode) -> std::ops::ControlFlow<zng_var::BoxAnyVarValue>,
478        ) -> std::ops::ControlFlow<zng_var::BoxAnyVarValue> {
479            self.delegate_owned_mut(|n| n.0.try_for_each_child(visitor))
480                .unwrap_or(std::ops::ControlFlow::Continue(()))
481        }
482
483        fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
484            self.delegate_owned_mut(|n| n.0.par_each_child(visitor));
485        }
486
487        fn par_fold_reduce(
488            &mut self,
489            identity: zng_var::BoxAnyVarValue,
490            fold: &(dyn Fn(zng_var::BoxAnyVarValue, usize, &mut UiNode) -> zng_var::BoxAnyVarValue + Sync),
491            reduce: &(dyn Fn(zng_var::BoxAnyVarValue, zng_var::BoxAnyVarValue) -> zng_var::BoxAnyVarValue + Sync),
492        ) -> zng_var::BoxAnyVarValue {
493            self.delegate_owned_mut(|n| n.0.par_fold_reduce(identity.clone(), fold, reduce))
494                .unwrap_or(identity)
495        }
496
497        fn is_list(&self) -> bool {
498            // check directly to avoid into_list wrapping lists nodes
499            self.rc.item.lock().0.is_list()
500        }
501
502        fn as_widget(&mut self) -> Option<&mut dyn WidgetUiNodeImpl> {
503            if self.delegate_owned_mut(|w| w.as_widget().is_some()).unwrap_or(false) {
504                Some(self)
505            } else {
506                None
507            }
508        }
509    }
510    impl<T: TakeOn> WidgetUiNodeImpl for TakeSlot<T> {
511        fn with_context(&mut self, update_mode: crate::widget::WidgetUpdateMode, visitor: &mut dyn FnMut()) {
512            #[cfg(debug_assertions)]
513            let mut called = 0;
514            self.delegate_owned_mut_with_handles(|w| {
515                #[cfg(debug_assertions)]
516                {
517                    called = 1;
518                }
519                if let Some(mut w) = w.as_widget() {
520                    #[cfg(debug_assertions)]
521                    {
522                        called = 2;
523                    }
524                    w.with_context(update_mode, visitor)
525                }
526            });
527            #[cfg(debug_assertions)]
528            match called {
529                0 => tracing::error!("ArcNode TakeSlot node taken while as_widget is held"),
530                1 => tracing::error!("ArcNode TakeSlot node was widget when as_widget returned, but not anymore"),
531                _ => {}
532            }
533        }
534    }
535}