1use std::{
4 borrow::Cow,
5 collections::{HashMap, hash_map},
6 fmt, mem,
7 sync::Arc,
8 task::Waker,
9};
10
11use parking_lot::Mutex;
12use zng_app_context::app_local;
13use zng_handle::{Handle, HandleOwner, WeakHandle};
14use zng_task::channel::ChannelError;
15use zng_unique_id::IdSet;
16use zng_var::{VARS, VARS_APP, VarUpdateId};
17
18use crate::{
19 AppEventSender, LoopTimer, async_hn_once,
20 handler::{AppWeakHandle, Handler, HandlerExt as _},
21 hn_once,
22 timer::TIMERS_SV,
23 widget::{
24 WIDGET, WidgetId,
25 info::{InteractionPath, WidgetInfo, WidgetInfoTree, WidgetPath},
26 node::UiNode,
27 },
28 window::{WINDOW, WindowId},
29};
30
31#[derive(Clone)]
33pub struct UpdateDeliveryList {
34 windows: IdSet<WindowId>,
35 widgets: IdSet<WidgetId>,
36 search: IdSet<WidgetId>,
37 search_root: bool,
38}
39impl fmt::Debug for UpdateDeliveryList {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("UpdateDeliveryList")
42 .field("windows", &self.windows)
43 .field("widgets", &self.widgets)
44 .field("search", &self.search)
45 .finish_non_exhaustive()
46 }
47}
48impl Default for UpdateDeliveryList {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53impl UpdateDeliveryList {
54 pub fn new() -> Self {
56 Self {
57 windows: IdSet::default(),
58 widgets: IdSet::default(),
59 search: IdSet::default(),
60 search_root: false,
61 }
62 }
63
64 pub(crate) fn insert_updates_root(&mut self, window_id: WindowId, root_id: WidgetId) {
65 self.windows.insert(window_id);
66 self.widgets.insert(root_id);
67 }
68
69 pub fn insert_wgt(&mut self, wgt: impl WidgetPathProvider) {
71 for w in wgt.widget_and_ancestors() {
72 if !self.widgets.insert(w) {
73 return;
74 }
75 }
76 self.windows.insert(wgt.window_id());
77 }
78
79 pub fn clone_insert_wgt(&self, wgt: impl WidgetPathProvider) -> Cow<'_, Self> {
83 let mut path = wgt.widget_and_ancestors();
84 if let Some(w) = path.next()
85 && !self.widgets.contains(&w)
86 {
87 let mut s = self.clone();
88 s.widgets.insert(w);
89 for w in path {
90 if !s.widgets.insert(w) {
91 return Cow::Owned(s);
92 }
93 }
94 s.windows.insert(wgt.window_id());
95 return Cow::Owned(s);
96 }
97 Cow::Borrowed(self)
98 }
99
100 pub fn clone_insert_all<W: WidgetPathProvider>(&self, widgets: impl IntoIterator<Item = W>) -> Cow<'_, Self> {
104 let mut widgets = widgets.into_iter();
105 for wgt in widgets.by_ref() {
106 match self.clone_insert_wgt(wgt) {
107 Cow::Borrowed(_) => continue,
108 Cow::Owned(mut l) => {
109 for wgt in widgets {
110 l.insert_wgt(wgt);
111 }
112 return Cow::Owned(l);
113 }
114 }
115 }
116 Cow::Borrowed(self)
117 }
118
119 pub fn clone_insert_any<W: WidgetPathProvider>(&self, widgets: impl IntoIterator<Item = W>) -> Cow<'_, Self> {
123 let mut first_missing = None;
124 for wgt in widgets.into_iter() {
125 if self.widgets.contains(&wgt.widget_and_ancestors().next().unwrap()) {
126 return Cow::Borrowed(self);
127 } else if first_missing.is_none() {
128 first_missing = Some(wgt);
129 }
130 }
131 match first_missing {
132 Some(wgt) => {
133 let mut l = self.clone();
134 l.insert_wgt(wgt);
135 Cow::Owned(l)
136 }
137 None => Cow::Borrowed(self),
138 }
139 }
140
141 pub fn insert_window(&mut self, id: WindowId) {
143 self.windows.insert(id);
144 self.search_root = true;
145 }
146
147 pub fn search_widget(&mut self, widget_id: WidgetId) {
149 self.search.insert(widget_id);
150 }
151
152 pub fn has_pending_search(&mut self) -> bool {
154 self.search_root || !self.search.is_empty()
155 }
156
157 pub fn fulfill_search<'a, 'b>(&'a mut self, windows: impl Iterator<Item = &'b WidgetInfoTree>) {
159 for window in windows {
160 if self.search_root && self.windows.contains(&window.window_id()) {
161 self.widgets.insert(window.root().id());
162 }
163
164 self.search.retain(|w| {
165 if let Some(w) = window.get(*w) {
166 for w in w.widget_and_ancestors() {
167 self.widgets.insert(w);
168 }
169 self.windows.insert(w.window_id());
170 false
171 } else {
172 true
173 }
174 });
175 }
176 self.search.clear();
177 self.search_root = false;
178 }
179
180 pub fn enter_window(&self, window_id: WindowId) -> bool {
182 self.windows.contains(&window_id)
183 }
184
185 pub fn enter_widget(&self, widget_id: WidgetId) -> bool {
187 self.widgets.contains(&widget_id)
188 }
189
190 pub fn windows(&self) -> &IdSet<WindowId> {
192 &self.windows
193 }
194
195 pub fn widgets(&self) -> &IdSet<WidgetId> {
197 &self.widgets
198 }
199
200 #[must_use = "use `search_widget` to request search"]
202 pub fn search_widgets(&mut self) -> &IdSet<WidgetId> {
203 &self.search
204 }
205
206 #[must_use = "use `insert_window` to request search"]
208 pub fn search_root(&mut self) -> bool {
209 self.search_root
210 }
211
212 pub fn extend(&mut self, other: UpdateDeliveryList) {
214 if self.windows.is_empty() {
215 self.windows = other.windows;
216 } else {
217 self.windows.extend(other.windows);
218 }
219
220 if self.widgets.is_empty() {
221 self.widgets = other.widgets;
222 } else {
223 self.widgets.extend(other.widgets);
224 }
225
226 if self.search.is_empty() {
227 self.search = other.search;
228 } else {
229 self.search.extend(other.search);
230 }
231 }
232}
233
234pub trait WidgetPathProvider {
236 type WidgetIter<'s>: Iterator<Item = WidgetId>
238 where
239 Self: 's;
240
241 fn window_id(&self) -> WindowId;
243 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_>;
245}
246impl WidgetPathProvider for WidgetInfo {
247 type WidgetIter<'s> = std::iter::Map<crate::widget::info::iter::Ancestors, fn(WidgetInfo) -> WidgetId>;
248
249 fn window_id(&self) -> WindowId {
250 self.tree().window_id()
251 }
252
253 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
254 fn wgt_to_id(wgt: WidgetInfo) -> WidgetId {
255 wgt.id()
256 }
257 self.self_and_ancestors().map(wgt_to_id)
258 }
259}
260impl WidgetPathProvider for WidgetPath {
261 type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
262
263 fn window_id(&self) -> WindowId {
264 self.window_id()
265 }
266
267 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
268 self.widgets_path().iter().copied().rev()
269 }
270}
271impl WidgetPathProvider for InteractionPath {
272 type WidgetIter<'s> = std::iter::Rev<std::iter::Copied<std::slice::Iter<'s, WidgetId>>>;
273
274 fn window_id(&self) -> WindowId {
275 WidgetPath::window_id(self)
276 }
277
278 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
279 self.widgets_path().iter().copied().rev()
280 }
281}
282impl<T: WidgetPathProvider> WidgetPathProvider for &T {
283 type WidgetIter<'s>
284 = <T as WidgetPathProvider>::WidgetIter<'s>
285 where
286 Self: 's;
287
288 fn window_id(&self) -> WindowId {
289 <T as WidgetPathProvider>::window_id(self)
290 }
291
292 fn widget_and_ancestors(&self) -> Self::WidgetIter<'_> {
293 <T as WidgetPathProvider>::widget_and_ancestors(self)
294 }
295}
296
297#[derive(Debug, Default)]
299pub struct InfoUpdates {
300 delivery_list: UpdateDeliveryList,
301}
302impl InfoUpdates {
303 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
305 Self { delivery_list }
306 }
307
308 pub fn delivery_list(&self) -> &UpdateDeliveryList {
310 &self.delivery_list
311 }
312
313 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
315 &mut self.delivery_list
316 }
317
318 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
320 where
321 H: FnOnce() -> R,
322 {
323 if self.delivery_list.enter_window(window_id) {
324 Some(handle())
325 } else {
326 None
327 }
328 }
329
330 pub fn extend(&mut self, other: InfoUpdates) {
332 self.delivery_list.extend(other.delivery_list)
333 }
334}
335
336#[derive(Debug, Default, Clone)]
350pub struct WidgetUpdates {
351 pub(crate) delivery_list: UpdateDeliveryList,
352}
353impl WidgetUpdates {
354 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
356 Self { delivery_list }
357 }
358
359 pub fn delivery_list(&self) -> &UpdateDeliveryList {
361 &self.delivery_list
362 }
363
364 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
366 &mut self.delivery_list
367 }
368
369 pub fn with_window<H, R>(&self, handle: H) -> Option<R>
371 where
372 H: FnOnce() -> R,
373 {
374 if self.delivery_list.enter_window(WINDOW.id()) {
375 Some(handle())
376 } else {
377 None
378 }
379 }
380
381 pub fn with_widget<H, R>(&self, handle: H) -> Option<R>
383 where
384 H: FnOnce() -> R,
385 {
386 if WIDGET.take_update(UpdateFlags::UPDATE) || self.delivery_list.enter_widget(WIDGET.id()) {
387 Some(handle())
388 } else {
389 None
390 }
391 }
392
393 pub fn extend(&mut self, other: WidgetUpdates) {
395 self.delivery_list.extend(other.delivery_list)
396 }
397
398 pub fn clone_insert_wgt(&self, wgt: impl WidgetPathProvider) -> Cow<'_, Self> {
402 match self.delivery_list.clone_insert_wgt(wgt) {
403 Cow::Borrowed(_) => Cow::Borrowed(self),
404 Cow::Owned(l) => Cow::Owned(Self { delivery_list: l }),
405 }
406 }
407
408 pub fn clone_insert_all<W: WidgetPathProvider>(&self, widgets: impl IntoIterator<Item = W>) -> Cow<'_, Self> {
412 match self.delivery_list.clone_insert_all(widgets) {
413 Cow::Borrowed(_) => Cow::Borrowed(self),
414 Cow::Owned(l) => Cow::Owned(Self { delivery_list: l }),
415 }
416 }
417
418 pub fn clone_insert_any<W: WidgetPathProvider>(&self, widgets: impl IntoIterator<Item = W>) -> Cow<'_, Self> {
422 match self.delivery_list.clone_insert_any(widgets) {
423 Cow::Borrowed(_) => Cow::Borrowed(self),
424 Cow::Owned(l) => Cow::Owned(Self { delivery_list: l }),
425 }
426 }
427}
428
429#[derive(Debug, Default)]
431pub struct LayoutUpdates {
432 pub(crate) delivery_list: UpdateDeliveryList,
433}
434impl LayoutUpdates {
435 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
437 Self { delivery_list }
438 }
439
440 pub fn delivery_list(&self) -> &UpdateDeliveryList {
442 &self.delivery_list
443 }
444
445 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
447 &mut self.delivery_list
448 }
449
450 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
452 where
453 H: FnOnce() -> R,
454 {
455 if self.delivery_list.enter_window(window_id) {
456 Some(handle())
457 } else {
458 None
459 }
460 }
461
462 pub fn extend(&mut self, other: LayoutUpdates) {
464 self.delivery_list.extend(other.delivery_list)
465 }
466}
467
468#[derive(Debug, Default)]
470pub struct RenderUpdates {
471 delivery_list: UpdateDeliveryList,
472}
473impl RenderUpdates {
474 pub fn new(delivery_list: UpdateDeliveryList) -> Self {
476 Self { delivery_list }
477 }
478
479 pub fn delivery_list(&self) -> &UpdateDeliveryList {
481 &self.delivery_list
482 }
483
484 pub fn delivery_list_mut(&mut self) -> &mut UpdateDeliveryList {
486 &mut self.delivery_list
487 }
488
489 pub fn with_window<H, R>(&self, window_id: WindowId, handle: H) -> Option<R>
491 where
492 H: FnOnce() -> R,
493 {
494 if self.delivery_list.enter_window(window_id) {
495 Some(handle())
496 } else {
497 None
498 }
499 }
500
501 pub fn extend(&mut self, other: RenderUpdates) {
503 self.delivery_list.extend(other.delivery_list)
504 }
505}
506
507pub trait UpdatesTraceUiNodeExt {
511 fn instrument<S: Into<String>>(self, tag: S) -> UiNode
513 where
514 Self: Sized;
515}
516impl UpdatesTraceUiNodeExt for UiNode {
517 fn instrument<S: Into<String>>(self, tag: S) -> UiNode {
518 let tag = tag.into();
519 self.trace(move |op| UpdatesTrace::custom_span(&tag, op.mtd_name()))
520 }
521}
522
523pub fn updates_trace_span(tag: &'static str) -> tracing::span::EnteredSpan {
527 UpdatesTrace::custom_span(tag, "")
528}
529
530pub fn updates_trace_event(tag: &str) {
534 UpdatesTrace::log_custom(tag)
535}
536
537pub(crate) struct UpdatesTrace {
538 context: Mutex<UpdateContext>,
539 trace: Arc<Mutex<Vec<UpdateTrace>>>,
540
541 widgets_stack: Mutex<Vec<(WidgetId, String)>>,
542 node_parents_stack: Mutex<Vec<String>>,
543 tags_stack: Mutex<Vec<String>>,
544}
545impl tracing::subscriber::Subscriber for UpdatesTrace {
546 fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {
547 metadata.target() == Self::UPDATES_TARGET
548 }
549
550 fn new_span(&self, span: &tracing::span::Attributes<'_>) -> tracing::span::Id {
551 match span.metadata().name() {
552 "property" | "intrinsic" => {
553 let name = visit_str(|v| span.record(v), "name");
554 let mut ctx = self.context.lock();
555
556 if let Some(p) = ctx.node_parent.replace(name) {
557 self.node_parents_stack.lock().push(p);
558 }
559 if let Some(p) = ctx.tag.replace(String::new()) {
560 self.tags_stack.lock().push(p);
561 }
562
563 tracing::span::Id::from_u64(1)
564 }
565 "widget" => {
566 let id = visit_u64(|v| span.record(v), "raw_id").unwrap();
567 if id == 0 {
568 panic!()
569 }
570 let id = WidgetId::from_raw(id);
571
572 let name = visit_str(|v| span.record(v), "name");
573
574 let mut ctx = self.context.lock();
575 if let Some(p) = ctx.widget.replace((id, name)) {
576 self.widgets_stack.lock().push(p);
577 }
578
579 if let Some(p) = ctx.node_parent.replace(String::new()) {
580 self.node_parents_stack.lock().push(p);
581 }
582
583 if let Some(p) = ctx.tag.replace(String::new()) {
584 self.tags_stack.lock().push(p);
585 }
586
587 tracing::span::Id::from_u64(2)
588 }
589 "Window" => {
590 let id = visit_u64(|v| span.record(v), "raw_id").unwrap() as u32;
591 if id == 0 {
592 panic!()
593 }
594 let id = WindowId::from_raw(id);
595
596 let mut ctx = self.context.lock();
597 ctx.window_id = Some(id);
598
599 if let Some(p) = ctx.tag.replace(String::new()) {
600 self.tags_stack.lock().push(p);
601 }
602
603 tracing::span::Id::from_u64(3)
604 }
605 "tag" => {
606 let tag = visit_str(|v| span.record(v), "tag");
607 let mut ctx = self.context.lock();
608 if let Some(p) = ctx.tag.replace(tag) {
609 self.tags_stack.lock().push(p);
610 }
611 tracing::span::Id::from_u64(5)
612 }
613 _ => tracing::span::Id::from_u64(u64::MAX),
614 }
615 }
616
617 fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {}
618
619 fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {}
620
621 fn event(&self, event: &tracing::Event<'_>) {
622 let action = match visit_str(|v| event.record(v), "kind").as_str() {
623 "var" => UpdateAction::Var {
624 type_name: visit_str(|v| event.record(v), "type_name"),
625 },
626 "request" => UpdateAction::Update,
627 "info" => UpdateAction::Info,
628 "layout" => UpdateAction::Layout,
629 "render" => UpdateAction::Render,
630 "custom" => UpdateAction::Custom {
631 tag: visit_str(|v| event.record(v), "tag"),
632 },
633 _ => return,
634 };
635
636 let ctx = self.context.lock().clone();
637 let entry = UpdateTrace { ctx, action };
642 self.trace.lock().push(entry);
643 }
644
645 fn enter(&self, _span: &tracing::span::Id) {}
646
647 fn exit(&self, span: &tracing::span::Id) {
648 let mut ctx = self.context.lock();
649 if span == &tracing::span::Id::from_u64(1) {
650 ctx.node_parent = self.node_parents_stack.lock().pop();
651 ctx.tag = self.tags_stack.lock().pop();
652 } else if span == &tracing::span::Id::from_u64(2) {
653 ctx.widget = self.widgets_stack.lock().pop();
654 ctx.node_parent = self.node_parents_stack.lock().pop();
655 ctx.tag = self.tags_stack.lock().pop();
656 } else if span == &tracing::span::Id::from_u64(3) {
657 ctx.window_id = None;
658 ctx.tag = self.tags_stack.lock().pop();
659 } else if span == &tracing::span::Id::from_u64(4) {
660 ctx.app_extension = None;
661 ctx.tag = self.tags_stack.lock().pop();
662 } else if span == &tracing::span::Id::from_u64(5) {
663 ctx.tag = self.tags_stack.lock().pop();
664 }
665 }
666}
667impl UpdatesTrace {
668 const UPDATES_TARGET: &'static str = "zng-updates";
669
670 fn new() -> Self {
671 UpdatesTrace {
672 context: Mutex::new(UpdateContext::default()),
673 trace: Arc::new(Mutex::new(Vec::with_capacity(100))),
674 widgets_stack: Mutex::new(Vec::with_capacity(100)),
675 node_parents_stack: Mutex::new(Vec::with_capacity(100)),
676 tags_stack: Mutex::new(Vec::new()),
677 }
678 }
679
680 pub fn window_span(id: WindowId) -> tracing::span::EnteredSpan {
684 tracing::debug_span!(target: UpdatesTrace::UPDATES_TARGET, "Window", %id, raw_id = id.get() as u64).entered()
685 }
686
687 #[cfg(feature = "trace_widget")]
691 pub fn widget_span(id: WidgetId, name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
692 tracing::debug_span!(target: UpdatesTrace::UPDATES_TARGET, "widget", %id, raw_id = id.get(), name, %node_mtd).entered()
693 }
694
695 #[cfg(feature = "trace_wgt_item")]
699 pub fn property_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
700 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "property", name, %node_mtd).entered()
701 }
702
703 #[cfg(feature = "trace_wgt_item")]
707 pub fn intrinsic_span(name: &'static str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
708 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "intrinsic", name, %node_mtd).entered()
709 }
710
711 pub fn custom_span(name: &str, node_mtd: &'static str) -> tracing::span::EnteredSpan {
715 tracing::trace_span!(target: UpdatesTrace::UPDATES_TARGET, "tag", %name, %node_mtd).entered()
716 }
717
718 pub fn log_update() {
722 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
723 kind = "update"
724 });
725 }
726
727 pub fn log_info() {
731 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
732 kind = "info"
733 });
734 }
735
736 pub fn log_layout() {
740 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
741 kind = "layout"
742 });
743 }
744
745 pub fn log_render() {
749 tracing::event!(target: UpdatesTrace::UPDATES_TARGET, tracing::Level::TRACE, {
750 kind = "render"
751 });
752 }
753
754 pub fn log_custom(tag: &str) {
758 tracing::event!(
759 target: UpdatesTrace::UPDATES_TARGET,
760 tracing::Level::TRACE,
761 { kind = "custom", %tag }
762 );
763 }
764
765 pub fn log_var(type_name: &str) {
769 tracing::event!(
770 target: UpdatesTrace::UPDATES_TARGET,
771 tracing::Level::TRACE,
772 { kind = "var", type_name = pretty_type_name::pretty_type_name_str(type_name) }
773 );
774 }
775
776 pub fn collect_trace<R>(trace: &mut Vec<UpdateTrace>, action: impl FnOnce() -> R) -> R {
778 let tracer = UpdatesTrace::new();
779 let result = Arc::clone(&tracer.trace);
780 let r = tracing::subscriber::with_default(tracer, action);
781 trace.extend(Arc::try_unwrap(result).unwrap().into_inner());
782
783 r
784 }
785
786 pub fn format_trace(trace: Vec<UpdateTrace>) -> String {
788 let mut frequencies = HashMap::with_capacity(50);
789 for t in trace {
790 match frequencies.entry(t) {
791 hash_map::Entry::Vacant(e) => {
792 e.insert(1);
793 }
794 hash_map::Entry::Occupied(mut e) => {
795 *e.get_mut() += 1;
796 }
797 }
798 }
799 let mut frequencies: Vec<_> = frequencies.into_iter().collect();
800 frequencies.sort_by_key(|(_, c)| -c);
801
802 let mut trace = String::new();
803 for (t, c) in frequencies.into_iter().take(20) {
804 use std::fmt::Write;
805 let _ = writeln!(&mut trace, "{t} ({c} times)");
806 }
807 trace
808 }
809}
810#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
811struct UpdateContext {
812 app_extension: Option<String>,
813 window_id: Option<WindowId>,
814 widget: Option<(WidgetId, String)>,
815 node_parent: Option<String>,
816 tag: Option<String>,
817}
818impl fmt::Display for UpdateContext {
819 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820 if let Some(e) = &self.app_extension {
821 write!(f, "{}", e.rsplit("::").next().unwrap())?;
822 } else {
823 write!(f, "<unknown>")?;
824 }
825 if let Some(w) = self.window_id {
826 write!(f, "//{w}")?;
827 }
828 if let Some((id, name)) = &self.widget {
829 write!(f, "/../{name}#{id}")?;
830 }
831 if let Some(p) = &self.node_parent
832 && !p.is_empty()
833 {
834 write!(f, "//{p}")?;
835 }
836 if let Some(t) = &self.tag
837 && !t.is_empty()
838 {
839 write!(f, "//{t}")?;
840 }
841 Ok(())
842 }
843}
844
845#[derive(Debug, PartialEq, Eq, Hash)]
846pub(crate) struct UpdateTrace {
847 ctx: UpdateContext,
848 action: UpdateAction,
849}
850impl fmt::Display for UpdateTrace {
851 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
852 write!(f, "{} {}", self.ctx, self.action)
853 }
854}
855#[derive(Debug, PartialEq, Eq, Hash)]
856enum UpdateAction {
857 Info,
858 Update,
859 Layout,
860 Render,
861 Var { type_name: String },
862 Custom { tag: String },
863}
864impl fmt::Display for UpdateAction {
865 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
866 match self {
867 UpdateAction::Info => write!(f, "info"),
868 UpdateAction::Update => write!(f, "update"),
869 UpdateAction::Layout => write!(f, "layout"),
870 UpdateAction::Render => write!(f, "render"),
871 UpdateAction::Var { type_name } => write!(f, "update {type_name}"),
872 UpdateAction::Custom { tag } => write!(f, "{tag}"),
873 }
874 }
875}
876
877fn visit_str(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> String {
878 struct Visitor<'a> {
879 name: &'a str,
880 result: String,
881 }
882 impl tracing::field::Visit for Visitor<'_> {
883 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
884 if field.name() == self.name {
885 self.result = format!("{value:?}");
886 }
887 }
888 fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
889 if field.name() == self.name {
890 value.clone_into(&mut self.result);
891 }
892 }
893 }
894
895 let mut visitor = Visitor {
896 name,
897 result: String::new(),
898 };
899 record(&mut visitor);
900 visitor.result
901}
902fn visit_u64(record: impl FnOnce(&mut dyn tracing::field::Visit), name: &str) -> Option<u64> {
903 struct Visitor<'a> {
904 name: &'a str,
905 result: Option<u64>,
906 }
907 impl tracing::field::Visit for Visitor<'_> {
908 fn record_debug(&mut self, _field: &tracing::field::Field, _value: &dyn std::fmt::Debug) {}
909 fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
910 if field.name() == self.name {
911 self.result = Some(value)
912 }
913 }
914 }
915
916 let mut visitor = Visitor { name, result: None };
917 record(&mut visitor);
918 visitor.result
919}
920
921pub struct UPDATES;
923impl UPDATES {
924 pub(crate) fn init(&self, event_sender: AppEventSender) {
925 UPDATES_SV.write().event_sender = Some(event_sender);
926 }
927
928 #[must_use]
929 #[cfg(any(test, doc, feature = "test_util"))]
930 pub(crate) fn apply(&self) -> ContextUpdates {
931 self.apply_updates() | self.apply_info() | self.apply_layout_render()
932 }
933
934 #[must_use]
935 pub(crate) fn apply_updates(&self) -> ContextUpdates {
936 VARS_APP.apply_updates();
937
938 let (update, update_widgets) = UPDATES.take_update();
939
940 ContextUpdates {
941 update,
942 update_widgets,
943 info: false,
944 info_widgets: InfoUpdates::default(),
945 layout: false,
946 layout_widgets: LayoutUpdates::default(),
947 render: false,
948 render_widgets: RenderUpdates::default(),
949 render_update_widgets: RenderUpdates::default(),
950 }
951 }
952 #[must_use]
953 pub(crate) fn apply_info(&self) -> ContextUpdates {
954 let (info, info_widgets) = UPDATES.take_info();
955
956 ContextUpdates {
957 update: false,
958 update_widgets: WidgetUpdates::default(),
959 info,
960 info_widgets,
961 layout: false,
962 layout_widgets: LayoutUpdates::default(),
963 render: false,
964 render_widgets: RenderUpdates::default(),
965 render_update_widgets: RenderUpdates::default(),
966 }
967 }
968 #[must_use]
969 pub(crate) fn apply_layout_render(&self) -> ContextUpdates {
970 let (layout, layout_widgets) = UPDATES.take_layout();
971 let (render, render_widgets, render_update_widgets) = UPDATES.take_render();
972
973 ContextUpdates {
974 update: false,
975 update_widgets: WidgetUpdates::default(),
976 info: false,
977 info_widgets: InfoUpdates::default(),
978 layout,
979 layout_widgets,
980 render,
981 render_widgets,
982 render_update_widgets,
983 }
984 }
985
986 pub(crate) fn on_app_awake(&self) {
987 UPDATES_SV.write().app_awake(true);
988 }
989
990 pub(crate) fn on_app_sleep(&self) {
991 UPDATES_SV.write().app_awake(false);
992 }
993
994 pub(crate) fn next_deadline(&self, timer: &mut LoopTimer) {
996 TIMERS_SV.write().next_deadline(timer);
997 VARS_APP.next_deadline(timer);
998 }
999
1000 pub(crate) fn update_timers(&self, timer: &mut LoopTimer) {
1002 TIMERS_SV.write().apply_updates(timer);
1003 VARS_APP.update_animations(timer);
1004 }
1005
1006 #[must_use]
1008 pub(crate) fn has_pending_updates(&self) -> bool {
1009 UPDATES_SV.read().update_ext.intersects(UpdateFlags::UPDATE | UpdateFlags::INFO)
1010 || VARS_APP.has_pending_updates()
1011 || TIMERS_SV.read().has_pending_updates()
1012 }
1013
1014 #[must_use]
1015 pub(crate) fn has_pending_layout_or_render(&self) -> bool {
1016 UPDATES_SV
1017 .read()
1018 .update_ext
1019 .intersects(UpdateFlags::LAYOUT | UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE)
1020 }
1021
1022 pub fn sender(&self) -> AppEventSender {
1024 UPDATES_SV.read().event_sender.as_ref().unwrap().clone()
1025 }
1026
1027 pub fn waker(&self, also_update: Option<WidgetId>) -> Waker {
1029 UPDATES_SV.read().event_sender.as_ref().unwrap().waker(also_update)
1030 }
1031
1032 pub(crate) fn update_flags_root(&self, flags: UpdateFlags, window_id: WindowId, root_id: WidgetId) {
1033 if flags.is_empty() {
1034 return;
1035 }
1036
1037 let mut u = UPDATES_SV.write();
1038 if flags.contains(UpdateFlags::UPDATE) {
1039 u.update_widgets.insert_updates_root(window_id, root_id);
1040 }
1041 if flags.contains(UpdateFlags::INFO) {
1042 u.info_widgets.insert_updates_root(window_id, root_id);
1043 }
1044 if flags.contains(UpdateFlags::LAYOUT) {
1045 u.layout_widgets.insert_updates_root(window_id, root_id);
1046 }
1047
1048 if flags.contains(UpdateFlags::RENDER) {
1049 u.render_widgets.insert_updates_root(window_id, root_id);
1050 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1051 u.render_update_widgets.insert_updates_root(window_id, root_id);
1052 }
1053
1054 u.update_ext |= flags;
1055 }
1056
1057 pub(crate) fn update_flags(&self, flags: UpdateFlags, target: WidgetId) {
1058 if flags.is_empty() {
1059 return;
1060 }
1061
1062 let mut u = UPDATES_SV.write();
1063
1064 if flags.contains(UpdateFlags::UPDATE) {
1065 u.update_widgets.search_widget(target);
1066 }
1067 if flags.contains(UpdateFlags::INFO) {
1068 u.info_widgets.search_widget(target);
1069 }
1070 if flags.contains(UpdateFlags::LAYOUT) {
1071 u.layout_widgets.search_widget(target);
1072 }
1073
1074 if flags.contains(UpdateFlags::RENDER) {
1075 u.render_widgets.search_widget(target);
1076 } else if flags.contains(UpdateFlags::RENDER_UPDATE) {
1077 u.render_update_widgets.search_widget(target);
1078 }
1079
1080 u.update_ext |= flags;
1081 }
1082
1083 pub fn update_op(&self, op: UpdateOp, target: WidgetId) -> &Self {
1085 match op {
1086 UpdateOp::Update => self.update(target),
1087 UpdateOp::Info => self.update_info(target),
1088 UpdateOp::Layout => self.layout(target),
1089 UpdateOp::Render => self.render(target),
1090 UpdateOp::RenderUpdate => self.render_update(target),
1091 }
1092 }
1093
1094 pub fn update_op_window(&self, op: UpdateOp, target: WindowId) -> &Self {
1096 match op {
1097 UpdateOp::Update => self.update_window(target),
1098 UpdateOp::Info => self.update_info_window(target),
1099 UpdateOp::Layout => self.layout_window(target),
1100 UpdateOp::Render => self.render_window(target),
1101 UpdateOp::RenderUpdate => self.render_update_window(target),
1102 }
1103 }
1104
1105 pub fn update(&self, target: WidgetId) -> &Self {
1109 UpdatesTrace::log_update();
1110 self.update_internal(target)
1111 }
1112 pub(crate) fn update_internal(&self, target: WidgetId) -> &UPDATES {
1114 let mut u = UPDATES_SV.write();
1115 u.update_ext.insert(UpdateFlags::UPDATE);
1116 u.send_awake();
1117 u.update_widgets.search_widget(target);
1118 self
1119 }
1120
1121 pub fn update_window(&self, target: WindowId) -> &Self {
1123 let mut u = UPDATES_SV.write();
1124 u.update_ext.insert(UpdateFlags::UPDATE);
1125 u.send_awake();
1126 u.update_widgets.insert_window(target);
1127 self
1128 }
1129
1130 pub fn update_app(&self) {
1132 let mut u = UPDATES_SV.write();
1133 u.update_ext.insert(UpdateFlags::UPDATE);
1134 u.send_awake();
1135 }
1136
1137 pub fn update_info(&self, target: WidgetId) -> &Self {
1141 UpdatesTrace::log_info();
1142 let mut u = UPDATES_SV.write();
1143 u.update_ext.insert(UpdateFlags::INFO);
1144 u.send_awake();
1145 u.info_widgets.search_widget(target);
1146 self
1147 }
1148
1149 pub fn update_info_window(&self, target: WindowId) -> &Self {
1151 UpdatesTrace::log_info();
1152 let mut u = UPDATES_SV.write();
1153 u.update_ext.insert(UpdateFlags::INFO);
1154 u.send_awake();
1155 u.info_widgets.insert_window(target);
1156 self
1157 }
1158
1159 pub fn layout(&self, target: WidgetId) -> &Self {
1163 UpdatesTrace::log_layout();
1164 let mut u = UPDATES_SV.write();
1165 u.update_ext.insert(UpdateFlags::LAYOUT);
1166 u.send_awake();
1167 u.layout_widgets.search_widget(target);
1168 self
1169 }
1170
1171 pub fn layout_window(&self, target: WindowId) -> &Self {
1173 UpdatesTrace::log_layout();
1174 let mut u = UPDATES_SV.write();
1175 u.update_ext.insert(UpdateFlags::LAYOUT);
1176 u.send_awake();
1177 u.layout_widgets.insert_window(target);
1178 self
1179 }
1180
1181 pub fn render(&self, target: WidgetId) -> &Self {
1188 UpdatesTrace::log_render();
1189 let mut u = UPDATES_SV.write();
1190 u.update_ext.insert(UpdateFlags::RENDER);
1191 u.send_awake();
1192 u.render_widgets.search_widget(target);
1193 self
1194 }
1195
1196 pub fn render_window(&self, target: WindowId) -> &Self {
1198 UpdatesTrace::log_render();
1199 let mut u = UPDATES_SV.write();
1200 u.update_ext.insert(UpdateFlags::RENDER);
1201 u.send_awake();
1202 u.render_widgets.insert_window(target);
1203 self
1204 }
1205
1206 pub fn render_update(&self, target: WidgetId) -> &Self {
1212 UpdatesTrace::log_render();
1213 let mut u = UPDATES_SV.write();
1214 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1215 u.send_awake();
1216 u.render_update_widgets.search_widget(target);
1217 self
1218 }
1219
1220 pub fn render_update_window(&self, target: WindowId) -> &Self {
1222 UpdatesTrace::log_render();
1223 let mut u = UPDATES_SV.write();
1224 u.update_ext.insert(UpdateFlags::RENDER_UPDATE);
1225 u.send_awake();
1226 u.render_update_widgets.insert_window(target);
1227 self
1228 }
1229
1230 pub fn is_pending_render(&self, window_id: WindowId) -> bool {
1232 let u = UPDATES_SV.read();
1233 u.render_widgets.enter_window(window_id) || u.render_update_widgets.enter_window(window_id)
1234 }
1235
1236 pub fn run<F: Future<Output = ()> + Send + 'static>(&self, future: impl IntoFuture<Output = (), IntoFuture = F>) -> OnUpdateHandle {
1242 let future = future.into_future();
1243 self.run_hn_once(async_hn_once!(|_| future.await))
1244 }
1245
1246 pub fn run_hn_once(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1253 let mut u = UPDATES_SV.write();
1254 u.update_ext.insert(UpdateFlags::UPDATE);
1255 u.send_awake();
1256 Self::push_handler(u.pre_handlers.get_mut(), true, handler.into_once(), true)
1257 }
1258
1259 pub fn on_pre_update(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1274 let u = UPDATES_SV.read();
1275 Self::push_handler(&mut u.pre_handlers.lock(), true, handler, false)
1276 }
1277
1278 pub fn on_update(&self, handler: Handler<UpdateArgs>) -> OnUpdateHandle {
1293 let u = UPDATES_SV.read();
1294 Self::push_handler(&mut u.pos_handlers.lock(), false, handler, false)
1295 }
1296
1297 pub fn update_id(&self) -> VarUpdateId {
1301 VARS.update_id()
1302 }
1303
1304 pub fn once_update(&self, debug_name: &'static str, u: impl FnOnce() + Send + 'static) {
1308 VARS.modify(debug_name, u);
1309 }
1310
1311 pub fn once_next_update(&self, debug_name: &'static str, u: impl FnOnce() + Send + 'static) {
1315 self.run_hn_once(hn_once!(|_| {
1316 UPDATES.once_update(debug_name, u);
1317 }))
1318 .perm();
1319 }
1320
1321 fn push_handler(
1322 entries: &mut Vec<UpdateHandler>,
1323 is_preview: bool,
1324 mut handler: Handler<UpdateArgs>,
1325 force_once: bool,
1326 ) -> OnUpdateHandle {
1327 let (handle_owner, handle) = OnUpdateHandle::new();
1328 entries.push(UpdateHandler {
1329 handle: handle_owner,
1330 count: 0,
1331 handler: Box::new(move |args, handle| {
1332 handler.app_event(handle.clone_boxed(), is_preview, args);
1333 if force_once {
1334 handle.unsubscribe();
1335 }
1336 }),
1337 });
1338 handle
1339 }
1340
1341 pub(crate) fn on_pre_updates(&self) {
1342 let _s = tracing::trace_span!("UPDATES.on_pre_updates");
1343 let mut handlers = mem::take(UPDATES_SV.write().pre_handlers.get_mut());
1344 Self::retain_updates(&mut handlers);
1345
1346 let mut u = UPDATES_SV.write();
1347 handlers.append(u.pre_handlers.get_mut());
1348 *u.pre_handlers.get_mut() = handlers;
1349 }
1350
1351 pub(crate) fn on_updates(&self) {
1352 let _s = tracing::trace_span!("UPDATES.on_updates");
1353 let mut handlers = mem::take(UPDATES_SV.write().pos_handlers.get_mut());
1354 Self::retain_updates(&mut handlers);
1355
1356 let mut u = UPDATES_SV.write();
1357 handlers.append(u.pos_handlers.get_mut());
1358 *u.pos_handlers.get_mut() = handlers;
1359 }
1360
1361 fn retain_updates(handlers: &mut Vec<UpdateHandler>) {
1362 handlers.retain_mut(|e| {
1363 !e.handle.is_dropped() && {
1364 e.count = e.count.wrapping_add(1);
1365 (e.handler)(&UpdateArgs { count: e.count }, &e.handle.weak_handle());
1366 !e.handle.is_dropped()
1367 }
1368 });
1369 }
1370
1371 pub(super) fn take_update(&self) -> (bool, WidgetUpdates) {
1373 let mut u = UPDATES_SV.write();
1374
1375 let ext = u.update_ext.contains(UpdateFlags::UPDATE);
1376 u.update_ext.remove(UpdateFlags::UPDATE);
1377
1378 (
1379 ext,
1380 WidgetUpdates {
1381 delivery_list: mem::take(&mut u.update_widgets),
1382 },
1383 )
1384 }
1385
1386 pub(super) fn take_info(&self) -> (bool, InfoUpdates) {
1388 let mut u = UPDATES_SV.write();
1389
1390 let ext = u.update_ext.contains(UpdateFlags::INFO);
1391 u.update_ext.remove(UpdateFlags::INFO);
1392
1393 (
1394 ext,
1395 InfoUpdates {
1396 delivery_list: mem::take(&mut u.info_widgets),
1397 },
1398 )
1399 }
1400
1401 pub(super) fn take_layout(&self) -> (bool, LayoutUpdates) {
1403 let mut u = UPDATES_SV.write();
1404
1405 let ext = u.update_ext.contains(UpdateFlags::LAYOUT);
1406 u.update_ext.remove(UpdateFlags::LAYOUT);
1407
1408 (
1409 ext,
1410 LayoutUpdates {
1411 delivery_list: mem::take(&mut u.layout_widgets),
1412 },
1413 )
1414 }
1415
1416 pub(super) fn take_render(&self) -> (bool, RenderUpdates, RenderUpdates) {
1418 let mut u = UPDATES_SV.write();
1419
1420 let ext = u.update_ext.intersects(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1421 u.update_ext.remove(UpdateFlags::RENDER | UpdateFlags::RENDER_UPDATE);
1422
1423 (
1424 ext,
1425 RenderUpdates {
1426 delivery_list: mem::take(&mut u.render_widgets),
1427 },
1428 RenderUpdates {
1429 delivery_list: mem::take(&mut u.render_update_widgets),
1430 },
1431 )
1432 }
1433}
1434
1435app_local! {
1436 static UPDATES_SV: UpdatesService = UpdatesService::new();
1437}
1438struct UpdatesService {
1439 event_sender: Option<AppEventSender>,
1440
1441 update_ext: UpdateFlags,
1442 update_widgets: UpdateDeliveryList,
1443 info_widgets: UpdateDeliveryList,
1444 layout_widgets: UpdateDeliveryList,
1445 render_widgets: UpdateDeliveryList,
1446 render_update_widgets: UpdateDeliveryList,
1447
1448 pre_handlers: Mutex<Vec<UpdateHandler>>,
1449 pos_handlers: Mutex<Vec<UpdateHandler>>,
1450
1451 app_is_awake: bool,
1452 awake_pending: bool,
1453}
1454impl UpdatesService {
1455 fn new() -> Self {
1456 Self {
1457 event_sender: None,
1458 update_ext: UpdateFlags::empty(),
1459 update_widgets: UpdateDeliveryList::new(),
1460 info_widgets: UpdateDeliveryList::new(),
1461 layout_widgets: UpdateDeliveryList::new(),
1462 render_widgets: UpdateDeliveryList::new(),
1463 render_update_widgets: UpdateDeliveryList::new(),
1464
1465 pre_handlers: Mutex::new(vec![]),
1466 pos_handlers: Mutex::new(vec![]),
1467
1468 app_is_awake: false,
1469 awake_pending: false,
1470 }
1471 }
1472
1473 fn send_awake(&mut self) {
1474 if !self.app_is_awake && !self.awake_pending {
1475 self.awake_pending = true;
1476 match self.event_sender.as_ref() {
1477 Some(s) => {
1478 if let Err(ChannelError::Disconnected { .. }) = s.send_update_app() {
1479 tracing::debug!("no app connected to update");
1480 }
1481 }
1482 None => {
1483 tracing::debug!("no app connected yet to update");
1484 }
1485 }
1486 }
1487 }
1488
1489 fn app_awake(&mut self, wake: bool) {
1490 self.awake_pending = false;
1491 self.app_is_awake = wake;
1492 }
1493}
1494
1495#[non_exhaustive]
1499#[derive(Default)]
1500pub struct ContextUpdates {
1501 pub update: bool,
1506
1507 pub info: bool,
1512
1513 pub layout: bool,
1518
1519 pub render: bool,
1524
1525 pub update_widgets: WidgetUpdates,
1529
1530 pub info_widgets: InfoUpdates,
1534
1535 pub layout_widgets: LayoutUpdates,
1539
1540 pub render_widgets: RenderUpdates,
1544
1545 pub render_update_widgets: RenderUpdates,
1549}
1550
1551impl fmt::Debug for ContextUpdates {
1552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1553 if f.alternate() {
1554 f.debug_struct("ContextUpdates")
1555 .field("update", &self.update)
1556 .field("info", &self.info)
1557 .field("layout", &self.layout)
1558 .field("render", &self.render)
1559 .field("update_widgets", &self.update_widgets)
1560 .field("info_widgets", &self.info_widgets)
1561 .field("layout_widgets", &self.layout_widgets)
1562 .field("render_widgets", &self.render_widgets)
1563 .field("render_update_widgets", &self.render_update_widgets)
1564 .finish()
1565 } else {
1566 write!(f, "ContextUpdates: ")?;
1567 let mut sep = "";
1568 if self.update {
1569 write!(f, "{sep}update")?;
1570 sep = ", ";
1571 }
1572 if self.info {
1573 write!(f, "{sep}info")?;
1574 sep = ", ";
1575 }
1576 if self.layout {
1577 write!(f, "{sep}layout")?;
1578 sep = ", ";
1579 }
1580 if self.render {
1581 write!(f, "{sep}render")?;
1582 sep = ", ";
1583 }
1584 if sep.is_empty() {
1585 write!(f, "<none>")?;
1586 }
1587 Ok(())
1588 }
1589 }
1590}
1591impl ContextUpdates {
1592 pub fn has_updates(&self) -> bool {
1594 self.update || self.info || self.layout || self.render
1595 }
1596}
1597impl std::ops::BitOrAssign for ContextUpdates {
1598 fn bitor_assign(&mut self, rhs: Self) {
1599 self.update |= rhs.update;
1600 self.update_widgets.extend(rhs.update_widgets);
1601 self.info |= rhs.info;
1602 self.info_widgets.extend(rhs.info_widgets);
1603 self.layout |= rhs.layout;
1604 self.layout_widgets.extend(rhs.layout_widgets);
1605 self.render |= rhs.render;
1606 self.render_widgets.extend(rhs.render_widgets);
1607 self.render_update_widgets.extend(rhs.render_update_widgets);
1608 }
1609}
1610impl std::ops::BitOr for ContextUpdates {
1611 type Output = Self;
1612
1613 fn bitor(mut self, rhs: Self) -> Self {
1614 self |= rhs;
1615 self
1616 }
1617}
1618
1619bitflags::bitflags! {
1620 #[derive(Clone, Copy, Debug, bytemuck::NoUninit)]
1621 #[repr(transparent)]
1622 pub(crate) struct UpdateFlags: u8 {
1623 const REINIT = 0b1000_0000;
1624 const INFO = 0b0001_0000;
1625 const UPDATE = 0b0000_0001;
1626 const LAYOUT = 0b0000_0010;
1627 const RENDER = 0b0000_0100;
1628 const RENDER_UPDATE = 0b0000_1000;
1629 }
1630}
1631
1632#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1637#[repr(transparent)]
1638#[must_use = "dropping the handle unsubscribes update handler"]
1639pub struct OnUpdateHandle(Handle<()>);
1640impl OnUpdateHandle {
1641 fn new() -> (HandleOwner<()>, OnUpdateHandle) {
1642 let (owner, handle) = Handle::new(());
1643 (owner, OnUpdateHandle(handle))
1644 }
1645
1646 pub fn dummy() -> Self {
1650 OnUpdateHandle(Handle::dummy(()))
1651 }
1652
1653 pub fn perm(self) {
1657 self.0.perm();
1658 }
1659
1660 pub fn is_permanent(&self) -> bool {
1664 self.0.is_permanent()
1665 }
1666
1667 pub fn unsubscribe(self) {
1669 self.0.force_drop()
1670 }
1671
1672 pub fn is_unsubscribed(&self) -> bool {
1676 self.0.is_dropped()
1677 }
1678
1679 pub fn downgrade(&self) -> WeakOnUpdateHandle {
1681 WeakOnUpdateHandle(self.0.downgrade())
1682 }
1683}
1684
1685#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
1687pub struct WeakOnUpdateHandle(WeakHandle<()>);
1688impl WeakOnUpdateHandle {
1689 pub fn new() -> Self {
1691 Self(WeakHandle::new())
1692 }
1693
1694 pub fn upgrade(&self) -> Option<OnUpdateHandle> {
1696 self.0.upgrade().map(OnUpdateHandle)
1697 }
1698}
1699
1700#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1702pub enum UpdateOp {
1703 Update,
1713 Info,
1720 Layout,
1726 Render,
1732 RenderUpdate,
1741}
1742
1743#[derive(Debug, Clone, Copy)]
1745#[non_exhaustive]
1746pub struct UpdateArgs {
1747 pub count: usize,
1749}
1750
1751struct UpdateHandler {
1752 handle: HandleOwner<()>,
1753 count: usize,
1754 handler: Box<dyn FnMut(&UpdateArgs, &dyn AppWeakHandle) + Send>,
1755}