sum_tree: Store context on cursor (#34904)

This gets rid of the need to pass context to all cursor functions. In
practice context is always immutable when interacting with cursors.

A nicety of this is in the follow-up PR we will be able to implement
Iterator for all Cursors/filter cursors (hell, we may be able to get rid
of filter cursor altogether, as it is just a custom `filter` impl on
iterator trait).
Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2025-07-22 18:20:48 +02:00 committed by GitHub
parent fa3e1ccc37
commit 64d0fec699
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 749 additions and 876 deletions

View file

@ -249,8 +249,8 @@ impl ListState {
let state = &mut *self.0.borrow_mut();
let mut old_items = state.items.cursor::<Count>(&());
let mut new_items = old_items.slice(&Count(old_range.start), Bias::Right, &());
old_items.seek_forward(&Count(old_range.end), Bias::Right, &());
let mut new_items = old_items.slice(&Count(old_range.start), Bias::Right);
old_items.seek_forward(&Count(old_range.end), Bias::Right);
let mut spliced_count = 0;
new_items.extend(
@ -260,7 +260,7 @@ impl ListState {
}),
&(),
);
new_items.append(old_items.suffix(&()), &());
new_items.append(old_items.suffix(), &());
drop(old_items);
state.items = new_items;
@ -300,14 +300,14 @@ impl ListState {
let current_offset = self.logical_scroll_top();
let state = &mut *self.0.borrow_mut();
let mut cursor = state.items.cursor::<ListItemSummary>(&());
cursor.seek(&Count(current_offset.item_ix), Bias::Right, &());
cursor.seek(&Count(current_offset.item_ix), Bias::Right);
let start_pixel_offset = cursor.start().height + current_offset.offset_in_item;
let new_pixel_offset = (start_pixel_offset + distance).max(px(0.));
if new_pixel_offset > start_pixel_offset {
cursor.seek_forward(&Height(new_pixel_offset), Bias::Right, &());
cursor.seek_forward(&Height(new_pixel_offset), Bias::Right);
} else {
cursor.seek(&Height(new_pixel_offset), Bias::Right, &());
cursor.seek(&Height(new_pixel_offset), Bias::Right);
}
state.logical_scroll_top = Some(ListOffset {
@ -343,11 +343,11 @@ impl ListState {
scroll_top.offset_in_item = px(0.);
} else {
let mut cursor = state.items.cursor::<ListItemSummary>(&());
cursor.seek(&Count(ix + 1), Bias::Right, &());
cursor.seek(&Count(ix + 1), Bias::Right);
let bottom = cursor.start().height + padding.top;
let goal_top = px(0.).max(bottom - height + padding.bottom);
cursor.seek(&Height(goal_top), Bias::Left, &());
cursor.seek(&Height(goal_top), Bias::Left);
let start_ix = cursor.start().count;
let start_item_top = cursor.start().height;
@ -372,11 +372,11 @@ impl ListState {
}
let mut cursor = state.items.cursor::<(Count, Height)>(&());
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
cursor.seek(&Count(scroll_top.item_ix), Bias::Right);
let scroll_top = cursor.start().1.0 + scroll_top.offset_in_item;
cursor.seek_forward(&Count(ix), Bias::Right, &());
cursor.seek_forward(&Count(ix), Bias::Right);
if let Some(&ListItem::Measured { size, .. }) = cursor.item() {
let &(Count(count), Height(top)) = cursor.start();
if count == ix {
@ -431,7 +431,7 @@ impl ListState {
let mut cursor = state.items.cursor::<ListItemSummary>(&());
let summary: ListItemSummary =
cursor.summary(&Count(logical_scroll_top.item_ix), Bias::Right, &());
cursor.summary(&Count(logical_scroll_top.item_ix), Bias::Right);
let content_height = state.items.summary().height;
let drag_offset =
// if dragging the scrollbar, we want to offset the point if the height changed
@ -450,9 +450,9 @@ impl ListState {
impl StateInner {
fn visible_range(&self, height: Pixels, scroll_top: &ListOffset) -> Range<usize> {
let mut cursor = self.items.cursor::<ListItemSummary>(&());
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
cursor.seek(&Count(scroll_top.item_ix), Bias::Right);
let start_y = cursor.start().height + scroll_top.offset_in_item;
cursor.seek_forward(&Height(start_y + height), Bias::Left, &());
cursor.seek_forward(&Height(start_y + height), Bias::Left);
scroll_top.item_ix..cursor.start().count + 1
}
@ -482,7 +482,7 @@ impl StateInner {
self.logical_scroll_top = None;
} else {
let mut cursor = self.items.cursor::<ListItemSummary>(&());
cursor.seek(&Height(new_scroll_top), Bias::Right, &());
cursor.seek(&Height(new_scroll_top), Bias::Right);
let item_ix = cursor.start().count;
let offset_in_item = new_scroll_top - cursor.start().height;
self.logical_scroll_top = Some(ListOffset {
@ -523,7 +523,7 @@ impl StateInner {
fn scroll_top(&self, logical_scroll_top: &ListOffset) -> Pixels {
let mut cursor = self.items.cursor::<ListItemSummary>(&());
cursor.seek(&Count(logical_scroll_top.item_ix), Bias::Right, &());
cursor.seek(&Count(logical_scroll_top.item_ix), Bias::Right);
cursor.start().height + logical_scroll_top.offset_in_item
}
@ -553,7 +553,7 @@ impl StateInner {
let mut cursor = old_items.cursor::<Count>(&());
// Render items after the scroll top, including those in the trailing overdraw
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
cursor.seek(&Count(scroll_top.item_ix), Bias::Right);
for (ix, item) in cursor.by_ref().enumerate() {
let visible_height = rendered_height - scroll_top.offset_in_item;
if visible_height >= available_height + self.overdraw {
@ -592,13 +592,13 @@ impl StateInner {
rendered_height += padding.bottom;
// Prepare to start walking upward from the item at the scroll top.
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
cursor.seek(&Count(scroll_top.item_ix), Bias::Right);
// If the rendered items do not fill the visible region, then adjust
// the scroll top upward.
if rendered_height - scroll_top.offset_in_item < available_height {
while rendered_height < available_height {
cursor.prev(&());
cursor.prev();
if let Some(item) = cursor.item() {
let item_index = cursor.start().0;
let mut element = (self.render_item)(item_index, window, cx);
@ -645,7 +645,7 @@ impl StateInner {
// Measure items in the leading overdraw
let mut leading_overdraw = scroll_top.offset_in_item;
while leading_overdraw < self.overdraw {
cursor.prev(&());
cursor.prev();
if let Some(item) = cursor.item() {
let size = if let ListItem::Measured { size, .. } = item {
*size
@ -666,10 +666,10 @@ impl StateInner {
let measured_range = cursor.start().0..(cursor.start().0 + measured_items.len());
let mut cursor = old_items.cursor::<Count>(&());
let mut new_items = cursor.slice(&Count(measured_range.start), Bias::Right, &());
let mut new_items = cursor.slice(&Count(measured_range.start), Bias::Right);
new_items.extend(measured_items, &());
cursor.seek(&Count(measured_range.end), Bias::Right, &());
new_items.append(cursor.suffix(&()), &());
cursor.seek(&Count(measured_range.end), Bias::Right);
new_items.append(cursor.suffix(), &());
self.items = new_items;
// If none of the visible items are focused, check if an off-screen item is focused
@ -679,7 +679,7 @@ impl StateInner {
let mut cursor = self
.items
.filter::<_, Count>(&(), |summary| summary.has_focus_handles);
cursor.next(&());
cursor.next();
while let Some(item) = cursor.item() {
if item.contains_focused(window, cx) {
let item_index = cursor.start().0;
@ -692,7 +692,7 @@ impl StateInner {
});
break;
}
cursor.next(&());
cursor.next();
}
}
@ -741,7 +741,7 @@ impl StateInner {
});
} else if autoscroll_bounds.bottom() > bounds.bottom() {
let mut cursor = self.items.cursor::<Count>(&());
cursor.seek(&Count(item.index), Bias::Right, &());
cursor.seek(&Count(item.index), Bias::Right);
let mut height = bounds.size.height - padding.top - padding.bottom;
// Account for the height of the element down until the autoscroll bottom.
@ -749,7 +749,7 @@ impl StateInner {
// Keep decreasing the scroll top until we fill all the available space.
while height > Pixels::ZERO {
cursor.prev(&());
cursor.prev();
let Some(item) = cursor.item() else { break };
let size = item.size().unwrap_or_else(|| {
@ -806,7 +806,7 @@ impl StateInner {
self.logical_scroll_top = None;
} else {
let mut cursor = self.items.cursor::<ListItemSummary>(&());
cursor.seek(&Height(new_scroll_top), Bias::Right, &());
cursor.seek(&Height(new_scroll_top), Bias::Right);
let item_ix = cursor.start().count;
let offset_in_item = new_scroll_top - cursor.start().height;