From c6ca33457f501e6403ff2c222101a8d2cfb1e7e7 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 17 Feb 2025 17:45:02 -0500 Subject: [PATCH] refactor: use RcWrapper --- src/widget/dropdown/menu/mod.rs | 61 ++++++++----------- src/widget/wrapper.rs | 103 +++++++++++++++++++++----------- 2 files changed, 94 insertions(+), 70 deletions(-) diff --git a/src/widget/dropdown/menu/mod.rs b/src/widget/dropdown/menu/mod.rs index 507a0d40..736fbac5 100644 --- a/src/widget/dropdown/menu/mod.rs +++ b/src/widget/dropdown/menu/mod.rs @@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex}; pub use appearance::{Appearance, StyleSheet}; use iced::advanced::widget; -use crate::widget::{icon, Container}; +use crate::widget::{icon, Container, RcElementWrapper, RcWrapper}; use iced_core::event::{self, Event}; use iced_core::layout::{self, Layout}; use iced_core::text::{self, Text}; @@ -127,19 +127,14 @@ where #[must_use] #[derive(Debug, Clone)] pub struct State { - pub(crate) tree: Arc>, + pub(crate) tree: RcWrapper, } -// TODO use the Rc wrapper instead -// XXX The tree is only used on one thread, but this is needed to make a message -unsafe impl Send for State {} -unsafe impl Sync for State {} - impl State { /// Creates a new [`State`] for a [`Menu`]. pub fn new() -> Self { Self { - tree: Arc::new(Mutex::new(Tree::empty())), + tree: RcWrapper::new(Tree::empty()), } } } @@ -151,7 +146,7 @@ impl Default for State { } struct Overlay<'a, Message> { - state: Arc>, + state: RcWrapper, container: Container<'a, Message, crate::Theme, crate::Renderer>, width: f32, target_height: f32, @@ -199,9 +194,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> { )) .class(crate::style::Container::Dropdown); - let mut tree_guard = state.tree.lock().unwrap(); - tree_guard.diff(&mut container as &mut dyn Widget<_, _, _>); - drop(tree_guard); + state + .tree + .with_data_mut(|tree| tree.diff(&mut container as &mut dyn Widget<_, _, _>)); + Self { state: state.tree.clone(), container, @@ -213,8 +209,6 @@ impl<'a, Message: 'a> Overlay<'a, Message> { } fn _layout(&self, renderer: &crate::Renderer, bounds: Size) -> layout::Node { - let mut guard = self.state.lock().unwrap(); - let space_below = bounds.height - (self.position.y + self.target_height); let space_above = self.position.y; @@ -231,7 +225,9 @@ impl<'a, Message: 'a> Overlay<'a, Message> { ) .width(self.width); - let node = self.container.layout(&mut guard, renderer, &limits); + let node = self + .state + .with_data_mut(|tree| self.container.layout(tree, renderer, &limits)); node.clone().move_to(if space_below > space_above { self.position + Vector::new(0.0, self.target_height) @@ -250,12 +246,12 @@ impl<'a, Message: 'a> Overlay<'a, Message> { shell: &mut Shell<'_, Message>, ) -> event::Status { let bounds = layout.bounds(); - let mut guard = self.state.lock().unwrap(); - let state = &mut *guard; - self.container.on_event( - state, event, layout, cursor, renderer, clipboard, shell, &bounds, - ) + self.state.with_data_mut(|tree| { + self.container.on_event( + tree, event, layout, cursor, renderer, clipboard, shell, &bounds, + ) + }) } fn _mouse_interaction( @@ -265,10 +261,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> { viewport: &Rectangle, renderer: &crate::Renderer, ) -> mouse::Interaction { - let guard = self.state.lock().unwrap(); - - self.container - .mouse_interaction(&guard, layout, cursor, viewport, renderer) + self.state.with_data(|tree| { + self.container + .mouse_interaction(tree, layout, cursor, viewport, renderer) + }) } fn _draw( @@ -279,8 +275,6 @@ impl<'a, Message: 'a> Overlay<'a, Message> { layout: Layout<'_>, cursor: mouse::Cursor, ) { - let state = self.state.lock().unwrap(); - let appearance = theme.appearance(&self.style); let bounds = layout.bounds(); @@ -297,8 +291,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> { appearance.background, ); - self.container - .draw(&*state, renderer, theme, style, layout, cursor, &bounds); + self.state.with_data(|tree| { + self.container + .draw(tree, renderer, theme, style, layout, cursor, &bounds) + }) } } @@ -306,8 +302,6 @@ impl<'a, Message: 'a> iced_core::Overlay for Overlay<'a, Message> { fn layout(&mut self, renderer: &crate::Renderer, bounds: Size) -> layout::Node { - let mut guard = self.state.lock().unwrap(); - self._layout(renderer, bounds) } @@ -341,8 +335,6 @@ impl<'a, Message: 'a> iced_core::Overlay layout: Layout<'_>, cursor: mouse::Cursor, ) { - let guard = self.state.lock().unwrap(); - self._draw(renderer, theme, style, layout, cursor); } } @@ -360,11 +352,10 @@ impl<'a, Message: 'a> crate::widget::Widget layout::Node { - let mut guard = self.state.lock().unwrap(); - let limits = limits.width(self.width); - self.container.layout(&mut guard, renderer, &limits) + self.state + .with_data_mut(|tree| self.container.layout(tree, renderer, &limits)) } fn mouse_interaction( diff --git a/src/widget/wrapper.rs b/src/widget/wrapper.rs index ca63dded..219254c7 100644 --- a/src/widget/wrapper.rs +++ b/src/widget/wrapper.rs @@ -8,48 +8,80 @@ use crate::Element; use iced::{event, Length, Rectangle, Size}; use iced_core::{id::Id, widget, widget::tree, Widget}; -#[derive(Clone)] -pub struct RcElementWrapper { - pub(crate) element: Rc>>, +#[derive(Debug)] +pub struct RcWrapper { + pub(crate) data: Rc>, pub(crate) thread_id: ThreadId, } -impl RcElementWrapper { - pub fn new(element: Element<'static, M>) -> Self { +impl Clone for RcWrapper { + fn clone(&self) -> Self { Self { - element: Rc::new(RefCell::new(element)), + data: self.data.clone(), + thread_id: self.thread_id, + } + } +} + +unsafe impl Send for RcWrapper {} +unsafe impl Sync for RcWrapper {} + +impl RcWrapper { + pub fn new(element: T) -> Self { + Self { + data: Rc::new(RefCell::new(element)), thread_id: thread::current().id(), } } - pub fn with_element(&self, f: impl FnOnce(&Element<'static, M>) -> T) -> T { + /// # Panics + /// + /// Will panic if used outside of original thread. + pub fn with_data(&self, f: impl FnOnce(&T) -> O) -> O { assert_eq!(self.thread_id, thread::current().id()); - let my_ref: &Element<'static, M> = &RefCell::borrow(self.element.as_ref()); + let my_ref: &T = &RefCell::borrow(self.data.as_ref()); f(my_ref) } - pub fn with_element_mut(&self, f: impl FnOnce(&mut Element<'static, M>) -> T) -> T { + /// # Panics + /// + /// Will panic if used outside of original thread. + pub fn with_data_mut(&self, f: impl FnOnce(&mut T) -> O) -> O { assert_eq!(self.thread_id, thread::current().id()); - let my_refmut: &mut Element<'static, M> = &mut RefCell::borrow_mut(self.element.as_ref()); + let my_refmut: &mut T = &mut RefCell::borrow_mut(self.data.as_ref()); f(my_refmut) } - pub(crate) unsafe fn as_ptr(&self) -> *mut Element<'static, M> { + /// # Panics + /// + /// Will panic if used outside of original thread. + pub(crate) unsafe fn as_ptr(&self) -> *mut T { assert_eq!(self.thread_id, thread::current().id()); - RefCell::as_ptr(self.element.as_ref()) + RefCell::as_ptr(self.data.as_ref()) } } -unsafe impl Send for RcElementWrapper {} -unsafe impl Sync for RcElementWrapper {} +#[derive(Clone)] +pub struct RcElementWrapper { + pub(crate) element: RcWrapper>, +} + +impl RcElementWrapper { + #[must_use] + pub fn new(element: Element<'static, M>) -> Self { + RcElementWrapper { + element: RcWrapper::new(element), + } + } +} impl Widget for RcElementWrapper { fn size(&self) -> Size { - self.with_element(|e| e.as_widget().size()) + self.element.with_data(|e| e.as_widget().size()) } fn size_hint(&self) -> Size { - self.element.borrow_mut().as_widget().size_hint() + self.element.with_data(move |e| e.as_widget().size_hint()) } fn layout( @@ -58,7 +90,8 @@ impl Widget for RcElementWrapper { renderer: &crate::Renderer, limits: &crate::iced_core::layout::Limits, ) -> crate::iced_core::layout::Node { - self.with_element_mut(|e| e.as_widget_mut().layout(tree, renderer, limits)) + self.element + .with_data_mut(|e| e.as_widget_mut().layout(tree, renderer, limits)) } fn draw( @@ -71,26 +104,26 @@ impl Widget for RcElementWrapper { cursor: crate::iced_core::mouse::Cursor, viewport: &Rectangle, ) { - self.with_element(move |e| { + self.element.with_data(move |e| { e.as_widget() - .draw(tree, renderer, theme, style, layout, cursor, viewport) - }) + .draw(tree, renderer, theme, style, layout, cursor, viewport); + }); } fn tag(&self) -> tree::Tag { - self.with_element(|e| e.as_widget().tag()) + self.element.with_data(|e| e.as_widget().tag()) } fn state(&self) -> tree::State { - self.with_element(|e| e.as_widget().state()) + self.element.with_data(|e| e.as_widget().state()) } fn children(&self) -> Vec { - self.with_element(|e| e.as_widget().children()) + self.element.with_data(|e| e.as_widget().children()) } fn diff(&mut self, tree: &mut tree::Tree) { - self.with_element_mut(|e| e.as_widget_mut().diff(tree)) + self.element.with_data_mut(|e| e.as_widget_mut().diff(tree)); } fn operate( @@ -100,9 +133,9 @@ impl Widget for RcElementWrapper { renderer: &crate::Renderer, operation: &mut dyn widget::Operation, ) { - self.with_element(|e| { + self.element.with_data(|e| { e.as_widget().operate(state, layout, renderer, operation); - }) + }); } fn on_event( @@ -116,7 +149,7 @@ impl Widget for RcElementWrapper { shell: &mut crate::iced_core::Shell<'_, M>, viewport: &Rectangle, ) -> event::Status { - self.with_element_mut(|e| { + self.element.with_data_mut(|e| { e.as_widget_mut().on_event( state, event, layout, cursor, renderer, clipboard, shell, viewport, ) @@ -131,7 +164,7 @@ impl Widget for RcElementWrapper { viewport: &Rectangle, renderer: &crate::Renderer, ) -> crate::iced_core::mouse::Interaction { - self.with_element(|e| { + self.element.with_data(|e| { e.as_widget() .mouse_interaction(state, layout, cursor, viewport, renderer) }) @@ -144,8 +177,8 @@ impl Widget for RcElementWrapper { renderer: &crate::Renderer, translation: crate::iced_core::Vector, ) -> Option> { - assert_eq!(self.thread_id, thread::current().id()); - Rc::get_mut(&mut self.element).and_then(|e| { + assert_eq!(self.element.thread_id, thread::current().id()); + Rc::get_mut(&mut self.element.data).and_then(|e| { e.get_mut() .as_widget_mut() .overlay(state, layout, renderer, translation) @@ -153,11 +186,11 @@ impl Widget for RcElementWrapper { } fn id(&self) -> Option { - self.with_element_mut(|e| e.as_widget_mut().id()) + self.element.with_data_mut(|e| e.as_widget_mut().id()) } fn set_id(&mut self, id: Id) { - self.with_element_mut(|e| e.as_widget_mut().set_id(id)) + self.element.with_data_mut(|e| e.as_widget_mut().set_id(id)); } fn drag_destinations( @@ -167,10 +200,10 @@ impl Widget for RcElementWrapper { renderer: &crate::Renderer, dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles, ) { - self.with_element_mut(|e| { + self.element.with_data_mut(|e| { e.as_widget_mut() - .drag_destinations(state, layout, renderer, dnd_rectangles) - }) + .drag_destinations(state, layout, renderer, dnd_rectangles); + }); } }