1use parking_lot::Mutex;
2use zng_layout::{
3 context::{InlineConstraints, InlineConstraintsLayout, InlineConstraintsMeasure, InlineSegment, InlineSegmentPos, LAYOUT, LayoutMask},
4 unit::{Factor, Px, PxBox, PxPoint, PxRect, PxSize, PxVector},
5};
6use zng_state_map::{OwnedStateMap, StateId, StateMapMut, StateValue};
7use zng_unique_id::{IdMap, IdSet};
8
9use crate::{
10 DInstant, INSTANT,
11 render::TransformStyle,
12 update::{InfoUpdates, LayoutUpdates, UpdateFlags},
13 widget::{WIDGET, WidgetId, WidgetUpdateMode, border::BORDER, node::UiNode},
14 window::{WINDOW, WindowId},
15};
16
17use super::{hit::ParallelSegmentOffsets, *};
18
19pub enum WidgetInfoMeta {}
21
22pub struct WidgetInfoBuilder {
26 info_widgets: Arc<InfoUpdates>,
27 window_id: WindowId,
28 pub(super) access_enabled: access::AccessEnabled,
29 started_access: bool,
30
31 node: tree::NodeId,
32 widget_id: WidgetId,
33 meta: Arc<Mutex<OwnedStateMap<WidgetInfoMeta>>>,
34
35 tree: Tree<WidgetInfoData>,
36 interactivity_filters: InteractivityFilters,
37
38 scale_factor: Factor,
39
40 build_meta: Arc<Mutex<OwnedStateMap<WidgetInfoMeta>>>,
41
42 build_start: DInstant,
43 pushed_widgets: u32,
44}
45impl WidgetInfoBuilder {
46 pub fn new(
48 info_widgets: Arc<InfoUpdates>,
49 window_id: WindowId,
50 access_enabled: access::AccessEnabled,
51 root_id: WidgetId,
52 root_bounds_info: WidgetBoundsInfo,
53 root_border_info: WidgetBorderInfo,
54 scale_factor: Factor,
55 ) -> Self {
56 let tree = Tree::new(WidgetInfoData {
57 id: root_id,
58 is_reused: false,
59 bounds_info: root_bounds_info,
60 border_info: root_border_info,
61 meta: Arc::new(OwnedStateMap::new()),
62 interactivity_filters: vec![],
63 local_interactivity: Interactivity::ENABLED,
64 cache: Mutex::new(WidgetInfoCache { interactivity: None }),
65 });
66 let mut lookup = IdMap::default();
67 let root_node = tree.root().id();
68 lookup.insert(root_id, root_node);
69
70 let mut builder = WidgetInfoBuilder {
71 info_widgets,
72 window_id,
73 access_enabled,
74 started_access: access_enabled.is_enabled() && WINDOW.info().access_enabled().is_disabled(),
75 node: root_node,
76 tree,
77 interactivity_filters: vec![],
78 meta: Arc::default(),
79 widget_id: root_id,
80 scale_factor,
81 build_meta: Arc::default(),
82 build_start: INSTANT.now(),
83 pushed_widgets: 1, };
85
86 if let Some(mut b) = builder.access() {
87 b.set_role(super::access::AccessRole::Application);
88 }
89
90 builder
91 }
92
93 fn node(&mut self, id: tree::NodeId) -> tree::NodeMut<WidgetInfoData> {
94 self.tree.index_mut(id)
95 }
96
97 pub fn widget_id(&self) -> WidgetId {
99 self.widget_id
100 }
101
102 pub fn with_build_meta<R>(&mut self, visitor: impl FnOnce(StateMapMut<WidgetInfoMeta>) -> R) -> R {
106 visitor(self.build_meta.lock().borrow_mut())
107 }
108 pub fn set_build_meta<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) {
110 let id = id.into();
111 let value = value.into();
112 self.with_build_meta(|mut s| s.set(id, value));
113 }
114 pub fn flag_build_meta(&mut self, id: impl Into<StateId<()>>) {
116 let id = id.into();
117 self.with_build_meta(|mut s| s.flag(id));
118 }
119
120 pub fn with_meta<R>(&mut self, visitor: impl FnOnce(StateMapMut<WidgetInfoMeta>) -> R) -> R {
122 visitor(self.meta.lock().borrow_mut())
123 }
124 pub fn set_meta<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) {
128 let id = id.into();
129 let value = value.into();
130 self.with_meta(|mut s| s.set(id, value));
131 }
132 pub fn flag_meta(&mut self, id: impl Into<StateId<()>>) {
134 let id = id.into();
135 self.with_meta(|mut s| s.flag(id));
136 }
137
138 pub fn push_widget(&mut self, f: impl FnOnce(&mut Self)) {
142 let id = WIDGET.id();
143 if !WIDGET.take_update(UpdateFlags::INFO) && !self.info_widgets.delivery_list().enter_widget(id) && !self.started_access {
144 let tree = WINDOW.info();
146 if let Some(wgt) = tree.get(id) {
147 self.tree.index_mut(self.node).push_reuse(wgt.node(), &mut |old_data| {
148 let mut r = old_data.clone();
149 r.is_reused = true;
150 r.cache.get_mut().interactivity = None;
151 for filter in &r.interactivity_filters {
152 self.interactivity_filters.push(filter.clone());
153 }
154 r
155 });
156 return;
157 }
158 }
159
160 let parent_node = self.node;
161 let parent_widget_id = self.widget_id;
162 let parent_meta = mem::take(&mut self.meta);
163
164 let bounds_info = WIDGET.bounds();
165 let border_info = WIDGET.border();
166
167 self.widget_id = id;
168 self.node = self
169 .node(parent_node)
170 .push_child(WidgetInfoData {
171 id,
172 is_reused: false,
173 bounds_info,
174 border_info,
175 meta: Arc::new(OwnedStateMap::new()),
176 interactivity_filters: vec![],
177 local_interactivity: Interactivity::ENABLED,
178 cache: Mutex::new(WidgetInfoCache { interactivity: None }),
179 })
180 .id();
181
182 self.pushed_widgets += 1;
183
184 f(self);
185
186 let meta = mem::replace(&mut self.meta, parent_meta);
187 let mut node = self.node(self.node);
188 node.value().meta = Arc::new(Arc::try_unwrap(meta).unwrap().into_inner());
189 node.close();
190
191 self.node = parent_node;
192 self.widget_id = parent_widget_id;
193 }
194
195 pub fn push_interactivity(&mut self, interactivity: Interactivity) {
201 let mut node = self.node(self.node);
202 let v = node.value();
203 v.local_interactivity |= interactivity;
204 }
205
206 pub fn push_interactivity_filter(&mut self, filter: impl Fn(&InteractivityFilterArgs) -> Interactivity + Send + Sync + 'static) {
217 let filter = Arc::new(filter);
218 self.interactivity_filters.push(filter.clone());
219 self.node(self.node).value().interactivity_filters.push(filter);
220 }
221
222 pub fn with_children_range(&mut self, info: impl FnOnce(&mut Self)) -> ops::Range<usize> {
224 let before_count = self.tree.index(self.node).children_count();
225 info(self);
226 before_count..self.tree.index(self.node).children_count()
227 }
228
229 pub fn parallel_split(&self) -> ParallelBuilder<Self> {
234 let node = self.tree.index(self.node).value();
235 let tree = Tree::new(WidgetInfoData {
236 id: node.id,
237 is_reused: node.is_reused,
238 bounds_info: node.bounds_info.clone(),
239 border_info: node.border_info.clone(),
240 meta: node.meta.clone(),
241 interactivity_filters: vec![],
242 local_interactivity: node.local_interactivity,
243 cache: Mutex::new(WidgetInfoCache { interactivity: None }),
244 });
245 ParallelBuilder(Some(Self {
246 info_widgets: self.info_widgets.clone(),
247 window_id: self.window_id,
248 access_enabled: self.access_enabled,
249 started_access: self.started_access,
250 widget_id: self.widget_id,
251 meta: self.meta.clone(),
252 node: tree.root().id(),
253 tree,
254 interactivity_filters: vec![],
255 scale_factor: self.scale_factor,
256 build_meta: self.build_meta.clone(),
257 build_start: self.build_start,
258 pushed_widgets: 0,
259 }))
260 }
261
262 pub fn parallel_fold(&mut self, mut split: ParallelBuilder<Self>) {
264 let mut split = split.take();
265
266 self.interactivity_filters.append(&mut split.interactivity_filters);
267 self.pushed_widgets += split.pushed_widgets;
268 {
269 debug_assert!(Arc::ptr_eq(&self.meta, &split.meta));
270
271 let mut split_node = split.tree.root_mut();
272 let mut node = self.node(self.node);
273 let split_node = split_node.value();
274 let node = node.value();
275
276 node.interactivity_filters.append(&mut split_node.interactivity_filters);
277 node.local_interactivity |= split_node.local_interactivity;
278 }
279
280 self.tree.index_mut(self.node).parallel_fold(split.tree, &mut |d| WidgetInfoData {
281 id: d.id,
282 is_reused: d.is_reused,
283 bounds_info: d.bounds_info.clone(),
284 border_info: d.border_info.clone(),
285 meta: d.meta.clone(),
286 interactivity_filters: mem::take(&mut d.interactivity_filters),
287 local_interactivity: d.local_interactivity,
288 cache: Mutex::new(d.cache.get_mut().clone()),
289 });
290 }
291
292 pub fn finalize(mut self, previous_tree: Option<WidgetInfoTree>, notify: bool) -> WidgetInfoTree {
296 let mut node = self.tree.root_mut();
297 let meta = Arc::new(Arc::try_unwrap(self.meta).unwrap().into_inner());
298 node.value().meta = meta;
299 node.close();
300
301 let generation;
302 let widget_count_offsets;
303 let spatial_bounds;
304 let transform_changed_subs;
305 let visibility_changed_subs;
306
307 if let Some(t) = &previous_tree {
308 let t = t.0.frame.read();
309 generation = t.stats.generation.wrapping_add(1);
310 widget_count_offsets = t.widget_count_offsets.clone();
311 spatial_bounds = t.spatial_bounds;
312 transform_changed_subs = t.transform_changed_subs.clone();
313 visibility_changed_subs = t.visibility_changed_subs.clone();
314 } else {
315 generation = 0;
316 widget_count_offsets = ParallelSegmentOffsets::default();
317 spatial_bounds = PxBox::zero();
318 transform_changed_subs = IdMap::new();
319 visibility_changed_subs = IdMap::new();
320 }
321
322 let mut lookup = IdMap::new();
323 lookup.reserve(self.tree.len());
324 let mut out_of_bounds = vec![];
325
326 for (id, data) in self.tree.iter() {
327 if lookup.insert(data.id, id).is_some() {
328 tracing::error!("widget `{}` repeated in info tree", data.id);
329 }
330 if data.bounds_info.is_actually_out_of_bounds() {
331 out_of_bounds.push(id);
332 }
333 }
334 out_of_bounds.shrink_to_fit();
335
336 let tree = WidgetInfoTree(Arc::new(WidgetInfoTreeInner {
337 window_id: self.window_id,
338 access_enabled: self.access_enabled,
339 lookup,
340 interactivity_filters: self.interactivity_filters,
341 build_meta: Arc::new(mem::take(&mut self.build_meta.lock())),
342
343 frame: RwLock::new(WidgetInfoTreeFrame {
344 stats: WidgetInfoTreeStats::new(self.build_start, self.tree.len() as u32 - self.pushed_widgets, generation),
345 stats_update: Default::default(),
346 out_of_bounds: Arc::new(out_of_bounds),
347 out_of_bounds_update: Default::default(),
348 scale_factor: self.scale_factor,
349 spatial_bounds,
350 widget_count_offsets,
351 transform_changed_subs,
352 visibility_changed_subs,
353 view_process_gen: ViewProcessGen::INVALID,
354 }),
355
356 tree: self.tree,
357 }));
358
359 if notify {
360 let prev_tree = previous_tree.unwrap_or_else(|| WidgetInfoTree::wgt(tree.window_id(), tree.root().id()));
361 let args = WidgetInfoChangedArgs::now(tree.window_id(), prev_tree.clone(), tree.clone());
362 WIDGET_INFO_CHANGED_EVENT.notify(args);
363
364 let mut targets = IdSet::default();
365 INTERACTIVITY_CHANGED_EVENT.visit_subscribers::<()>(|wid| {
366 if let Some(wgt) = tree.get(wid) {
367 let prev = prev_tree.get(wid).map(|w| w.interactivity());
368 let new_int = wgt.interactivity();
369 if prev != Some(new_int) {
370 targets.insert(wid);
371 }
372 }
373 ops::ControlFlow::Continue(())
374 });
375 if !targets.is_empty() {
376 let args = InteractivityChangedArgs::now(prev_tree, tree.clone(), targets);
377 INTERACTIVITY_CHANGED_EVENT.notify(args);
378 }
379 }
380
381 tree
382 }
383}
384
385crate::event::event! {
386 pub static WIDGET_INFO_CHANGED_EVENT: WidgetInfoChangedArgs;
388
389 pub static INTERACTIVITY_CHANGED_EVENT: InteractivityChangedArgs;
396
397 pub static VISIBILITY_CHANGED_EVENT: VisibilityChangedArgs;
402
403 pub static TRANSFORM_CHANGED_EVENT: TransformChangedArgs;
408}
409
410crate::event::event_args! {
411 pub struct WidgetInfoChangedArgs {
413 pub window_id: WindowId,
415
416 pub prev_tree: WidgetInfoTree,
420
421 pub tree: WidgetInfoTree,
423
424 ..
425
426 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
428 list.search_all()
429 }
430 }
431
432 pub struct TransformChangedArgs {
434 pub tree: WidgetInfoTree,
436
437 pub changed: IdMap<WidgetId, PxTransform>,
439
440 ..
441
442 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
444 for id in self.changed.keys() {
445 if let Some(wgt) = self.tree.get(*id) {
446 list.insert_wgt(&wgt);
447 }
448 }
449 }
450 }
451
452 pub struct VisibilityChangedArgs {
454 pub tree: WidgetInfoTree,
456
457 pub changed: IdMap<WidgetId, Visibility>,
459
460 ..
461
462 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
464 for id in self.changed.keys() {
465 if let Some(wgt) = self.tree.get(*id) {
466 list.insert_wgt(&wgt);
467 }
468 }
469 }
470 }
471
472 pub struct InteractivityChangedArgs {
474 pub prev_tree: WidgetInfoTree,
476
477 pub tree: WidgetInfoTree,
479
480 pub changed: IdSet<WidgetId>,
482
483 ..
484
485 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
487 for id in self.changed.iter() {
488 if let Some(wgt) = self.tree.get(*id) {
489 list.insert_wgt(&wgt);
490 }
491 }
492 }
493 }
494}
495impl TransformChangedArgs {
496 pub fn change(&self, id: WidgetId) -> Option<(PxTransform, PxTransform)> {
498 let prev = *self.changed.get(&id)?;
499 let new = self.tree.get(id)?.inner_transform();
500 Some((prev, new))
501 }
502
503 pub fn offset(&self, id: WidgetId) -> Option<PxVector> {
505 let (prev, new) = self.change(id)?;
506
507 let prev = prev.transform_point(PxPoint::zero()).unwrap_or_default();
508 let new = new.transform_point(PxPoint::zero()).unwrap_or_default();
509 Some(prev - new)
510 }
511}
512impl InteractivityChangedArgs {
513 pub fn prev_interactivity(&self, widget_id: WidgetId) -> Option<Interactivity> {
517 self.prev_tree.get(widget_id).map(|w| w.interactivity())
518 }
519
520 pub fn new_interactivity(&self, widget_id: WidgetId) -> Interactivity {
529 if let Some(w) = self.tree.get(widget_id) {
530 w.interactivity()
531 } else if self.changed.contains(&widget_id) {
532 panic!("widget {widget_id} was in targets and not in new tree, invalid args");
533 } else {
534 panic!("widget {widget_id} is not in targets");
535 }
536 }
537
538 pub fn is_enable(&self, widget_id: WidgetId) -> bool {
540 self.prev_interactivity(widget_id).unwrap_or(Interactivity::DISABLED).is_disabled()
541 && self.new_interactivity(widget_id).is_enabled()
542 }
543
544 pub fn is_disable(&self, widget_id: WidgetId) -> bool {
546 self.prev_interactivity(widget_id).unwrap_or(Interactivity::ENABLED).is_enabled() && self.new_interactivity(widget_id).is_disabled()
547 }
548
549 pub fn is_unblock(&self, widget_id: WidgetId) -> bool {
551 self.prev_interactivity(widget_id).unwrap_or(Interactivity::BLOCKED).is_blocked() && !self.new_interactivity(widget_id).is_blocked()
552 }
553
554 pub fn is_block(&self, widget_id: WidgetId) -> bool {
556 !self.prev_interactivity(widget_id).unwrap_or(Interactivity::BLOCKED).is_blocked() && self.new_interactivity(widget_id).is_blocked()
557 }
558
559 pub fn is_vis_enable(&self, widget_id: WidgetId) -> bool {
561 self.prev_interactivity(widget_id)
562 .unwrap_or(Interactivity::DISABLED)
563 .is_vis_disabled()
564 && self.new_interactivity(widget_id).is_vis_enabled()
565 }
566
567 pub fn is_vis_disable(&self, widget_id: WidgetId) -> bool {
569 self.prev_interactivity(widget_id)
570 .unwrap_or(Interactivity::ENABLED)
571 .is_vis_enabled()
572 && self.new_interactivity(widget_id).is_vis_disabled()
573 }
574
575 pub fn enabled_change(&self, widget_id: WidgetId) -> Option<(Option<Interactivity>, Interactivity)> {
577 self.change_check(widget_id, Interactivity::is_enabled)
578 }
579
580 pub fn vis_enabled_change(&self, widget_id: WidgetId) -> Option<(Option<Interactivity>, Interactivity)> {
582 self.change_check(widget_id, Interactivity::is_vis_enabled)
583 }
584
585 pub fn blocked_change(&self, widget_id: WidgetId) -> Option<(Option<Interactivity>, Interactivity)> {
587 self.change_check(widget_id, Interactivity::is_blocked)
588 }
589
590 fn change_check(&self, widget_id: WidgetId, mtd: impl Fn(Interactivity) -> bool) -> Option<(Option<Interactivity>, Interactivity)> {
591 let new = self.new_interactivity(widget_id);
592 let prev = self.prev_interactivity(widget_id);
593 if let Some(prev) = prev {
594 if mtd(prev) != mtd(new) { Some((Some(prev), new)) } else { None }
595 } else {
596 Some((prev, new))
597 }
598 }
599
600 pub fn is_new(&self, widget_id: WidgetId) -> bool {
603 !self.prev_tree.contains(widget_id) && self.tree.contains(widget_id)
604 }
605}
606
607impl VisibilityChangedArgs {
608 pub fn change(&self, widget_id: WidgetId) -> Option<(Visibility, Visibility)> {
610 let prev = *self.changed.get(&widget_id)?;
611 let new = self.tree.get(widget_id)?.visibility();
612 Some((prev, new))
613 }
614
615 pub fn prev_vis(&self, widget_id: WidgetId) -> Option<Visibility> {
617 self.changed.get(&widget_id).copied()
618 }
619
620 pub fn new_vis(&self, widget_id: WidgetId) -> Option<Visibility> {
622 self.change(widget_id).map(|(_, n)| n)
623 }
624
625 pub fn is_collapse(&self, widget_id: WidgetId) -> bool {
627 matches!(
628 self.change(widget_id),
629 Some((Visibility::Visible | Visibility::Hidden, Visibility::Collapsed))
630 )
631 }
632
633 pub fn is_hide(&self, widget_id: WidgetId) -> bool {
635 matches!(
636 self.change(widget_id),
637 Some((Visibility::Visible | Visibility::Collapsed, Visibility::Hidden))
638 )
639 }
640
641 pub fn is_show(&self, widget_id: WidgetId) -> bool {
643 matches!(
644 self.change(widget_id),
645 Some((Visibility::Hidden | Visibility::Collapsed, Visibility::Visible))
646 )
647 }
648}
649
650#[derive(Clone, Debug, Default, PartialEq)]
652pub struct WidgetInlineMeasure {
653 pub first: PxSize,
657
658 pub first_wrapped: bool,
660
661 pub first_segs: Arc<Vec<InlineSegment>>,
665
666 pub last: PxSize,
675
676 pub last_wrapped: bool,
678
679 pub last_segs: Arc<Vec<InlineSegment>>,
683}
684impl WidgetInlineMeasure {
685 pub fn with_first_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
690 Self::with_segs(&mut self.first_segs, f)
691 }
692
693 pub fn with_last_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
698 Self::with_segs(&mut self.last_segs, f)
699 }
700
701 fn with_segs(items: &mut Arc<Vec<InlineSegment>>, f: impl FnOnce(&mut Vec<InlineSegment>)) {
702 match Arc::get_mut(items) {
703 Some(items) => {
704 items.clear();
705 f(items);
706 }
707 None => {
708 let mut new = vec![];
709 f(&mut new);
710 *items = Arc::new(new);
711 }
712 }
713 }
714
715 pub fn is_default(&self) -> bool {
719 self.first.is_empty()
720 && !self.first_wrapped
721 && self.first_segs.is_empty()
722 && self.last.is_empty()
723 && !self.last_wrapped
724 && self.last_segs.is_empty()
725 }
726}
727
728#[derive(Clone, Copy, Debug, PartialEq, Eq)]
732pub struct InlineSegmentInfo {
733 pub x: Px,
735 pub width: Px,
739}
740
741#[derive(Debug, Default)]
743pub struct WidgetInlineInfo {
744 pub rows: Vec<PxRect>,
748
749 pub first_segs: Vec<InlineSegmentInfo>,
759
760 pub last_segs: Vec<InlineSegmentInfo>,
762
763 pub inner_size: PxSize,
765
766 negative_space: Mutex<(Arc<Vec<PxRect>>, bool)>,
767}
768impl WidgetInlineInfo {
769 pub fn set_first_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
777 Self::set_segs(&mut self.first_segs, segs);
778 self.invalidate_negative_space();
779 }
780
781 pub fn set_last_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
789 Self::set_segs(&mut self.last_segs, segs);
790 self.invalidate_negative_space();
791 }
792
793 fn set_segs(vec: &mut Vec<InlineSegmentInfo>, segs: impl Iterator<Item = InlineSegmentInfo>) {
794 vec.clear();
795
796 let mut needs_sort = false;
797
798 for seg in segs {
799 if seg.width <= 0 {
800 continue;
801 }
802
803 if let Some(last) = vec.last_mut() {
804 let la = last.x;
805 let lb = last.x + last.width;
806
807 let a = seg.x;
808 let b = seg.x + seg.width;
809
810 if la.max(a) <= lb.min(b) {
811 last.x = a.min(la);
813 last.width = b.max(lb) - last.x;
814 continue;
815 }
816
817 needs_sort |= a < la;
818 }
819 vec.push(seg);
820 }
821
822 if needs_sort {
823 vec.sort_unstable_by_key(|s| s.x);
824 }
825 }
826
827 pub fn union(&self) -> PxRect {
829 self.rows.iter().fold(PxRect::zero(), |union, row| union.union(row))
830 }
831
832 pub fn negative_space(&self) -> Arc<Vec<PxRect>> {
840 let mut space = self.negative_space.lock();
841 if space.1 {
842 return space.0.clone();
843 }
844
845 let mut vec = Arc::try_unwrap(mem::take(&mut space.0)).unwrap_or_default();
846 vec.clear();
847
848 self.negative_enveloped(&mut vec, PxRect::from_size(self.inner_size));
849
850 let r = Arc::new(vec);
851 *space = (r.clone(), true);
852 r
853 }
854
855 pub fn invalidate_negative_space(&mut self) {
859 self.negative_space.get_mut().1 = false;
860 }
861
862 fn negative_enveloped(&self, space: &mut Vec<PxRect>, bounds: PxRect) {
863 let bounds_max_x = bounds.max_x();
864 let mut last_max_y = bounds.origin.y;
865
866 for r in &self.rows {
867 let spacing_y = r.origin.y - last_max_y;
868 if spacing_y > Px(0) {
869 space.push(PxRect::new(
870 PxPoint::new(bounds.origin.x, last_max_y),
871 PxSize::new(bounds.size.width, spacing_y),
872 ));
873 }
874 last_max_y = r.max_y();
875
876 let left = r.origin.x - bounds.origin.x;
877 if left > Px(0) {
878 space.push(PxRect::new(
879 PxPoint::new(bounds.origin.x, r.origin.y),
880 PxSize::new(left, r.size.height),
881 ));
882 }
883 let max_x = r.max_x();
884 let right = bounds_max_x - max_x;
885 if right > Px(0) {
886 space.push(PxRect::new(PxPoint::new(max_x, r.origin.y), PxSize::new(right, r.size.height)));
887 }
888 }
889 let spacing_y = bounds.max_y() - last_max_y;
890 if spacing_y > Px(0) {
891 space.push(PxRect::new(
892 PxPoint::new(bounds.origin.x, last_max_y),
893 PxSize::new(bounds.size.width, spacing_y),
894 ));
895 }
896
897 if let Some(r) = self.rows.first() {
898 if !self.first_segs.is_empty() {
899 let mut x = r.origin.x;
900 for seg in self.first_segs.iter() {
901 let blank = seg.x - x;
902 if blank > Px(0) {
903 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
904 }
905 x = seg.x + seg.width;
906 }
907 let blank = r.max_x() - x;
908 if blank > Px(0) {
909 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
910 }
911 }
912 }
913 if let Some(r) = self.rows.last() {
914 if !self.last_segs.is_empty() {
915 let mut x = r.origin.x;
916 for seg in self.last_segs.iter() {
917 let blank = seg.x - x;
918 if blank > Px(0) {
919 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
920 }
921 x = seg.x + seg.width;
922 }
923 let blank = r.max_x() - x;
924 if blank > Px(0) {
925 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
926 }
927 }
928 }
929 }
930
931 pub fn clear(&mut self) {
933 self.first_segs.clear();
934 self.last_segs.clear();
935 self.rows.clear();
936 self.inner_size = PxSize::zero();
937 self.invalidate_negative_space();
938 }
939
940 pub fn is_default(&self) -> bool {
944 self.rows.is_empty() && self.first_segs.is_empty() && self.last_segs.is_empty() && self.inner_size.is_empty()
945 }
946}
947impl Clone for WidgetInlineInfo {
948 fn clone(&self) -> Self {
949 Self {
950 rows: self.rows.clone(),
951 first_segs: self.first_segs.clone(),
952 last_segs: self.last_segs.clone(),
953 inner_size: self.inner_size,
954 negative_space: Mutex::new((Arc::new(vec![]), false)),
955 }
956 }
957
958 fn clone_from(&mut self, source: &Self) {
959 self.clear();
960 self.rows.extend_from_slice(&source.rows);
961 self.first_segs.extend_from_slice(&source.first_segs);
962 self.last_segs.extend_from_slice(&source.last_segs);
963 self.inner_size = source.inner_size;
964 }
965}
966impl PartialEq for WidgetInlineInfo {
967 fn eq(&self, other: &Self) -> bool {
968 self.rows == other.rows
969 && self.first_segs == other.first_segs
970 && self.last_segs == other.last_segs
971 && self.inner_size == other.inner_size
972 }
973}
974
975pub struct WidgetMeasure {
979 layout_widgets: Arc<LayoutUpdates>,
980 inline: Option<WidgetInlineMeasure>,
981 inline_locked: bool,
982}
983impl WidgetMeasure {
984 pub(crate) fn new(layout_widgets: Arc<LayoutUpdates>) -> Self {
985 Self {
986 layout_widgets,
987 inline: None,
988 inline_locked: false,
989 }
990 }
991
992 pub fn new_reuse(inline: Option<WidgetInlineMeasure>) -> Self {
996 let mut r = Self::new(Arc::default());
997 r.inline = inline;
998 r
999 }
1000
1001 pub fn is_inline(&self) -> bool {
1003 self.inline.is_some()
1004 }
1005
1006 pub fn inline(&mut self) -> Option<&mut WidgetInlineMeasure> {
1012 self.inline.as_mut()
1013 }
1014
1015 pub fn disable_inline(&mut self) {
1028 if !self.inline_locked {
1029 self.inline = None;
1030 }
1031 }
1032
1033 pub fn measure_block(&mut self, child: &mut impl UiNode) -> PxSize {
1035 self.disable_inline();
1036 LAYOUT.with_no_inline(|| child.measure(self))
1037 }
1038
1039 pub fn measure_inline(&mut self, first_max: Px, mid_clear_min: Px, child: &mut impl UiNode) -> (Option<WidgetInlineMeasure>, PxSize) {
1052 let constraints = InlineConstraints::Measure(InlineConstraintsMeasure { first_max, mid_clear_min });
1053 let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1054 let size = LAYOUT.with_context(metrics, || child.measure(self));
1055 let inline = child
1056 .with_context(WidgetUpdateMode::Ignore, || WIDGET.bounds().measure_inline())
1057 .flatten();
1058 (inline, size)
1059 }
1060
1061 pub fn with_widget(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1063 let metrics = LAYOUT.metrics();
1064 let bounds = WIDGET.bounds();
1065
1066 let snap = metrics.snapshot();
1067 if !WIDGET.layout_is_pending(&self.layout_widgets) {
1068 let measure_uses = bounds.measure_metrics_used();
1069 if bounds.measure_metrics().map(|m| m.masked_eq(&snap, measure_uses)).unwrap_or(false) {
1070 let mut reused = false;
1071 if let Some(inline) = self.inline() {
1072 if let Some(prev) = bounds.measure_inline() {
1073 *inline = prev;
1074 reused = true;
1075 }
1076 } else {
1077 reused = bounds.measure_inline().is_none();
1078 }
1079
1080 if reused {
1081 return bounds.measure_outer_size();
1083 }
1084 }
1085 }
1086
1087 let parent_inline = self.inline.take();
1088 if LAYOUT.inline_constraints().is_some() {
1089 self.inline = Some(Default::default());
1090 }
1091
1092 let (measure_uses, size) = LAYOUT.capture_metrics_use(|| measure(self));
1093
1094 bounds.set_measure_metrics(Some(snap), measure_uses);
1095 bounds.set_measure_outer_size(size);
1096
1097 if let Some(inline) = self.inline.take() {
1098 if inline.is_default() && !size.is_empty() {
1099 bounds.set_measure_inline(None);
1101 } else {
1102 #[cfg(debug_assertions)]
1103 if !inline.last_wrapped && inline.first != inline.last {
1104 tracing::error!(
1105 "widget {:?} invalid inline measure, last {:?} != first {:?} but last did not wrap",
1106 WIDGET.id(),
1107 inline.last,
1108 inline.first
1109 );
1110 }
1111
1112 bounds.set_measure_inline(Some(inline));
1113 }
1114 } else {
1115 bounds.set_measure_inline(None);
1116 }
1117 self.inline = parent_inline;
1118
1119 size
1120 }
1121
1122 pub fn with_inline_visual(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1129 self.inline_locked = true;
1130 if self.inline.is_none() {
1131 self.inline = Some(Default::default());
1132 }
1133 let metrics = LAYOUT.metrics();
1134 let size = if metrics.inline_constraints().is_none() {
1135 let constraints = InlineConstraints::Measure(InlineConstraintsMeasure {
1136 first_max: metrics.constraints().x.max_or(Px::MAX),
1137 mid_clear_min: Px(0),
1138 });
1139 let metrics = metrics.with_inline_constraints(Some(constraints));
1140 LAYOUT.with_context(metrics, || measure(self))
1141 } else {
1142 measure(self)
1143 };
1144 self.inline_locked = false;
1145
1146 let inline = self.inline.clone().unwrap();
1147 let bounds = WIDGET.bounds();
1148 if inline.is_default() && !size.is_empty() {
1149 bounds.set_measure_inline(None);
1151 } else {
1152 bounds.set_measure_inline(Some(inline));
1153 }
1154 bounds.set_measure_outer_size(size);
1155
1156 size
1157 }
1158
1159 pub fn parallel_split(&self) -> ParallelBuilder<WidgetMeasure> {
1166 ParallelBuilder(Some(Self {
1167 layout_widgets: self.layout_widgets.clone(),
1168 inline: self.inline.clone(),
1169 inline_locked: self.inline_locked,
1170 }))
1171 }
1172
1173 pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetMeasure>) {
1175 let _ = split.take();
1176 }
1177}
1178
1179pub struct WidgetLayout {
1181 layout_widgets: Arc<LayoutUpdates>,
1182 bounds: WidgetBoundsInfo,
1183 nest_group: LayoutNestGroup,
1184 inline: Option<WidgetInlineInfo>,
1185 needs_ref_count: Option<u32>,
1186}
1187impl WidgetLayout {
1188 pub fn with_root_widget(layout_widgets: Arc<LayoutUpdates>, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1192 Self {
1193 layout_widgets,
1194 bounds: WIDGET.bounds(),
1195 nest_group: LayoutNestGroup::Inner,
1196 inline: None,
1197 needs_ref_count: None,
1198 }
1199 .with_widget(layout)
1200 }
1201
1202 pub fn parallel_split(&self) -> ParallelBuilder<WidgetLayout> {
1212 if self.nest_group != LayoutNestGroup::Child && WIDGET.parent_id().is_some() {
1213 tracing::error!("called `parallel_split` outside child scope");
1214 }
1215 ParallelBuilder(Some(WidgetLayout {
1216 layout_widgets: self.layout_widgets.clone(),
1217 bounds: self.bounds.clone(),
1218 nest_group: LayoutNestGroup::Child,
1219 inline: None,
1220 needs_ref_count: None,
1221 }))
1222 }
1223
1224 pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetLayout>) {
1226 let folded = split.take();
1227 assert_eq!(self.bounds, folded.bounds);
1228
1229 let count = self.needs_ref_count.unwrap_or(0) + folded.needs_ref_count.unwrap_or(0);
1230 self.needs_ref_count = Some(count);
1231 }
1232
1233 pub fn with_widget(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1242 let metrics = LAYOUT.metrics();
1243 let bounds = WIDGET.bounds();
1244
1245 let snap = metrics.snapshot();
1246 if let Some(c) = &mut self.needs_ref_count {
1247 *c += 1;
1248 }
1249
1250 if !WIDGET.take_update(UpdateFlags::LAYOUT) && !self.layout_widgets.delivery_list().enter_widget(WIDGET.id()) {
1251 let uses = bounds.metrics_used();
1253 if bounds.metrics().map(|m| m.masked_eq(&snap, uses)).unwrap_or(false) {
1254 LAYOUT.register_metrics_use(uses); return bounds.outer_size();
1257 }
1258 }
1259
1260 let parent_needs_ref_count = self.needs_ref_count.take();
1261 let parent_inline = self.inline.take();
1262 if LAYOUT.inline_constraints().is_some() && bounds.measure_inline().is_some() {
1263 self.inline = bounds.take_inline();
1265 if let Some(inline) = self.inline.as_mut() {
1266 inline.clear();
1267 } else {
1268 self.inline = Some(Default::default());
1269 }
1270 }
1271 let parent_bounds = mem::replace(&mut self.bounds, bounds);
1272 self.nest_group = LayoutNestGroup::Inner;
1273 let prev_inner_offset = self.bounds.inner_offset();
1274 let prev_child_offset = self.bounds.child_offset();
1275 let prev_baseline = self.bounds.baseline();
1276 let prev_inner_offset_baseline = self.bounds.inner_offset_baseline();
1277 let prev_can_auto_hide = self.bounds.can_auto_hide();
1278 let prev_transform_style = self.bounds.transform_style();
1279 let prev_perspective = self.bounds.raw_perspective();
1280 let prev_perspective_origin = self.bounds.raw_perspective_origin();
1281 self.bounds.set_inner_offset(PxVector::zero());
1282 self.bounds.set_child_offset(PxVector::zero());
1283 self.bounds.set_baseline(Px(0));
1284 self.bounds.set_inner_offset_baseline(false);
1285 self.bounds.set_can_auto_hide(true);
1286 self.bounds.set_transform_style(TransformStyle::Flat);
1287 self.bounds.set_perspective(f32::INFINITY);
1288 self.bounds.set_perspective_origin(None);
1289
1290 let (uses, size) = LAYOUT.capture_metrics_use(|| layout(self));
1292
1293 LAYOUT.register_metrics_use(uses);
1294 self.bounds.set_outer_size(size);
1295 self.bounds.set_metrics(Some(snap), uses);
1296 if let Some(inline) = &mut self.inline {
1297 inline.inner_size = self.bounds.inner_size();
1298 inline.invalidate_negative_space();
1299 }
1300 self.bounds.set_inline(self.inline.take());
1301
1302 if prev_can_auto_hide != self.bounds.can_auto_hide() || prev_transform_style != self.bounds.transform_style() {
1303 WIDGET.render();
1304 } else if prev_inner_offset != self.bounds.inner_offset()
1305 || prev_child_offset != self.bounds.child_offset()
1306 || prev_inner_offset_baseline != self.bounds.inner_offset_baseline()
1307 || prev_perspective != self.bounds.raw_perspective()
1308 || prev_perspective_origin != self.bounds.raw_perspective_origin()
1309 || (self.bounds.inner_offset_baseline() && prev_baseline != self.bounds.baseline())
1310 {
1311 WIDGET.render_update();
1312 }
1313
1314 self.needs_ref_count = parent_needs_ref_count;
1315 self.inline = parent_inline;
1316 self.bounds = parent_bounds;
1317 self.nest_group = LayoutNestGroup::Child;
1318
1319 size
1320 }
1321
1322 pub fn with_inline_visual(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1327 if self.is_inline() {
1328 let size = layout(self);
1329 WIDGET.bounds().set_inline(self.inline.clone());
1330 size
1331 } else {
1332 let bounds = WIDGET.bounds();
1333 if let Some(measure) = bounds.measure_inline() {
1334 let constraints = InlineConstraintsLayout {
1335 first: PxRect::from_size(measure.first),
1336 mid_clear: Px(0),
1337 last: {
1338 let mut r = PxRect::from_size(measure.last);
1339 r.origin.y = bounds.measure_outer_size().height - measure.last.height;
1340 r
1341 },
1342 first_segs: Arc::new(vec![]),
1343 last_segs: Arc::new(vec![]),
1344 };
1345
1346 self.inline = Some(Default::default());
1347
1348 let metrics = LAYOUT
1349 .metrics()
1350 .with_inline_constraints(Some(InlineConstraints::Layout(constraints)));
1351 let size = LAYOUT.with_context(metrics, || layout(self));
1352
1353 bounds.set_inline(self.inline.clone());
1354 size
1355 } else {
1356 layout(self)
1357 }
1358 }
1359 }
1360
1361 pub fn with_inner(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1369 self.nest_group = LayoutNestGroup::Child;
1370 let size = BORDER.with_inner(|| layout(self));
1371 WIDGET.bounds().set_inner_size(size);
1372 self.nest_group = LayoutNestGroup::Inner;
1373 size
1374 }
1375
1376 pub fn with_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, bool) {
1386 let parent_needs_ref_count = mem::replace(&mut self.needs_ref_count, Some(0));
1387
1388 self.nest_group = LayoutNestGroup::Child;
1389 let child_size = layout(self);
1390 self.nest_group = LayoutNestGroup::Child;
1391
1392 let need_ref_frame = self.needs_ref_count != Some(1);
1393 self.needs_ref_count = parent_needs_ref_count;
1394 (child_size, need_ref_frame)
1395 }
1396
1397 pub fn require_child_ref_frame(&mut self) {
1404 if let Some(c) = &mut self.needs_ref_count {
1405 *c += 2;
1406 }
1407 }
1408
1409 pub fn with_branch_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, PxVector) {
1416 let parent_needs_ref_count = self.needs_ref_count;
1417 let parent_translate = self.bounds.child_offset();
1418 let parent_inner_offset_baseline = self.bounds.inner_offset_baseline();
1419 self.bounds.set_child_offset(PxVector::zero());
1420 let parent_group = self.nest_group;
1421
1422 self.nest_group = LayoutNestGroup::Child;
1423 let child_size = layout(self);
1424
1425 let translate = self.bounds.child_offset();
1426 self.bounds.set_child_offset(parent_translate);
1427 self.bounds.set_inner_offset_baseline(parent_inner_offset_baseline);
1428 self.nest_group = parent_group;
1429 self.needs_ref_count = parent_needs_ref_count;
1430
1431 (child_size, translate)
1432 }
1433
1434 pub fn translate(&mut self, offset: PxVector) {
1439 match self.nest_group {
1440 LayoutNestGroup::Inner => {
1441 let mut o = self.bounds.inner_offset();
1442 o += offset;
1443 self.bounds.set_inner_offset(o);
1444 }
1445 LayoutNestGroup::Child => {
1446 let mut o = self.bounds.child_offset();
1447 o += offset;
1448 self.bounds.set_child_offset(o);
1449 }
1450 }
1451 }
1452
1453 pub fn set_baseline(&mut self, baseline: Px) {
1455 self.bounds.set_baseline(baseline);
1456 }
1457
1458 pub fn translate_baseline(&mut self, enabled: bool) {
1460 self.bounds.set_inner_offset_baseline(enabled);
1461 }
1462
1463 pub fn set_transform_style(&mut self, style: TransformStyle) {
1465 self.bounds.set_transform_style(style);
1466 }
1467
1468 pub fn set_perspective(&mut self, d: f32) {
1472 self.bounds.set_perspective(d)
1473 }
1474
1475 pub fn set_perspective_origin(&mut self, origin: PxPoint) {
1477 self.bounds.set_perspective_origin(Some(origin))
1478 }
1479
1480 pub fn allow_auto_hide(&mut self, enabled: bool) {
1487 self.bounds.set_can_auto_hide(enabled);
1488 }
1489
1490 pub fn collapse(&mut self) {
1500 WIDGET.take_update(UpdateFlags::LAYOUT);
1501 let tree = WINDOW.info();
1502 let id = WIDGET.id();
1503 if let Some(w) = tree.get(id) {
1504 for w in w.self_and_descendants() {
1505 let info = w.info();
1506 info.bounds_info.set_outer_size(PxSize::zero());
1507 info.bounds_info.set_inner_size(PxSize::zero());
1508 info.bounds_info.set_baseline(Px(0));
1509 info.bounds_info.set_inner_offset_baseline(false);
1510 info.bounds_info.set_can_auto_hide(true);
1511 info.bounds_info.set_inner_offset(PxVector::zero());
1512 info.bounds_info.set_child_offset(PxVector::zero());
1513 info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1514 info.bounds_info.set_metrics(None, LayoutMask::empty());
1515 info.bounds_info.set_is_collapsed(true);
1516 info.bounds_info.set_rendered(None, &tree);
1517 }
1518 } else {
1519 tracing::error!("collapse did not find `{}` in the info tree", id)
1520 }
1521 }
1522
1523 pub fn collapse_descendants(&mut self) {
1532 let tree = WINDOW.info();
1533 let id = WIDGET.id();
1534 if let Some(w) = tree.get(id) {
1535 for w in w.descendants() {
1536 let info = w.info();
1537 info.bounds_info.set_outer_size(PxSize::zero());
1538 info.bounds_info.set_inner_size(PxSize::zero());
1539 info.bounds_info.set_baseline(Px(0));
1540 info.bounds_info.set_inner_offset_baseline(false);
1541 info.bounds_info.set_can_auto_hide(true);
1542 info.bounds_info.set_inner_offset(PxVector::zero());
1543 info.bounds_info.set_child_offset(PxVector::zero());
1544 info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1545 info.bounds_info.set_metrics(None, LayoutMask::empty());
1546 info.bounds_info.set_is_collapsed(true);
1547 }
1548 } else {
1549 tracing::error!("collapse_descendants did not find `{}` in the info tree", id)
1550 }
1551 }
1552
1553 pub fn collapse_child(&mut self, index: usize) {
1562 let tree = WINDOW.info();
1563 let id = WIDGET.id();
1564 if let Some(w) = tree.get(id) {
1565 if let Some(w) = w.children().nth(index) {
1566 for w in w.self_and_descendants() {
1567 let info = w.info();
1568 info.bounds_info.set_outer_size(PxSize::zero());
1569 info.bounds_info.set_inner_size(PxSize::zero());
1570 info.bounds_info.set_baseline(Px(0));
1571 info.bounds_info.set_inner_offset_baseline(false);
1572 info.bounds_info.set_can_auto_hide(true);
1573 info.bounds_info.set_inner_offset(PxVector::zero());
1574 info.bounds_info.set_child_offset(PxVector::zero());
1575 info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1576 info.bounds_info.set_metrics(None, LayoutMask::empty());
1577 info.bounds_info.set_is_collapsed(true);
1578 }
1579 } else {
1580 tracing::error!(
1581 "collapse_child out-of-bounds for `{}` in the children of `{}` in the info tree",
1582 index,
1583 id
1584 )
1585 }
1586 } else {
1587 tracing::error!("collapse_child did not find `{}` in the info tree", id)
1588 }
1589 }
1590
1591 pub fn is_inline(&self) -> bool {
1596 self.inline.is_some()
1597 }
1598
1599 pub fn inline(&mut self) -> Option<&mut WidgetInlineInfo> {
1614 self.inline.as_mut()
1615 }
1616
1617 pub fn to_measure(&self, inline: Option<WidgetInlineMeasure>) -> WidgetMeasure {
1621 WidgetMeasure {
1622 layout_widgets: self.layout_widgets.clone(),
1623 inline,
1624 inline_locked: false,
1625 }
1626 }
1627
1628 pub fn layout_block(&mut self, child: &mut impl UiNode) -> PxSize {
1633 LAYOUT.with_no_inline(|| child.layout(self))
1634 }
1635
1636 pub fn layout_inline(
1645 &mut self,
1646 first: PxRect,
1647 mid_clear: Px,
1648 last: PxRect,
1649 first_segs: Arc<Vec<InlineSegmentPos>>,
1650 last_segs: Arc<Vec<InlineSegmentPos>>,
1651 child: &mut impl UiNode,
1652 ) -> PxSize {
1653 let constraints = InlineConstraints::Layout(InlineConstraintsLayout {
1654 first,
1655 mid_clear,
1656 last,
1657 first_segs,
1658 last_segs,
1659 });
1660 let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1661 LAYOUT.with_context(metrics, || child.layout(self))
1662 }
1663
1664 pub fn with_layout_updates(&mut self, layout_updates: Arc<LayoutUpdates>, layout: impl FnOnce(&mut WidgetLayout) -> PxSize) -> PxSize {
1668 let parent_layout_widgets = mem::replace(&mut self.layout_widgets, layout_updates);
1669 let r = layout(self);
1670 self.layout_widgets = parent_layout_widgets;
1671 r
1672 }
1673}
1674
1675#[derive(Debug, Clone, Copy, PartialEq)]
1676enum LayoutNestGroup {
1677 Inner,
1679 Child,
1681}
1682
1683#[must_use = "use in parallel task, then move it to `B::parallel_fold`"]
1690pub struct ParallelBuilder<B>(pub(crate) Option<B>);
1691impl<B> ParallelBuilder<B> {
1692 pub(crate) fn take(&mut self) -> B {
1693 self.0.take().expect("parallel builder finished")
1694 }
1695}
1696impl<B> ops::Deref for ParallelBuilder<B> {
1697 type Target = B;
1698
1699 fn deref(&self) -> &Self::Target {
1700 self.0.as_ref().expect("parallel builder finished")
1701 }
1702}
1703impl<B> ops::DerefMut for ParallelBuilder<B> {
1704 fn deref_mut(&mut self) -> &mut Self::Target {
1705 self.0.as_mut().expect("parallel builder finished")
1706 }
1707}
1708impl<B> Drop for ParallelBuilder<B> {
1709 fn drop(&mut self) {
1710 if self.0.is_some() && !std::thread::panicking() {
1711 tracing::error!("builder dropped without calling `{}::parallel_fold`", std::any::type_name::<B>())
1712 }
1713 }
1714}