atagen

monolith

public
Star0
Watch0

Commit e2443dec4dcd

tarball

atagen <boss@atagen.co>2026-10-18 10:18 UTC

2 files changed+173-202
layout: keep window sizes on the windows

Sizes lived on container slots, so a row holding windows of other tags kept claiming their room and every move had to hand weight between slots. Carrying it into a lane of hidden windows made the moved window take that lane's whole size, and no rule for passing weight around kept both on-screen sizes and hidden windows' sizes stable. Each window now has its own width and height and a container asks for the mean of its visible children, so moves carry nothing and hidden windows change nothing on screen.
Modified file: crates/layout/src/tests.rs+11 additions−10 deletions
@@ -330,8 +330,7 @@ fn expand_skips_containers_of_hidden_windows() {
330330 assert_eq!(rect(b).w, AREA.w);
331331 }
332332
333-/// Joining a stack hands the window's weight to it and leaving hands it back,
334-/// so going in and out repeatedly leaves every window the size it was.
333+/// Going in and out of a stack repeatedly leaves every window the size it was.
335334 #[test]
336335 fn stacking_in_and_out_does_not_drift() {
337336 for out in [Dir::Up, Dir::Down, Dir::Right] {
@@ -352,8 +351,8 @@ fn stacking_in_and_out_does_not_drift() {
352351 }
353352 }
354353
355-/// Hidden windows in the rows around a window must not soak up its weight
356-/// as it passes through their lanes, or it shrinks on every round trip.
354+/// Windows of other tags in the rows around a window must not change what
355+/// the user sees as it moves through them, nor drift over round trips.
357356 #[test]
358357 fn moving_past_hidden_windows_does_not_drift() {
359358 let (a, b, h, h2) = (1, 2, 3, 4);
@@ -366,15 +365,17 @@ fn moving_past_hidden_windows_does_not_drift() {
366365 let once = t.arrange(AREA, 0.0, |_| true);
367366 for _ in 0..4 {
368367 for d in [Dir::Up, Dir::Up, Dir::Down] {
369- assert!(t.move_window(b, d, vis));
368+ t.move_window(b, d, vis);
369+ let shown = t.arrange(AREA, 0.0, vis);
370+ let r = shown.iter().find(|p| p.0 == b).unwrap().1;
371+ assert!(
372+ (r.w * r.h - AREA.w * AREA.h / 2.0).abs() < 1e-6,
373+ "{d:?} left {r:?}"
374+ );
370375 }
371376 t.check();
372377 }
373- let after = t.arrange(AREA, 0.0, |_| true);
374- for ((w, r), (v, s)) in once.iter().zip(&after) {
375- assert_eq!(w, v);
376- assert!((r.y - s.y).abs() < 1e-6 && (r.h - s.h).abs() < 1e-6, "{w}: {r:?} became {s:?}");
377- }
378+ assert_eq!(t.arrange(AREA, 0.0, |_| true), once);
378379 }
379380
380381 /// Monitors sleeping together unplug one after another, so windows already
Modified file: crates/layout/src/tree.rs+162 additions−192 deletions
@@ -20,6 +20,13 @@ impl Axis {
2020 Self::Vertical => Self::Horizontal,
2121 }
2222 }
23+
24+ fn index(self) -> usize {
25+ match self {
26+ Self::Horizontal => 0,
27+ Self::Vertical => 1,
28+ }
29+ }
2330 }
2431
2532 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -47,18 +54,15 @@ impl Dir {
4754
4855 const MIN_SHARE: f64 = 0.05;
4956
50-#[derive(Clone, Debug)]
51-struct Child {
52- node: NodeId,
53- weight: f64,
54-}
57+/// A window's width and height relative to its neighbours'.
58+type Size = [f64; 2];
5559
5660 #[derive(Clone, Debug)]
5761 enum Kind<W> {
58- Leaf(W),
62+ Leaf(W, Size),
5963 Container {
6064 axis: Axis,
61- children: Vec<Child>,
65+ children: Vec<NodeId>,
6266 expanded: Option<NodeId>,
6367 },
6468 }
@@ -118,43 +122,45 @@ impl<W: Copy + Eq + Hash> Tree<W> {
118122 let Some(&a) = self.leaves.get(&anchor) else {
119123 return self.insert_row(w);
120124 };
121- let n = self.new_leaf(w);
122125 match self.position(a) {
123126 Some((p, i)) if Some(p) == self.root && self.axis(p) == Some(self.stack) => {
124- let weight = self.unlink(p, i).weight;
127+ let n = self.new_leaf(w, self.size(a));
128+ self.unlink(p, i);
125129 let c = self.new_container(self.stack.other());
126- self.attach(c, 0, a, 1.0);
127- self.attach(c, 1, n, 1.0);
128- self.attach(p, i, c, weight);
130+ self.attach(c, 0, a);
131+ self.attach(c, 1, n);
132+ self.attach(p, i, c);
133+ self.reveal(n, true);
129134 }
130135 Some((p, i)) => {
131- let weight = self.mean_weight(p);
132- self.attach(p, i + 1, n, weight);
136+ let n = self.new_leaf(w, self.size(p));
137+ self.attach(p, i + 1, n);
138+ self.reveal(n, true);
133139 }
134140 None => {
141+ let n = self.new_leaf(w, self.size(a));
135142 let c = self.new_container(self.stack.other());
136- self.attach(c, 0, a, 1.0);
137- self.attach(c, 1, n, 1.0);
143+ self.attach(c, 0, a);
144+ self.attach(c, 1, n);
138145 self.root = Some(c);
139146 }
140147 }
141- self.reveal(n, true);
142148 }
143149
144150 /// Appends `w` as a row of its own along the stacking axis.
145151 pub fn insert_row(&mut self, w: W) {
146- let n = self.new_leaf(w);
152+ let size = self.root.map_or([1.0; 2], |r| self.size(r));
153+ let n = self.new_leaf(w, size);
147154 match self.root {
148155 None => self.root = Some(n),
149156 Some(r) if self.axis(r) == Some(self.stack) => {
150- let weight = self.mean_weight(r);
151157 let end = self.children(r).len();
152- self.attach(r, end, n, weight);
158+ self.attach(r, end, n);
153159 }
154160 Some(r) => {
155161 let c = self.new_container(self.stack);
156- self.attach(c, 0, r, 1.0);
157- self.attach(c, 1, n, 1.0);
162+ self.attach(c, 0, r);
163+ self.attach(c, 1, n);
158164 self.root = Some(c);
159165 }
160166 }
@@ -257,7 +263,7 @@ impl<W: Copy + Eq + Hash> Tree<W> {
257263 let shared = self
258264 .children(p)
259265 .iter()
260- .any(|c| c.node != cur && self.visible(c.node, vis));
266+ .any(|&c| c != cur && self.visible(c, vis));
261267 if shared {
262268 path.push((p, cur));
263269 }
@@ -270,8 +276,9 @@ impl<W: Copy + Eq + Hash> Tree<W> {
270276 pub fn flip(&mut self) {
271277 self.stack = self.stack.other();
272278 for node in self.nodes.values_mut() {
273- if let Kind::Container { axis, .. } = &mut node.kind {
274- *axis = axis.other();
279+ match &mut node.kind {
280+ Kind::Container { axis, .. } => *axis = axis.other(),
281+ Kind::Leaf(_, size) => size.reverse(),
275282 }
276283 }
277284 }
@@ -306,30 +313,28 @@ impl<W: Copy + Eq + Hash> Tree<W> {
306313
307314 /// Grows `w` by `delta`, a fraction of the visible length of the nearest
308315 /// container along `axis` where it has a visible sibling. Hidden siblings
309- /// keep their weights, and with them their share.
316+ /// keep their sizes, and with them their share.
310317 pub fn resize(&mut self, w: W, axis: Axis, delta: f64, vis: impl Fn(W) -> bool) -> bool {
311318 let Some(&leaf) = self.leaves.get(&w) else {
312319 return false;
313320 };
314321 let mut cur = leaf;
315- while let Some((p, i)) = self.position(cur) {
322+ while let Some(p) = self.nodes[cur].parent {
316323 if self.axis(p) == Some(axis) {
317- let shown: Vec<usize> = (0..self.children(p).len())
318- .filter(|&j| self.visible(self.children(p)[j].node, &vis))
324+ let shown: Vec<(NodeId, f64)> = self
325+ .children(p)
326+ .iter()
327+ .filter(|&&c| self.visible(c, &vis))
328+ .map(|&c| (c, self.extent(c, axis, &vis)))
319329 .collect();
320330 if shown.len() >= 2 {
321- let children = self.children_mut(p);
322- let sum: f64 = shown.iter().map(|&j| children[j].weight).sum();
323- let old = children[i].weight;
331+ let sum: f64 = shown.iter().map(|s| s.1).sum();
332+ let old = self.extent(cur, axis, &vis);
324333 let max = 1.0 - MIN_SHARE * (shown.len() - 1) as f64;
325334 let new = (old / sum + delta).clamp(MIN_SHARE, max) * sum;
326335 let scale = (sum - new) / (sum - old);
327- for j in shown {
328- children[j].weight = if j == i {
329- new
330- } else {
331- children[j].weight * scale
332- };
336+ for (c, _) in shown {
337+ self.scale(c, axis, if c == cur { new / old } else { scale });
333338 }
334339 return true;
335340 }
@@ -339,6 +344,55 @@ impl<W: Copy + Eq + Hash> Tree<W> {
339344 false
340345 }
341346
347+ /// Scales every window under `n` along `axis`, hidden ones too, so they
348+ /// keep their proportions for when they are shown again.
349+ fn scale(&mut self, n: NodeId, axis: Axis, by: f64) {
350+ match &mut self.nodes[n].kind {
351+ Kind::Leaf(_, size) => size[axis.index()] *= by,
352+ Kind::Container { children, .. } => {
353+ for c in children.clone() {
354+ self.scale(c, axis, by);
355+ }
356+ }
357+ }
358+ }
359+
360+ /// How much room `n` asks for along `axis` among its siblings. A
361+ /// container asks for the mean of what its visible children ask for, so
362+ /// windows of other tags sharing a lane change nothing on screen, and a
363+ /// window carries its own size wherever it moves.
364+ fn extent(&self, n: NodeId, axis: Axis, vis: &impl Fn(W) -> bool) -> f64 {
365+ match &self.nodes[n].kind {
366+ Kind::Leaf(_, size) => size[axis.index()],
367+ Kind::Container { children, .. } => {
368+ let shown: Vec<f64> = children
369+ .iter()
370+ .filter(|&&c| self.visible(c, vis))
371+ .map(|&c| self.extent(c, axis, vis))
372+ .collect();
373+ if shown.is_empty() {
374+ children
375+ .iter()
376+ .map(|&c| self.extent(c, axis, vis))
377+ .sum::<f64>()
378+ / children.len() as f64
379+ } else {
380+ shown.iter().sum::<f64>() / shown.len() as f64
381+ }
382+ }
383+ }
384+ }
385+
386+ /// The size a window placed in `n`'s stead would take, ignoring
387+ /// visibility since new windows land on any tag.
388+ fn size(&self, n: NodeId) -> Size {
389+ let all = |_: W| true;
390+ [
391+ self.extent(n, Axis::Horizontal, &all),
392+ self.extent(n, Axis::Vertical, &all),
393+ ]
394+ }
395+
342396 /// Lays the tree out in `area`. Hidden windows come back as zero-size
343397 /// rects on the boundary where they would reappear.
344398 pub fn arrange(&self, area: Rect, gap: f64, vis: impl Fn(W) -> bool) -> Vec<(W, Rect)> {
@@ -363,54 +417,54 @@ impl<W: Copy + Eq + Hash> Tree<W> {
363417 out: &mut Vec<(W, Rect)>,
364418 ) {
365419 let (axis, children, expanded) = match &self.nodes[n].kind {
366- Kind::Leaf(w) => return out.push((*w, r)),
420+ Kind::Leaf(w, _) => return out.push((*w, r)),
367421 Kind::Container {
368422 axis,
369423 children,
370424 expanded,
371425 } => (*axis, children, *expanded),
372426 };
373- let shown: Vec<bool> = children.iter().map(|c| self.visible(c.node, vis)).collect();
427+ let shown: Vec<bool> = children.iter().map(|&c| self.visible(c, vis)).collect();
374428 let (start, len) = span(r, axis);
375- if let Some(e) = expanded.and_then(|e| children.iter().position(|c| c.node == e))
429+ if let Some(e) = expanded.and_then(|e| children.iter().position(|&c| c == e))
376430 && shown[e]
377431 {
378- for (i, c) in children.iter().enumerate() {
432+ for (i, &c) in children.iter().enumerate() {
379433 let sub = match i.cmp(&e) {
380434 std::cmp::Ordering::Equal => r,
381435 std::cmp::Ordering::Less => with_span(r, axis, start, 0.0),
382436 std::cmp::Ordering::Greater => with_span(r, axis, start + len, 0.0),
383437 };
384- self.place(c.node, sub, gap, vis, out);
438+ self.place(c, sub, gap, vis, out);
385439 }
386440 return;
387441 }
388442 let count = shown.iter().filter(|s| **s).count();
389- let total: f64 = children
443+ let extents: Vec<f64> = children
390444 .iter()
391445 .zip(&shown)
392- .filter(|(_, s)| **s)
393- .map(|(c, _)| c.weight)
394- .sum();
446+ .map(|(&c, &s)| if s { self.extent(c, axis, vis) } else { 0.0 })
447+ .collect();
448+ let total: f64 = extents.iter().sum();
395449 let gaps = count.saturating_sub(1) as f64;
396450 let gap = if gaps > 0.0 { gap.min(len / gaps) } else { gap };
397451 let avail = len - gap * gaps;
398452 let last = shown.iter().rposition(|s| *s);
399453 let mut pos = start;
400454 let mut seen = false;
401- for (i, c) in children.iter().enumerate() {
455+ for (i, &c) in children.iter().enumerate() {
402456 if shown[i] {
403457 if seen {
404458 pos += gap;
405459 }
406- let l = avail * c.weight / total;
407- self.place(c.node, with_span(r, axis, pos, l), gap, vis, out);
460+ let l = avail * extents[i] / total;
461+ self.place(c, with_span(r, axis, pos, l), gap, vis, out);
408462 pos += l;
409463 seen = true;
410464 } else {
411465 let between = seen && last.is_some_and(|l| l > i);
412466 let at = if between { pos + gap / 2.0 } else { pos };
413- self.place(c.node, with_span(r, axis, at, 0.0), gap, vis, out);
467+ self.place(c, with_span(r, axis, at, 0.0), gap, vis, out);
414468 }
415469 }
416470 }
@@ -421,24 +475,23 @@ impl<W: Copy + Eq + Hash> Tree<W> {
421475 if self.axis(p) == Some(dir.axis()) {
422476 let hidden_lane = self
423477 .adjacent(p, i, dir)
424- .filter(|&j| enter && !self.visible(self.children(p)[j].node, vis));
478+ .filter(|&j| enter && !self.visible(self.children(p)[j], vis));
425479 if cur != n {
426480 if let Some(j) = hidden_lane {
427481 self.join_lane(n, p, j);
428482 } else {
429483 let at = if dir.forward() { i + 1 } else { i };
430- self.step_out(n, p, i, at);
484+ self.relocate(n, p, at);
431485 }
432486 return true;
433487 }
434488 if let Some(j) = self.next_shown(p, i, dir, vis) {
435- let sib = self.children(p)[j].node;
489+ let sib = self.children(p)[j];
436490 if enter && self.axis(sib).is_some() {
437491 self.join_lane(n, p, j);
438492 } else {
439493 let children = self.children_mut(p);
440- children[i].node = sib;
441- children[j].node = n;
494+ children.swap(i, j);
442495 }
443496 return true;
444497 }
@@ -453,27 +506,25 @@ impl<W: Copy + Eq + Hash> Tree<W> {
453506 return false;
454507 }
455508 let (old, i) = self.position(n).expect("n is below the root");
456- self.release_share(n);
457509 self.unlink(old, i);
458510 self.normalize(old);
459511 let r = self.root.expect("the rest of the tree survives");
460512 if self.axis(r) == Some(dir.axis()) {
461- let weight = self.mean_weight(r);
462513 let at = if dir.forward() {
463514 self.children(r).len()
464515 } else {
465516 0
466517 };
467- self.attach(r, at, n, weight);
518+ self.attach(r, at, n);
468519 } else {
469520 let c = self.new_container(dir.axis());
470- self.attach(c, 0, r, 1.0);
521+ self.attach(c, 0, r);
471522 let at = if dir.forward() {
472523 self.children(c).len()
473524 } else {
474525 0
475526 };
476- self.attach(c, at, n, 1.0);
527+ self.attach(c, at, n);
477528 self.root = Some(c);
478529 }
479530 true
@@ -482,9 +533,9 @@ impl<W: Copy + Eq + Hash> Tree<W> {
482533 fn next_shown(&self, p: NodeId, i: usize, dir: Dir, vis: &impl Fn(W) -> bool) -> Option<usize> {
483534 let children = self.children(p);
484535 if dir.forward() {
485- (i + 1..children.len()).find(|&j| self.visible(children[j].node, vis))
536+ (i + 1..children.len()).find(|&j| self.visible(children[j], vis))
486537 } else {
487- (0..i).rev().find(|&j| self.visible(children[j].node, vis))
538+ (0..i).rev().find(|&j| self.visible(children[j], vis))
488539 }
489540 }
490541
@@ -500,129 +551,52 @@ impl<W: Copy + Eq + Hash> Tree<W> {
500551 /// Moves `n` to the end of the lane at `p`'s child `j`. A lone window
501552 /// there becomes a lane of its own, perpendicular to `p`.
502553 fn join_lane(&mut self, n: NodeId, p: NodeId, j: usize) {
503- let lane = self.children(p)[j].node;
554+ let lane = self.children(p)[j];
504555 let lane = if self.axis(lane).is_some() {
505556 lane
506557 } else {
507558 let c = self.new_container(self.axis(p).expect("p is a container").other());
508- self.children_mut(p)[j].node = c;
559+ self.children_mut(p)[j] = c;
509560 self.nodes[c].parent = Some(p);
510561 if let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
511562 && *expanded == Some(lane)
512563 {
513564 *expanded = Some(c);
514565 }
515- self.attach(c, 0, lane, 1.0);
566+ self.attach(c, 0, lane);
516567 c
517568 };
518569 let end = self.children(lane).len();
519- let (old, i) = self.position(n).expect("n is below p");
520- let weight = if old == p {
521- Some(self.children(p)[i].weight)
522- } else if self.position(old).is_some_and(|(q, _)| q == p) {
523- self.release_share(n)
524- } else {
525- None
526- };
527- let inner = match weight {
528- Some(weight) => {
529- let k = self.position(lane).expect("lanes sit in p").1;
530- let total: f64 = self.children(lane).iter().map(|c| c.weight).sum();
531- total * weight / self.children(p)[k].weight
532- }
533- None => self.mean_weight(lane),
534- };
535- self.relocate_weighted(n, lane, end, inner);
536- if let Some(weight) = weight
537- && self.nodes.contains_key(lane)
538- && let Some((q, k)) = self.position(lane)
539- && q == p
540- {
541- self.children_mut(p)[k].weight += weight;
542- }
543- }
544-
545- /// Moves `n` out of `p`'s child `i` to sit beside it at `at`, taking
546- /// along the share of that child's weight it had.
547- fn step_out(&mut self, n: NodeId, p: NodeId, i: usize, at: usize) {
548- let cur = self.children(p)[i].node;
549- let Some((parent, k)) = self.position(n).filter(|&(q, _)| q == cur) else {
550- self.relocate(n, p, at);
551- return;
552- };
553- let share = self.release_share(n).unwrap_or_else(|| self.mean_weight(p));
554- self.unlink(parent, k);
555- self.attach(p, at, n, share);
556- self.normalize(parent);
557- }
558-
559- /// Takes `n`'s share of its container's weight away from the container,
560- /// for `n` to carry out. Joining a lane hands a window's weight to the
561- /// lane, so leaving gives it back and windows going in and out of
562- /// stacks do not shrink their neighbours a little more each time.
563- fn release_share(&mut self, n: NodeId) -> Option<f64> {
564- let (old, i) = self.position(n)?;
565- let (q, k) = self.position(old)?;
566- let total: f64 = self.children(old).iter().map(|c| c.weight).sum();
567- let share = self.children(q)[k].weight * self.children(old)[i].weight / total;
568- self.children_mut(q)[k].weight -= share;
569- Some(share)
570+ self.relocate(n, lane, end);
570571 }
571572
572573 fn relocate(&mut self, n: NodeId, p: NodeId, at: usize) {
573- self.relocate_weighted(n, p, at, self.mean_weight(p));
574- }
575-
576- fn relocate_weighted(&mut self, n: NodeId, p: NodeId, at: usize, weight: f64) {
577574 let (old, i) = self.position(n).expect("relocated nodes have a parent");
578575 let at = if old == p && i < at { at - 1 } else { at };
579576 self.unlink(old, i);
580- self.attach(p, at, n, weight);
577+ self.attach(p, at, n);
581578 self.normalize(old);
582579 }
583580
584581 /// Places `node` among `p`'s children. A container running along `p`'s
585582 /// axis is dissolved into `p` so axes keep alternating.
586- fn attach(&mut self, p: NodeId, at: usize, node: NodeId, weight: f64) {
587- if self.axis(node) == self.axis(p) {
588- let Some(Node {
589- kind: Kind::Container { children, .. },
590- ..
591- }) = self.nodes.remove(node)
592- else {
593- unreachable!("only containers have an axis");
594- };
595- let total: f64 = children.iter().map(|c| c.weight).sum();
596- for (k, c) in children.into_iter().enumerate() {
597- self.nodes[c.node].parent = Some(p);
598- let weight = weight * c.weight / total;
599- self.children_mut(p).insert(
600- at + k,
601- Child {
602- node: c.node,
603- weight,
604- },
605- );
583+ fn attach(&mut self, p: NodeId, at: usize, node: NodeId) {
584+ if self.axis(node).is_some() && self.axis(node) == self.axis(p) {
585+ let children = self.children(node).to_vec();
586+ self.nodes.remove(node);
587+ for (k, &c) in children.iter().enumerate() {
588+ self.nodes[c].parent = Some(p);
589+ self.children_mut(p).insert(at + k, c);
606590 }
607591 } else {
608592 self.nodes[node].parent = Some(p);
609- self.children_mut(p).insert(at, Child { node, weight });
593+ self.children_mut(p).insert(at, node);
610594 }
611595 }
612596
613- fn unlink(&mut self, p: NodeId, i: usize) -> Child {
614- let Kind::Container {
615- children, expanded, ..
616- } = &mut self.nodes[p].kind
617- else {
618- unreachable!("parents are containers");
619- };
620- let child = children.remove(i);
621- if *expanded == Some(child.node) {
622- *expanded = None;
623- }
624- self.nodes[child.node].parent = None;
625- child
597+ fn unlink(&mut self, p: NodeId, i: usize) {
598+ let child = self.unlink_dead(p, i);
599+ self.nodes[child].parent = None;
626600 }
627601
628602 fn detach(&mut self, n: NodeId) {
@@ -657,25 +631,25 @@ impl<W: Copy + Eq + Hash> Tree<W> {
657631 }
658632 (None, None) => self.root = None,
659633 (Some(only), Some((p, i))) => {
660- let weight = self.unlink_dead(p, i).weight;
661- let leaf_like = self.axis(only.node) != self.axis(p);
662- self.attach(p, i, only.node, weight);
634+ self.unlink_dead(p, i);
635+ let leaf_like = self.axis(only) != self.axis(p);
636+ self.attach(p, i, only);
663637 if was_expanded
664638 && leaf_like
665639 && let Kind::Container { expanded, .. } = &mut self.nodes[p].kind
666640 {
667- *expanded = Some(only.node);
641+ *expanded = Some(only);
668642 }
669643 }
670644 (Some(only), None) => {
671- self.nodes[only.node].parent = None;
672- self.root = Some(only.node);
645+ self.nodes[only].parent = None;
646+ self.root = Some(only);
673647 }
674648 }
675649 }
676650
677651 /// Like `unlink`, for a child whose node is already gone.
678- fn unlink_dead(&mut self, p: NodeId, i: usize) -> Child {
652+ fn unlink_dead(&mut self, p: NodeId, i: usize) -> NodeId {
679653 let Kind::Container {
680654 children, expanded, ..
681655 } = &mut self.nodes[p].kind
@@ -683,16 +657,16 @@ impl<W: Copy + Eq + Hash> Tree<W> {
683657 unreachable!("parents are containers");
684658 };
685659 let child = children.remove(i);
686- if *expanded == Some(child.node) {
660+ if *expanded == Some(child) {
687661 *expanded = None;
688662 }
689663 child
690664 }
691665
692- fn new_leaf(&mut self, w: W) -> NodeId {
666+ fn new_leaf(&mut self, w: W, size: Size) -> NodeId {
693667 let n = self.nodes.insert(Node {
694668 parent: None,
695- kind: Kind::Leaf(w),
669+ kind: Kind::Leaf(w, size),
696670 });
697671 self.leaves.insert(w, n);
698672 n
@@ -711,51 +685,42 @@ impl<W: Copy + Eq + Hash> Tree<W> {
711685
712686 fn position(&self, n: NodeId) -> Option<(NodeId, usize)> {
713687 let p = self.nodes[n].parent?;
714- let i = self.children(p).iter().position(|c| c.node == n)?;
688+ let i = self.children(p).iter().position(|&c| c == n)?;
715689 Some((p, i))
716690 }
717691
718692 fn axis(&self, n: NodeId) -> Option<Axis> {
719693 match &self.nodes[n].kind {
720694 Kind::Container { axis, .. } => Some(*axis),
721- Kind::Leaf(_) => None,
695+ Kind::Leaf(..) => None,
722696 }
723697 }
724698
725699 fn expanded(&self, n: NodeId) -> Option<NodeId> {
726700 match &self.nodes[n].kind {
727701 Kind::Container { expanded, .. } => *expanded,
728- Kind::Leaf(_) => None,
702+ Kind::Leaf(..) => None,
729703 }
730704 }
731705
732- fn children(&self, n: NodeId) -> &[Child] {
706+ fn children(&self, n: NodeId) -> &[NodeId] {
733707 match &self.nodes[n].kind {
734708 Kind::Container { children, .. } => children,
735- Kind::Leaf(_) => &[],
709+ Kind::Leaf(..) => &[],
736710 }
737711 }
738712
739- fn children_mut(&mut self, n: NodeId) -> &mut Vec<Child> {
713+ fn children_mut(&mut self, n: NodeId) -> &mut Vec<NodeId> {
740714 match &mut self.nodes[n].kind {
741715 Kind::Container { children, .. } => children,
742- Kind::Leaf(_) => unreachable!("leaves have no children"),
743- }
744- }
745-
746- fn mean_weight(&self, p: NodeId) -> f64 {
747- let children = self.children(p);
748- if children.is_empty() {
749- 1.0
750- } else {
751- children.iter().map(|c| c.weight).sum::<f64>() / children.len() as f64
716+ Kind::Leaf(..) => unreachable!("leaves have no children"),
752717 }
753718 }
754719
755720 fn visible(&self, n: NodeId, vis: &impl Fn(W) -> bool) -> bool {
756721 match &self.nodes[n].kind {
757- Kind::Leaf(w) => vis(*w),
758- Kind::Container { children, .. } => children.iter().any(|c| self.visible(c.node, vis)),
722+ Kind::Leaf(w, _) => vis(*w),
723+ Kind::Container { children, .. } => children.iter().any(|&c| self.visible(c, vis)),
759724 }
760725 }
761726
@@ -770,14 +735,20 @@ impl<W: Copy + Eq + Hash> Tree<W> {
770735 };
771736 assert_eq!(reachable, self.nodes.len(), "orphaned nodes");
772737 for (&w, &n) in &self.leaves {
773- assert!(matches!(self.nodes[n].kind, Kind::Leaf(x) if x == w));
738+ assert!(matches!(self.nodes[n].kind, Kind::Leaf(x, _) if x == w));
774739 }
775740 }
776741
777742 #[cfg(test)]
778743 fn check_node(&self, n: NodeId) -> usize {
779744 match &self.nodes[n].kind {
780- Kind::Leaf(_) => 1,
745+ Kind::Leaf(_, size) => {
746+ assert!(
747+ size.iter().all(|s| *s > 0.0 && s.is_finite()),
748+ "size {size:?}"
749+ );
750+ 1
751+ }
781752 Kind::Container {
782753 axis,
783754 children,
@@ -789,14 +760,13 @@ impl<W: Copy + Eq + Hash> Tree<W> {
789760 children.len()
790761 );
791762 if let Some(e) = expanded {
792- assert!(children.iter().any(|c| c.node == *e));
763+ assert!(children.contains(e));
793764 }
794765 let mut count = 1;
795- for c in children {
796- assert!(c.weight > 0.0 && c.weight.is_finite());
797- assert_eq!(self.nodes[c.node].parent, Some(n));
798- assert_ne!(self.axis(c.node), Some(*axis), "axes must alternate");
799- count += self.check_node(c.node);
766+ for &c in children {
767+ assert_eq!(self.nodes[c].parent, Some(n));
768+ assert_ne!(self.axis(c), Some(*axis), "axes must alternate");
769+ count += self.check_node(c);
800770 }
801771 count
802772 }