From 497ebcd0c36c45d6203fc84005abb81f95cf34ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 20 Aug 2025 23:14:23 +0200 Subject: [PATCH] Make `Widget::diff` mutable --- core/src/element.rs | 37 ++++++++++++++++++++++++++++--- core/src/widget.rs | 2 +- core/src/widget/tree.rs | 26 ++++++++++++---------- examples/loupe/src/main.rs | 4 ++-- examples/toast/src/main.rs | 6 ++--- runtime/src/user_interface.rs | 2 +- widget/src/button.rs | 4 ++-- widget/src/column.rs | 4 ++-- widget/src/combo_box.rs | 2 +- widget/src/container.rs | 4 ++-- widget/src/float.rs | 4 ++-- widget/src/grid.rs | 4 ++-- widget/src/helpers.rs | 8 +++---- widget/src/keyed/column.rs | 6 ++--- widget/src/lazy.rs | 6 ++--- widget/src/lazy/component.rs | 6 ++--- widget/src/lazy/responsive.rs | 2 +- widget/src/mouse_area.rs | 4 ++-- widget/src/overlay/menu.rs | 4 ++-- widget/src/pane_grid.rs | 4 ++-- widget/src/pane_grid/content.rs | 6 ++--- widget/src/pane_grid/title_bar.rs | 10 ++++----- widget/src/pin.rs | 4 ++-- widget/src/row.rs | 6 ++--- widget/src/scrollable.rs | 4 ++-- widget/src/sensor.rs | 4 ++-- widget/src/stack.rs | 4 ++-- widget/src/table.rs | 4 ++-- widget/src/text_input.rs | 2 +- widget/src/themer.rs | 4 ++-- widget/src/tooltip.rs | 8 +++---- 31 files changed, 114 insertions(+), 81 deletions(-) diff --git a/core/src/element.rs b/core/src/element.rs index 6a71296c..349aecb6 100644 --- a/core/src/element.rs +++ b/core/src/element.rs @@ -9,7 +9,7 @@ use crate::{ Vector, Widget, }; -use std::borrow::Borrow; +use std::borrow::{Borrow, BorrowMut}; /// A generic [`Widget`]. /// @@ -239,6 +239,37 @@ impl<'a, Message, Theme, Renderer> } } +impl<'a, Message, Theme, Renderer> + Borrow + 'a> + for &mut Element<'a, Message, Theme, Renderer> +{ + fn borrow(&self) -> &(dyn Widget + 'a) { + self.widget.borrow() + } +} + +impl<'a, Message, Theme, Renderer> + BorrowMut + 'a> + for Element<'a, Message, Theme, Renderer> +{ + fn borrow_mut( + &mut self, + ) -> &mut (dyn Widget + 'a) { + self.widget.borrow_mut() + } +} + +impl<'a, Message, Theme, Renderer> + BorrowMut + 'a> + for &mut Element<'a, Message, Theme, Renderer> +{ + fn borrow_mut( + &mut self, + ) -> &mut (dyn Widget + 'a) { + self.widget.borrow_mut() + } +} + struct Map<'a, A, B, Theme, Renderer> { widget: Box + 'a>, mapper: Box B + 'a>, @@ -278,7 +309,7 @@ where self.widget.children() } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { self.widget.diff(tree); } @@ -421,7 +452,7 @@ where self.element.widget.children() } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { self.element.widget.diff(tree); } diff --git a/core/src/widget.rs b/core/src/widget.rs index 3b39ffcc..9316dba1 100644 --- a/core/src/widget.rs +++ b/core/src/widget.rs @@ -96,7 +96,7 @@ where } /// Reconciles the [`Widget`] with the provided [`Tree`]. - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { tree.children.clear(); } diff --git a/core/src/widget/tree.rs b/core/src/widget/tree.rs index 2600cfc6..20b55360 100644 --- a/core/src/widget/tree.rs +++ b/core/src/widget/tree.rs @@ -2,7 +2,7 @@ use crate::Widget; use std::any::{self, Any}; -use std::borrow::Borrow; +use std::borrow::{Borrow, BorrowMut}; use std::fmt; /// A persistent state widget tree. @@ -56,12 +56,12 @@ impl Tree { /// [`Widget::diff`]: crate::Widget::diff pub fn diff<'a, Message, Theme, Renderer>( &mut self, - new: impl Borrow + 'a>, + mut new: impl BorrowMut + 'a>, ) where Renderer: crate::Renderer, { - if self.tag == new.borrow().tag() { - new.borrow().diff(self); + if self.tag == new.borrow_mut().tag() { + new.borrow_mut().diff(self); } else { *self = Self::new(new); } @@ -70,13 +70,15 @@ impl Tree { /// Reconciles the children of the tree with the provided list of widgets. pub fn diff_children<'a, Message, Theme, Renderer>( &mut self, - new_children: &[impl Borrow + 'a>], + new_children: &mut [impl BorrowMut< + dyn Widget + 'a, + >], ) where Renderer: crate::Renderer, { self.diff_children_custom( new_children, - |tree, widget| tree.diff(widget.borrow()), + |tree, widget| tree.diff(widget.borrow_mut()), |widget| Self::new(widget.borrow()), ); } @@ -85,8 +87,8 @@ impl Tree { /// logic both for diffing and creating new widget state. pub fn diff_children_custom( &mut self, - new_children: &[T], - diff: impl Fn(&mut Tree, &T), + new_children: &mut [T], + diff: impl Fn(&mut Tree, &mut T), new_state: impl Fn(&T) -> Self, ) { if self.children.len() > new_children.len() { @@ -94,7 +96,7 @@ impl Tree { } for (child_state, new) in - self.children.iter_mut().zip(new_children.iter()) + self.children.iter_mut().zip(new_children.iter_mut()) { diff(child_state, new); } @@ -114,8 +116,8 @@ impl Tree { /// `maybe_changed` closure. pub fn diff_children_custom_with_search( current_children: &mut Vec, - new_children: &[T], - diff: impl Fn(&mut Tree, &T), + new_children: &mut [T], + diff: impl Fn(&mut Tree, &mut T), maybe_changed: impl Fn(usize) -> bool, new_state: impl Fn(&T) -> Tree, ) { @@ -183,7 +185,7 @@ pub fn diff_children_custom_with_search( // TODO: Merge loop with extend logic (?) for (child_state, new) in - current_children.iter_mut().zip(new_children.iter()) + current_children.iter_mut().zip(new_children.iter_mut()) { diff(child_state, new); } diff --git a/examples/loupe/src/main.rs b/examples/loupe/src/main.rs index 89bc82da..ebd7a44f 100644 --- a/examples/loupe/src/main.rs +++ b/examples/loupe/src/main.rs @@ -87,8 +87,8 @@ mod loupe { self.content.as_widget().children() } - fn diff(&self, tree: &mut widget::Tree) { - self.content.as_widget().diff(tree); + fn diff(&mut self, tree: &mut widget::Tree) { + self.content.as_widget_mut().diff(tree); } fn size(&self) -> Size { diff --git a/examples/toast/src/main.rs b/examples/toast/src/main.rs index dc8c2593..d1be0c09 100644 --- a/examples/toast/src/main.rs +++ b/examples/toast/src/main.rs @@ -314,7 +314,7 @@ mod toast { .collect() } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { let instants = tree.state.downcast_mut::>>(); // Invalidating removed instants to None allows us to remove @@ -336,8 +336,8 @@ mod toast { } tree.diff_children( - &std::iter::once(&self.content) - .chain(self.toasts.iter()) + &mut std::iter::once(&mut self.content) + .chain(self.toasts.iter_mut()) .collect::>(), ); } diff --git a/runtime/src/user_interface.rs b/runtime/src/user_interface.rs index 26c96201..6e32d10f 100644 --- a/runtime/src/user_interface.rs +++ b/runtime/src/user_interface.rs @@ -100,7 +100,7 @@ where let mut root = root.into(); let Cache { mut state } = cache; - state.diff(root.as_widget()); + state.diff(root.as_widget_mut()); let base = root.as_widget_mut().layout( &mut state, diff --git a/widget/src/button.rs b/widget/src/button.rs index 6ae8d3e5..2ae1508b 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -223,8 +223,8 @@ where vec![Tree::new(&self.content)] } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(std::slice::from_ref(&self.content)); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(std::slice::from_mut(&mut self.content)); } fn size(&self) -> Size { diff --git a/widget/src/column.rs b/widget/src/column.rs index 39507a78..bcbbe49e 100644 --- a/widget/src/column.rs +++ b/widget/src/column.rs @@ -194,8 +194,8 @@ where self.children.iter().map(Tree::new).collect() } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(&self.children); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(&mut self.children); } fn size(&self) -> Size { diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs index f94705d8..86533c3a 100644 --- a/widget/src/combo_box.rs +++ b/widget/src/combo_box.rs @@ -509,7 +509,7 @@ where vec![widget::Tree::new(&self.text_input as &dyn Widget<_, _, _>)] } - fn diff(&self, _tree: &mut widget::Tree) { + fn diff(&mut self, _tree: &mut widget::Tree) { // do nothing so the children don't get cleared } diff --git a/widget/src/container.rs b/widget/src/container.rs index 286c5a63..97502b17 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -247,8 +247,8 @@ where self.content.as_widget().children() } - fn diff(&self, tree: &mut Tree) { - self.content.as_widget().diff(tree); + fn diff(&mut self, tree: &mut Tree) { + self.content.as_widget_mut().diff(tree); } fn size(&self) -> Size { diff --git a/widget/src/float.rs b/widget/src/float.rs index 1ff6ab10..a7eaf5bb 100644 --- a/widget/src/float.rs +++ b/widget/src/float.rs @@ -103,8 +103,8 @@ where self.content.as_widget().children() } - fn diff(&self, tree: &mut widget::Tree) { - self.content.as_widget().diff(tree); + fn diff(&mut self, tree: &mut widget::Tree) { + self.content.as_widget_mut().diff(tree); } fn size(&self) -> Size { diff --git a/widget/src/grid.rs b/widget/src/grid.rs index 25e3ebe0..5bf2bf6b 100644 --- a/widget/src/grid.rs +++ b/widget/src/grid.rs @@ -158,8 +158,8 @@ where self.children.iter().map(Tree::new).collect() } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(&self.children); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(&mut self.children); } fn size(&self) -> Size { diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 9e01fa99..a926d2ef 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -596,8 +596,8 @@ where self.content.as_widget().children() } - fn diff(&self, tree: &mut Tree) { - self.content.as_widget().diff(tree); + fn diff(&mut self, tree: &mut Tree) { + self.content.as_widget_mut().diff(tree); } fn size(&self) -> Size { @@ -759,8 +759,8 @@ where vec![Tree::new(&self.base), Tree::new(&self.top)] } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(&[&self.base, &self.top]); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(&mut [&mut self.base, &mut self.top]); } fn size(&self) -> Size { diff --git a/widget/src/keyed/column.rs b/widget/src/keyed/column.rs index 6ca6f485..907ae479 100644 --- a/widget/src/keyed/column.rs +++ b/widget/src/keyed/column.rs @@ -222,7 +222,7 @@ where self.children.iter().map(Tree::new).collect() } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { let Tree { state, children, .. } = tree; @@ -231,8 +231,8 @@ where tree::diff_children_custom_with_search( children, - &self.children, - |tree, child| child.as_widget().diff(tree), + &mut self.children, + |tree, child| child.as_widget_mut().diff(tree), |index| { self.keys.get(index).or_else(|| self.keys.last()).copied() != Some(state.keys[index]) diff --git a/widget/src/lazy.rs b/widget/src/lazy.rs index 0d56269b..36edce79 100644 --- a/widget/src/lazy.rs +++ b/widget/src/lazy.rs @@ -127,7 +127,7 @@ where self.with_element(|element| vec![Tree::new(element.as_widget())]) } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { let current = tree .state .downcast_mut::>(); @@ -146,8 +146,8 @@ where current.element = Rc::new(RefCell::new(Some(element))); (*self.element.borrow_mut()) = Some(current.element.clone()); - self.with_element(|element| { - tree.diff_children(std::slice::from_ref(&element.as_widget())); + self.with_element_mut(|element| { + tree.diff_children(std::slice::from_mut(element)); }); } else { (*self.element.borrow_mut()) = Some(current.element.clone()); diff --git a/widget/src/lazy/component.rs b/widget/src/lazy/component.rs index 1b582dee..c40be4d1 100644 --- a/widget/src/lazy/component.rs +++ b/widget/src/lazy/component.rs @@ -147,13 +147,13 @@ where Renderer: renderer::Renderer, { fn diff_self(&self) { - self.with_element(|element| { + self.with_element_mut(|element| { self.tree .borrow_mut() .borrow_mut() .as_mut() .unwrap() - .diff_children(std::slice::from_ref(&element)); + .diff_children(std::slice::from_mut(element)); }); } @@ -279,7 +279,7 @@ where vec![] } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { let tree = tree.state.downcast_ref::>>>(); *self.tree.borrow_mut() = tree.clone(); self.rebuild_element_if_necessary(); diff --git a/widget/src/lazy/responsive.rs b/widget/src/lazy/responsive.rs index f72250c6..18451a41 100644 --- a/widget/src/lazy/responsive.rs +++ b/widget/src/lazy/responsive.rs @@ -82,7 +82,7 @@ where let size = limits.max(); self.content = (self.view)(size); - state.tree.diff(&self.content); + state.tree.diff(&mut self.content); self.content.as_widget_mut().layout( &mut state.tree, diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs index f4a76d3b..e7ce47b5 100644 --- a/widget/src/mouse_area.rs +++ b/widget/src/mouse_area.rs @@ -181,8 +181,8 @@ where vec![Tree::new(&self.content)] } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(std::slice::from_ref(&self.content)); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(std::slice::from_mut(&mut self.content)); } fn size(&self) -> Size { diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs index c4c5b521..e84ae858 100644 --- a/widget/src/overlay/menu.rs +++ b/widget/src/overlay/menu.rs @@ -205,7 +205,7 @@ where class, } = menu; - let list = Scrollable::new(List { + let mut list = Scrollable::new(List { options, hovered_option, on_selected, @@ -218,7 +218,7 @@ where class, }); - state.tree.diff(&list as &dyn Widget<_, _, _>); + state.tree.diff(&mut list as &mut dyn Widget<_, _, _>); Self { position, diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index 8c63fe63..3dd0c941 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -378,7 +378,7 @@ where self.contents.iter().map(Content::state).collect() } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { let Memory { order, .. } = tree.state.downcast_ref(); // `Pane` always increments and is iterated by Ord so new @@ -401,7 +401,7 @@ where }); tree.diff_children_custom( - &self.contents, + &mut self.contents, |state, content| content.diff(state), Content::state, ); diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs index 6592694b..00f0d060 100644 --- a/widget/src/pane_grid/content.rs +++ b/widget/src/pane_grid/content.rs @@ -91,13 +91,13 @@ where } } - pub(super) fn diff(&self, tree: &mut Tree) { + pub(super) fn diff(&mut self, tree: &mut Tree) { if tree.children.len() == 2 { - if let Some(title_bar) = self.title_bar.as_ref() { + if let Some(title_bar) = self.title_bar.as_mut() { title_bar.diff(&mut tree.children[1]); } - tree.children[0].diff(&self.body); + tree.children[0].diff(&mut self.body); } else { *tree = self.state(); } diff --git a/widget/src/pane_grid/title_bar.rs b/widget/src/pane_grid/title_bar.rs index 7d15bf80..598cbcf5 100644 --- a/widget/src/pane_grid/title_bar.rs +++ b/widget/src/pane_grid/title_bar.rs @@ -128,17 +128,17 @@ where } } - pub(super) fn diff(&self, tree: &mut Tree) { + pub(super) fn diff(&mut self, tree: &mut Tree) { if tree.children.len() == 3 { - if let Some(controls) = self.controls.as_ref() { - if let Some(compact) = controls.compact.as_ref() { + if let Some(controls) = self.controls.as_mut() { + if let Some(compact) = controls.compact.as_mut() { tree.children[2].diff(compact); } - tree.children[1].diff(&controls.full); + tree.children[1].diff(&mut controls.full); } - tree.children[0].diff(&self.content); + tree.children[0].diff(&mut self.content); } else { *tree = self.state(); } diff --git a/widget/src/pin.rs b/widget/src/pin.rs index 04ed0324..f4a1c667 100644 --- a/widget/src/pin.rs +++ b/widget/src/pin.rs @@ -127,8 +127,8 @@ where self.content.as_widget().children() } - fn diff(&self, tree: &mut widget::Tree) { - self.content.as_widget().diff(tree); + fn diff(&mut self, tree: &mut widget::Tree) { + self.content.as_widget_mut().diff(tree); } fn size(&self) -> Size { diff --git a/widget/src/row.rs b/widget/src/row.rs index d70dee7f..2ee3d345 100644 --- a/widget/src/row.rs +++ b/widget/src/row.rs @@ -196,8 +196,8 @@ where self.children.iter().map(Tree::new).collect() } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(&self.children); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(&mut self.children); } fn size(&self) -> Size { @@ -398,7 +398,7 @@ where self.row.children() } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { self.row.diff(tree); } diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 909a14d9..0b0b6f9b 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -409,8 +409,8 @@ where vec![Tree::new(&self.content)] } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(std::slice::from_ref(&self.content)); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(std::slice::from_mut(&mut self.content)); } fn size(&self) -> Size { diff --git a/widget/src/sensor.rs b/widget/src/sensor.rs index e0122b2e..fd7a3510 100644 --- a/widget/src/sensor.rs +++ b/widget/src/sensor.rs @@ -184,8 +184,8 @@ where vec![Tree::new(&self.content)] } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(&[&self.content]); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(std::slice::from_mut(&mut self.content)); } fn update( diff --git a/widget/src/stack.rs b/widget/src/stack.rs index c0fb3147..63a6b97e 100644 --- a/widget/src/stack.rs +++ b/widget/src/stack.rs @@ -146,8 +146,8 @@ where self.children.iter().map(Tree::new).collect() } - fn diff(&self, tree: &mut Tree) { - tree.diff_children(&self.children); + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(&mut self.children); } fn size(&self) -> Size { diff --git a/widget/src/table.rs b/widget/src/table.rs index 06b47124..97083835 100644 --- a/widget/src/table.rs +++ b/widget/src/table.rs @@ -227,8 +227,8 @@ where .collect() } - fn diff(&self, state: &mut widget::Tree) { - state.diff_children(&self.cells); + fn diff(&mut self, state: &mut widget::Tree) { + state.diff_children(&mut self.cells); } fn layout( diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index c385b34b..1a4f8a99 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -654,7 +654,7 @@ where tree::State::new(State::::new()) } - fn diff(&self, tree: &mut Tree) { + fn diff(&mut self, tree: &mut Tree) { let state = tree.state.downcast_mut::>(); // Stop pasting if input becomes disabled diff --git a/widget/src/themer.rs b/widget/src/themer.rs index f335cd01..a089d1d5 100644 --- a/widget/src/themer.rs +++ b/widget/src/themer.rs @@ -81,8 +81,8 @@ where self.content.as_widget().children() } - fn diff(&self, tree: &mut Tree) { - self.content.as_widget().diff(tree); + fn diff(&mut self, tree: &mut Tree) { + self.content.as_widget_mut().diff(tree); } fn size(&self) -> Size { diff --git a/widget/src/tooltip.rs b/widget/src/tooltip.rs index 4c2c1a2e..782258da 100644 --- a/widget/src/tooltip.rs +++ b/widget/src/tooltip.rs @@ -155,10 +155,10 @@ where ] } - fn diff(&self, tree: &mut widget::Tree) { - tree.diff_children(&[ - self.content.as_widget(), - self.tooltip.as_widget(), + fn diff(&mut self, tree: &mut widget::Tree) { + tree.diff_children(&mut [ + self.content.as_widget_mut(), + self.tooltip.as_widget_mut(), ]); }