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)]
652#[non_exhaustive]
653pub struct WidgetInlineMeasure {
654 pub first: PxSize,
658
659 pub first_wrapped: bool,
661
662 pub first_segs: Arc<Vec<InlineSegment>>,
666
667 pub last: PxSize,
676
677 pub last_wrapped: bool,
679
680 pub last_segs: Arc<Vec<InlineSegment>>,
684}
685impl WidgetInlineMeasure {
686 pub fn with_first_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
691 Self::with_segs(&mut self.first_segs, f)
692 }
693
694 pub fn with_last_segs(&mut self, f: impl FnOnce(&mut Vec<InlineSegment>)) {
699 Self::with_segs(&mut self.last_segs, f)
700 }
701
702 fn with_segs(items: &mut Arc<Vec<InlineSegment>>, f: impl FnOnce(&mut Vec<InlineSegment>)) {
703 match Arc::get_mut(items) {
704 Some(items) => {
705 items.clear();
706 f(items);
707 }
708 None => {
709 let mut new = vec![];
710 f(&mut new);
711 *items = Arc::new(new);
712 }
713 }
714 }
715
716 pub fn is_default(&self) -> bool {
720 self.first.is_empty()
721 && !self.first_wrapped
722 && self.first_segs.is_empty()
723 && self.last.is_empty()
724 && !self.last_wrapped
725 && self.last_segs.is_empty()
726 }
727}
728
729#[derive(Clone, Copy, Debug, PartialEq, Eq)]
733#[non_exhaustive]
734pub struct InlineSegmentInfo {
735 pub x: Px,
737 pub width: Px,
741}
742
743impl InlineSegmentInfo {
744 pub fn new(x: Px, width: Px) -> Self {
746 Self { x, width }
747 }
748}
749
750#[derive(Debug, Default)]
752#[non_exhaustive]
753pub struct WidgetInlineInfo {
754 pub rows: Vec<PxRect>,
758
759 pub first_segs: Vec<InlineSegmentInfo>,
769
770 pub last_segs: Vec<InlineSegmentInfo>,
772
773 pub inner_size: PxSize,
775
776 negative_space: Mutex<(Arc<Vec<PxRect>>, bool)>,
777}
778impl WidgetInlineInfo {
779 pub fn set_first_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
787 Self::set_segs(&mut self.first_segs, segs);
788 self.invalidate_negative_space();
789 }
790
791 pub fn set_last_segs(&mut self, segs: impl Iterator<Item = InlineSegmentInfo>) {
799 Self::set_segs(&mut self.last_segs, segs);
800 self.invalidate_negative_space();
801 }
802
803 fn set_segs(vec: &mut Vec<InlineSegmentInfo>, segs: impl Iterator<Item = InlineSegmentInfo>) {
804 vec.clear();
805
806 let mut needs_sort = false;
807
808 for seg in segs {
809 if seg.width <= 0 {
810 continue;
811 }
812
813 if let Some(last) = vec.last_mut() {
814 let la = last.x;
815 let lb = last.x + last.width;
816
817 let a = seg.x;
818 let b = seg.x + seg.width;
819
820 if la.max(a) <= lb.min(b) {
821 last.x = a.min(la);
823 last.width = b.max(lb) - last.x;
824 continue;
825 }
826
827 needs_sort |= a < la;
828 }
829 vec.push(seg);
830 }
831
832 if needs_sort {
833 vec.sort_unstable_by_key(|s| s.x);
834 }
835 }
836
837 pub fn union(&self) -> PxRect {
839 self.rows.iter().fold(PxRect::zero(), |union, row| union.union(row))
840 }
841
842 pub fn negative_space(&self) -> Arc<Vec<PxRect>> {
850 let mut space = self.negative_space.lock();
851 if space.1 {
852 return space.0.clone();
853 }
854
855 let mut vec = Arc::try_unwrap(mem::take(&mut space.0)).unwrap_or_default();
856 vec.clear();
857
858 self.negative_enveloped(&mut vec, PxRect::from_size(self.inner_size));
859
860 let r = Arc::new(vec);
861 *space = (r.clone(), true);
862 r
863 }
864
865 pub fn invalidate_negative_space(&mut self) {
869 self.negative_space.get_mut().1 = false;
870 }
871
872 fn negative_enveloped(&self, space: &mut Vec<PxRect>, bounds: PxRect) {
873 let bounds_max_x = bounds.max_x();
874 let mut last_max_y = bounds.origin.y;
875
876 for r in &self.rows {
877 let spacing_y = r.origin.y - last_max_y;
878 if spacing_y > Px(0) {
879 space.push(PxRect::new(
880 PxPoint::new(bounds.origin.x, last_max_y),
881 PxSize::new(bounds.size.width, spacing_y),
882 ));
883 }
884 last_max_y = r.max_y();
885
886 let left = r.origin.x - bounds.origin.x;
887 if left > Px(0) {
888 space.push(PxRect::new(
889 PxPoint::new(bounds.origin.x, r.origin.y),
890 PxSize::new(left, r.size.height),
891 ));
892 }
893 let max_x = r.max_x();
894 let right = bounds_max_x - max_x;
895 if right > Px(0) {
896 space.push(PxRect::new(PxPoint::new(max_x, r.origin.y), PxSize::new(right, r.size.height)));
897 }
898 }
899 let spacing_y = bounds.max_y() - last_max_y;
900 if spacing_y > Px(0) {
901 space.push(PxRect::new(
902 PxPoint::new(bounds.origin.x, last_max_y),
903 PxSize::new(bounds.size.width, spacing_y),
904 ));
905 }
906
907 if let Some(r) = self.rows.first()
908 && !self.first_segs.is_empty()
909 {
910 let mut x = r.origin.x;
911 for seg in self.first_segs.iter() {
912 let blank = seg.x - x;
913 if blank > Px(0) {
914 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
915 }
916 x = seg.x + seg.width;
917 }
918 let blank = r.max_x() - x;
919 if blank > Px(0) {
920 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
921 }
922 }
923 if let Some(r) = self.rows.last()
924 && !self.last_segs.is_empty()
925 {
926 let mut x = r.origin.x;
927 for seg in self.last_segs.iter() {
928 let blank = seg.x - x;
929 if blank > Px(0) {
930 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
931 }
932 x = seg.x + seg.width;
933 }
934 let blank = r.max_x() - x;
935 if blank > Px(0) {
936 space.push(PxRect::new(PxPoint::new(x, r.origin.y), PxSize::new(blank, r.size.height)));
937 }
938 }
939 }
940
941 pub fn clear(&mut self) {
943 self.first_segs.clear();
944 self.last_segs.clear();
945 self.rows.clear();
946 self.inner_size = PxSize::zero();
947 self.invalidate_negative_space();
948 }
949
950 pub fn is_default(&self) -> bool {
954 self.rows.is_empty() && self.first_segs.is_empty() && self.last_segs.is_empty() && self.inner_size.is_empty()
955 }
956}
957impl Clone for WidgetInlineInfo {
958 fn clone(&self) -> Self {
959 Self {
960 rows: self.rows.clone(),
961 first_segs: self.first_segs.clone(),
962 last_segs: self.last_segs.clone(),
963 inner_size: self.inner_size,
964 negative_space: Mutex::new((Arc::new(vec![]), false)),
965 }
966 }
967
968 fn clone_from(&mut self, source: &Self) {
969 self.clear();
970 self.rows.extend_from_slice(&source.rows);
971 self.first_segs.extend_from_slice(&source.first_segs);
972 self.last_segs.extend_from_slice(&source.last_segs);
973 self.inner_size = source.inner_size;
974 }
975}
976impl PartialEq for WidgetInlineInfo {
977 fn eq(&self, other: &Self) -> bool {
978 self.rows == other.rows
979 && self.first_segs == other.first_segs
980 && self.last_segs == other.last_segs
981 && self.inner_size == other.inner_size
982 }
983}
984
985pub struct WidgetMeasure {
989 layout_widgets: Arc<LayoutUpdates>,
990 inline: Option<WidgetInlineMeasure>,
991 inline_locked: bool,
992}
993impl WidgetMeasure {
994 pub(crate) fn new(layout_widgets: Arc<LayoutUpdates>) -> Self {
995 Self {
996 layout_widgets,
997 inline: None,
998 inline_locked: false,
999 }
1000 }
1001
1002 pub fn new_reuse(inline: Option<WidgetInlineMeasure>) -> Self {
1006 let mut r = Self::new(Arc::default());
1007 r.inline = inline;
1008 r
1009 }
1010
1011 pub fn is_inline(&self) -> bool {
1013 self.inline.is_some()
1014 }
1015
1016 pub fn inline(&mut self) -> Option<&mut WidgetInlineMeasure> {
1022 self.inline.as_mut()
1023 }
1024
1025 pub fn disable_inline(&mut self) {
1038 if !self.inline_locked {
1039 self.inline = None;
1040 }
1041 }
1042
1043 pub fn measure_block(&mut self, child: &mut UiNode) -> PxSize {
1045 self.disable_inline();
1046 LAYOUT.with_no_inline(|| child.measure(self))
1047 }
1048
1049 pub fn measure_inline(&mut self, first_max: Px, mid_clear_min: Px, child: &mut UiNode) -> (Option<WidgetInlineMeasure>, PxSize) {
1062 let constraints = InlineConstraints::Measure(InlineConstraintsMeasure::new(first_max, mid_clear_min));
1063 let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1064 let size = LAYOUT.with_context(metrics, || child.measure(self));
1065 let inline = child
1066 .as_widget()
1067 .and_then(|mut w| w.with_context(WidgetUpdateMode::Ignore, || WIDGET.bounds().measure_inline()));
1068 (inline, size)
1069 }
1070
1071 pub fn with_widget(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1073 let metrics = LAYOUT.metrics();
1074 let bounds = WIDGET.bounds();
1075
1076 let snap = metrics.snapshot();
1077 if !WIDGET.layout_is_pending(&self.layout_widgets) {
1078 let measure_uses = bounds.measure_metrics_used();
1079 if bounds.measure_metrics().map(|m| m.masked_eq(&snap, measure_uses)).unwrap_or(false) {
1080 let mut reused = false;
1081 if let Some(inline) = self.inline() {
1082 if let Some(prev) = bounds.measure_inline() {
1083 *inline = prev;
1084 reused = true;
1085 }
1086 } else {
1087 reused = bounds.measure_inline().is_none();
1088 }
1089
1090 if reused {
1091 return bounds.measure_outer_size();
1093 }
1094 }
1095 }
1096
1097 let parent_inline = self.inline.take();
1098 if LAYOUT.inline_constraints().is_some() {
1099 self.inline = Some(Default::default());
1100 }
1101
1102 let (measure_uses, size) = LAYOUT.capture_metrics_use(|| measure(self));
1103
1104 bounds.set_measure_metrics(Some(snap), measure_uses);
1105 bounds.set_measure_outer_size(size);
1106
1107 if let Some(inline) = self.inline.take() {
1108 if inline.is_default() && !size.is_empty() {
1109 bounds.set_measure_inline(None);
1111 } else {
1112 #[cfg(debug_assertions)]
1113 if !inline.last_wrapped && inline.first != inline.last {
1114 tracing::error!(
1115 "widget {:?} invalid inline measure, last {:?} != first {:?} but last did not wrap",
1116 WIDGET.id(),
1117 inline.last,
1118 inline.first
1119 );
1120 }
1121
1122 bounds.set_measure_inline(Some(inline));
1123 }
1124 } else {
1125 bounds.set_measure_inline(None);
1126 }
1127 self.inline = parent_inline;
1128
1129 size
1130 }
1131
1132 pub fn with_inline_visual(&mut self, measure: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1139 self.inline_locked = true;
1140 if self.inline.is_none() {
1141 self.inline = Some(Default::default());
1142 }
1143 let metrics = LAYOUT.metrics();
1144 let size = if metrics.inline_constraints().is_none() {
1145 let constraints = InlineConstraints::Measure(InlineConstraintsMeasure::new(metrics.constraints().x.max_or(Px::MAX), Px(0)));
1146 let metrics = metrics.with_inline_constraints(Some(constraints));
1147 LAYOUT.with_context(metrics, || measure(self))
1148 } else {
1149 measure(self)
1150 };
1151 self.inline_locked = false;
1152
1153 let inline = self.inline.clone().unwrap();
1154 let bounds = WIDGET.bounds();
1155 if inline.is_default() && !size.is_empty() {
1156 bounds.set_measure_inline(None);
1158 } else {
1159 bounds.set_measure_inline(Some(inline));
1160 }
1161 bounds.set_measure_outer_size(size);
1162
1163 size
1164 }
1165
1166 pub fn parallel_split(&self) -> ParallelBuilder<WidgetMeasure> {
1173 ParallelBuilder(Some(Self {
1174 layout_widgets: self.layout_widgets.clone(),
1175 inline: self.inline.clone(),
1176 inline_locked: self.inline_locked,
1177 }))
1178 }
1179
1180 pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetMeasure>) {
1182 let _ = split.take();
1183 }
1184}
1185
1186pub struct WidgetLayout {
1188 layout_widgets: Arc<LayoutUpdates>,
1189 bounds: WidgetBoundsInfo,
1190 nest_group: LayoutNestGroup,
1191 inline: Option<WidgetInlineInfo>,
1192 needs_ref_count: Option<u32>,
1193}
1194impl WidgetLayout {
1195 pub fn with_root_widget(layout_widgets: Arc<LayoutUpdates>, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1199 Self {
1200 layout_widgets,
1201 bounds: WIDGET.bounds(),
1202 nest_group: LayoutNestGroup::Inner,
1203 inline: None,
1204 needs_ref_count: None,
1205 }
1206 .with_widget(layout)
1207 }
1208
1209 pub fn parallel_split(&self) -> ParallelBuilder<WidgetLayout> {
1219 if self.nest_group != LayoutNestGroup::Child && WIDGET.parent_id().is_some() {
1220 tracing::error!("called `parallel_split` outside child scope");
1221 }
1222 ParallelBuilder(Some(WidgetLayout {
1223 layout_widgets: self.layout_widgets.clone(),
1224 bounds: self.bounds.clone(),
1225 nest_group: LayoutNestGroup::Child,
1226 inline: None,
1227 needs_ref_count: None,
1228 }))
1229 }
1230
1231 pub fn parallel_fold(&mut self, mut split: ParallelBuilder<WidgetLayout>) {
1233 let folded = split.take();
1234 assert_eq!(self.bounds, folded.bounds);
1235
1236 let count = self.needs_ref_count.unwrap_or(0) + folded.needs_ref_count.unwrap_or(0);
1237 self.needs_ref_count = Some(count);
1238 }
1239
1240 pub fn with_widget(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1249 let metrics = LAYOUT.metrics();
1250 let bounds = WIDGET.bounds();
1251
1252 let snap = metrics.snapshot();
1253 if let Some(c) = &mut self.needs_ref_count {
1254 *c += 1;
1255 }
1256
1257 if !WIDGET.take_update(UpdateFlags::LAYOUT) && !self.layout_widgets.delivery_list().enter_widget(WIDGET.id()) {
1258 let uses = bounds.metrics_used();
1260 if bounds.metrics().map(|m| m.masked_eq(&snap, uses)).unwrap_or(false) {
1261 LAYOUT.register_metrics_use(uses); return bounds.outer_size();
1264 }
1265 }
1266
1267 let parent_needs_ref_count = self.needs_ref_count.take();
1268 let parent_inline = self.inline.take();
1269 if LAYOUT.inline_constraints().is_some() && bounds.measure_inline().is_some() {
1270 self.inline = bounds.take_inline();
1272 if let Some(inline) = self.inline.as_mut() {
1273 inline.clear();
1274 } else {
1275 self.inline = Some(Default::default());
1276 }
1277 }
1278 let parent_bounds = mem::replace(&mut self.bounds, bounds);
1279 self.nest_group = LayoutNestGroup::Inner;
1280 let prev_inner_offset = self.bounds.inner_offset();
1281 let prev_child_offset = self.bounds.child_offset();
1282 let prev_baseline = self.bounds.baseline();
1283 let prev_inner_offset_baseline = self.bounds.inner_offset_baseline();
1284 let prev_can_auto_hide = self.bounds.can_auto_hide();
1285 let prev_transform_style = self.bounds.transform_style();
1286 let prev_perspective = self.bounds.raw_perspective();
1287 let prev_perspective_origin = self.bounds.raw_perspective_origin();
1288 self.bounds.set_inner_offset(PxVector::zero());
1289 self.bounds.set_child_offset(PxVector::zero());
1290 self.bounds.set_baseline(Px(0));
1291 self.bounds.set_inner_offset_baseline(false);
1292 self.bounds.set_can_auto_hide(true);
1293 self.bounds.set_transform_style(TransformStyle::Flat);
1294 self.bounds.set_perspective(f32::INFINITY);
1295 self.bounds.set_perspective_origin(None);
1296
1297 let (uses, size) = LAYOUT.capture_metrics_use(|| layout(self));
1299
1300 LAYOUT.register_metrics_use(uses);
1301 self.bounds.set_outer_size(size);
1302 self.bounds.set_metrics(Some(snap), uses);
1303 if let Some(inline) = &mut self.inline {
1304 inline.inner_size = self.bounds.inner_size();
1305 inline.invalidate_negative_space();
1306 }
1307 self.bounds.set_inline(self.inline.take());
1308
1309 if prev_can_auto_hide != self.bounds.can_auto_hide() || prev_transform_style != self.bounds.transform_style() {
1310 WIDGET.render();
1311 } else if prev_inner_offset != self.bounds.inner_offset()
1312 || prev_child_offset != self.bounds.child_offset()
1313 || prev_inner_offset_baseline != self.bounds.inner_offset_baseline()
1314 || prev_perspective != self.bounds.raw_perspective()
1315 || prev_perspective_origin != self.bounds.raw_perspective_origin()
1316 || (self.bounds.inner_offset_baseline() && prev_baseline != self.bounds.baseline())
1317 {
1318 WIDGET.render_update();
1319 }
1320
1321 self.needs_ref_count = parent_needs_ref_count;
1322 self.inline = parent_inline;
1323 self.bounds = parent_bounds;
1324 self.nest_group = LayoutNestGroup::Child;
1325
1326 size
1327 }
1328
1329 pub fn with_inline_visual(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1334 if self.is_inline() {
1335 let size = layout(self);
1336 WIDGET.bounds().set_inline(self.inline.clone());
1337 size
1338 } else {
1339 let bounds = WIDGET.bounds();
1340 if let Some(measure) = bounds.measure_inline() {
1341 let constraints = InlineConstraintsLayout::new(
1342 PxRect::from_size(measure.first),
1343 Px(0),
1344 {
1345 let mut r = PxRect::from_size(measure.last);
1346 r.origin.y = bounds.measure_outer_size().height - measure.last.height;
1347 r
1348 },
1349 Arc::new(vec![]),
1350 Arc::new(vec![]),
1351 );
1352
1353 self.inline = Some(Default::default());
1354
1355 let metrics = LAYOUT
1356 .metrics()
1357 .with_inline_constraints(Some(InlineConstraints::Layout(constraints)));
1358 let size = LAYOUT.with_context(metrics, || layout(self));
1359
1360 bounds.set_inline(self.inline.clone());
1361 size
1362 } else {
1363 layout(self)
1364 }
1365 }
1366 }
1367
1368 pub fn with_inner(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> PxSize {
1376 self.nest_group = LayoutNestGroup::Child;
1377 let size = BORDER.with_inner(|| layout(self));
1378 WIDGET.bounds().set_inner_size(size);
1379 self.nest_group = LayoutNestGroup::Inner;
1380 size
1381 }
1382
1383 pub fn with_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, bool) {
1393 let parent_needs_ref_count = self.needs_ref_count.replace(0);
1394
1395 self.nest_group = LayoutNestGroup::Child;
1396 let child_size = layout(self);
1397 self.nest_group = LayoutNestGroup::Child;
1398
1399 let need_ref_frame = self.needs_ref_count != Some(1);
1400 self.needs_ref_count = parent_needs_ref_count;
1401 (child_size, need_ref_frame)
1402 }
1403
1404 pub fn require_child_ref_frame(&mut self) {
1411 if let Some(c) = &mut self.needs_ref_count {
1412 *c += 2;
1413 }
1414 }
1415
1416 pub fn with_branch_child(&mut self, layout: impl FnOnce(&mut Self) -> PxSize) -> (PxSize, PxVector) {
1423 let parent_needs_ref_count = self.needs_ref_count;
1424 let parent_translate = self.bounds.child_offset();
1425 let parent_inner_offset_baseline = self.bounds.inner_offset_baseline();
1426 self.bounds.set_child_offset(PxVector::zero());
1427 let parent_group = self.nest_group;
1428
1429 self.nest_group = LayoutNestGroup::Child;
1430 let child_size = layout(self);
1431
1432 let translate = self.bounds.child_offset();
1433 self.bounds.set_child_offset(parent_translate);
1434 self.bounds.set_inner_offset_baseline(parent_inner_offset_baseline);
1435 self.nest_group = parent_group;
1436 self.needs_ref_count = parent_needs_ref_count;
1437
1438 (child_size, translate)
1439 }
1440
1441 pub fn translate(&mut self, offset: PxVector) {
1446 match self.nest_group {
1447 LayoutNestGroup::Inner => {
1448 let mut o = self.bounds.inner_offset();
1449 o += offset;
1450 self.bounds.set_inner_offset(o);
1451 }
1452 LayoutNestGroup::Child => {
1453 let mut o = self.bounds.child_offset();
1454 o += offset;
1455 self.bounds.set_child_offset(o);
1456 }
1457 }
1458 }
1459
1460 pub fn set_baseline(&mut self, baseline: Px) {
1462 self.bounds.set_baseline(baseline);
1463 }
1464
1465 pub fn translate_baseline(&mut self, enabled: bool) {
1467 self.bounds.set_inner_offset_baseline(enabled);
1468 }
1469
1470 pub fn set_transform_style(&mut self, style: TransformStyle) {
1472 self.bounds.set_transform_style(style);
1473 }
1474
1475 pub fn set_perspective(&mut self, d: f32) {
1479 self.bounds.set_perspective(d)
1480 }
1481
1482 pub fn set_perspective_origin(&mut self, origin: PxPoint) {
1484 self.bounds.set_perspective_origin(Some(origin))
1485 }
1486
1487 pub fn allow_auto_hide(&mut self, enabled: bool) {
1494 self.bounds.set_can_auto_hide(enabled);
1495 }
1496
1497 pub fn collapse(&mut self) {
1507 WIDGET.take_update(UpdateFlags::LAYOUT);
1508 let tree = WINDOW.info();
1509 let id = WIDGET.id();
1510 if let Some(w) = tree.get(id) {
1511 for w in w.self_and_descendants() {
1512 let info = w.info();
1513 info.bounds_info.set_outer_size(PxSize::zero());
1514 info.bounds_info.set_inner_size(PxSize::zero());
1515 info.bounds_info.set_baseline(Px(0));
1516 info.bounds_info.set_inner_offset_baseline(false);
1517 info.bounds_info.set_can_auto_hide(true);
1518 info.bounds_info.set_inner_offset(PxVector::zero());
1519 info.bounds_info.set_child_offset(PxVector::zero());
1520 info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1521 info.bounds_info.set_metrics(None, LayoutMask::empty());
1522 info.bounds_info.set_is_collapsed(true);
1523 info.bounds_info.set_rendered(None, &tree);
1524 }
1525 } else {
1526 tracing::error!("collapse did not find `{}` in the info tree", id)
1527 }
1528 }
1529
1530 pub fn collapse_descendants(&mut self) {
1539 let tree = WINDOW.info();
1540 let id = WIDGET.id();
1541 if let Some(w) = tree.get(id) {
1542 for w in w.descendants() {
1543 let info = w.info();
1544 info.bounds_info.set_outer_size(PxSize::zero());
1545 info.bounds_info.set_inner_size(PxSize::zero());
1546 info.bounds_info.set_baseline(Px(0));
1547 info.bounds_info.set_inner_offset_baseline(false);
1548 info.bounds_info.set_can_auto_hide(true);
1549 info.bounds_info.set_inner_offset(PxVector::zero());
1550 info.bounds_info.set_child_offset(PxVector::zero());
1551 info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1552 info.bounds_info.set_metrics(None, LayoutMask::empty());
1553 info.bounds_info.set_is_collapsed(true);
1554 }
1555 } else {
1556 tracing::error!("collapse_descendants did not find `{}` in the info tree", id)
1557 }
1558 }
1559
1560 pub fn collapse_child(&mut self, index: usize) {
1569 let tree = WINDOW.info();
1570 let id = WIDGET.id();
1571 if let Some(w) = tree.get(id) {
1572 if let Some(w) = w.children().nth(index) {
1573 for w in w.self_and_descendants() {
1574 let info = w.info();
1575 info.bounds_info.set_outer_size(PxSize::zero());
1576 info.bounds_info.set_inner_size(PxSize::zero());
1577 info.bounds_info.set_baseline(Px(0));
1578 info.bounds_info.set_inner_offset_baseline(false);
1579 info.bounds_info.set_can_auto_hide(true);
1580 info.bounds_info.set_inner_offset(PxVector::zero());
1581 info.bounds_info.set_child_offset(PxVector::zero());
1582 info.bounds_info.set_measure_metrics(None, LayoutMask::empty());
1583 info.bounds_info.set_metrics(None, LayoutMask::empty());
1584 info.bounds_info.set_is_collapsed(true);
1585 }
1586 } else {
1587 tracing::error!(
1588 "collapse_child out-of-bounds for `{}` in the children of `{}` in the info tree",
1589 index,
1590 id
1591 )
1592 }
1593 } else {
1594 tracing::error!("collapse_child did not find `{}` in the info tree", id)
1595 }
1596 }
1597
1598 pub fn is_inline(&self) -> bool {
1603 self.inline.is_some()
1604 }
1605
1606 pub fn inline(&mut self) -> Option<&mut WidgetInlineInfo> {
1621 self.inline.as_mut()
1622 }
1623
1624 pub fn to_measure(&self, inline: Option<WidgetInlineMeasure>) -> WidgetMeasure {
1628 WidgetMeasure {
1629 layout_widgets: self.layout_widgets.clone(),
1630 inline,
1631 inline_locked: false,
1632 }
1633 }
1634
1635 pub fn layout_block(&mut self, child: &mut UiNode) -> PxSize {
1640 LAYOUT.with_no_inline(|| child.layout(self))
1641 }
1642
1643 pub fn layout_inline(
1652 &mut self,
1653 first: PxRect,
1654 mid_clear: Px,
1655 last: PxRect,
1656 first_segs: Arc<Vec<InlineSegmentPos>>,
1657 last_segs: Arc<Vec<InlineSegmentPos>>,
1658 child: &mut UiNode,
1659 ) -> PxSize {
1660 let constraints = InlineConstraints::Layout(InlineConstraintsLayout::new(first, mid_clear, last, first_segs, last_segs));
1661 let metrics = LAYOUT.metrics().with_inline_constraints(Some(constraints));
1662 LAYOUT.with_context(metrics, || child.layout(self))
1663 }
1664
1665 pub fn with_layout_updates(&mut self, layout_updates: Arc<LayoutUpdates>, layout: impl FnOnce(&mut WidgetLayout) -> PxSize) -> PxSize {
1669 let parent_layout_widgets = mem::replace(&mut self.layout_widgets, layout_updates);
1670 let r = layout(self);
1671 self.layout_widgets = parent_layout_widgets;
1672 r
1673 }
1674}
1675
1676#[derive(Debug, Clone, Copy, PartialEq)]
1677enum LayoutNestGroup {
1678 Inner,
1680 Child,
1682}
1683
1684#[must_use = "use in parallel task, then move it to `B::parallel_fold`"]
1691pub struct ParallelBuilder<B>(pub(crate) Option<B>);
1692impl<B> ParallelBuilder<B> {
1693 pub(crate) fn take(&mut self) -> B {
1694 self.0.take().expect("parallel builder finished")
1695 }
1696}
1697impl<B> ops::Deref for ParallelBuilder<B> {
1698 type Target = B;
1699
1700 fn deref(&self) -> &Self::Target {
1701 self.0.as_ref().expect("parallel builder finished")
1702 }
1703}
1704impl<B> ops::DerefMut for ParallelBuilder<B> {
1705 fn deref_mut(&mut self) -> &mut Self::Target {
1706 self.0.as_mut().expect("parallel builder finished")
1707 }
1708}
1709impl<B> Drop for ParallelBuilder<B> {
1710 fn drop(&mut self) {
1711 if self.0.is_some() && !std::thread::panicking() {
1712 tracing::error!("builder dropped without calling `{}::parallel_fold`", std::any::type_name::<B>())
1713 }
1714 }
1715}