refactor: use RcWrapper

This commit is contained in:
Ashley Wulber 2025-02-17 17:45:02 -05:00
parent 9ee6233884
commit 3de3e3efa8
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
2 changed files with 94 additions and 70 deletions

View file

@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex};
pub use appearance::{Appearance, StyleSheet}; pub use appearance::{Appearance, StyleSheet};
use iced::advanced::widget; 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::event::{self, Event};
use iced_core::layout::{self, Layout}; use iced_core::layout::{self, Layout};
use iced_core::text::{self, Text}; use iced_core::text::{self, Text};
@ -127,19 +127,14 @@ where
#[must_use] #[must_use]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct State { pub struct State {
pub(crate) tree: Arc<Mutex<Tree>>, pub(crate) tree: RcWrapper<Tree>,
} }
// 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 { impl State {
/// Creates a new [`State`] for a [`Menu`]. /// Creates a new [`State`] for a [`Menu`].
pub fn new() -> Self { pub fn new() -> Self {
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> { struct Overlay<'a, Message> {
state: Arc<Mutex<Tree>>, state: RcWrapper<Tree>,
container: Container<'a, Message, crate::Theme, crate::Renderer>, container: Container<'a, Message, crate::Theme, crate::Renderer>,
width: f32, width: f32,
target_height: f32, target_height: f32,
@ -199,9 +194,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
)) ))
.class(crate::style::Container::Dropdown); .class(crate::style::Container::Dropdown);
let mut tree_guard = state.tree.lock().unwrap(); state
tree_guard.diff(&mut container as &mut dyn Widget<_, _, _>); .tree
drop(tree_guard); .with_data_mut(|tree| tree.diff(&mut container as &mut dyn Widget<_, _, _>));
Self { Self {
state: state.tree.clone(), state: state.tree.clone(),
container, container,
@ -213,8 +209,6 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
} }
fn _layout(&self, renderer: &crate::Renderer, bounds: Size) -> layout::Node { 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_below = bounds.height - (self.position.y + self.target_height);
let space_above = self.position.y; let space_above = self.position.y;
@ -231,7 +225,9 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
) )
.width(self.width); .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 { node.clone().move_to(if space_below > space_above {
self.position + Vector::new(0.0, self.target_height) self.position + Vector::new(0.0, self.target_height)
@ -250,12 +246,12 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
) -> event::Status { ) -> event::Status {
let bounds = layout.bounds(); let bounds = layout.bounds();
let mut guard = self.state.lock().unwrap();
let state = &mut *guard; self.state.with_data_mut(|tree| {
self.container.on_event( self.container.on_event(
state, event, layout, cursor, renderer, clipboard, shell, &bounds, tree, event, layout, cursor, renderer, clipboard, shell, &bounds,
) )
})
} }
fn _mouse_interaction( fn _mouse_interaction(
@ -265,10 +261,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
viewport: &Rectangle, viewport: &Rectangle,
renderer: &crate::Renderer, renderer: &crate::Renderer,
) -> mouse::Interaction { ) -> mouse::Interaction {
let guard = self.state.lock().unwrap(); self.state.with_data(|tree| {
self.container
self.container .mouse_interaction(tree, layout, cursor, viewport, renderer)
.mouse_interaction(&guard, layout, cursor, viewport, renderer) })
} }
fn _draw( fn _draw(
@ -279,8 +275,6 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
layout: Layout<'_>, layout: Layout<'_>,
cursor: mouse::Cursor, cursor: mouse::Cursor,
) { ) {
let state = self.state.lock().unwrap();
let appearance = theme.appearance(&self.style); let appearance = theme.appearance(&self.style);
let bounds = layout.bounds(); let bounds = layout.bounds();
@ -297,8 +291,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
appearance.background, appearance.background,
); );
self.container self.state.with_data(|tree| {
.draw(&*state, renderer, theme, style, layout, cursor, &bounds); self.container
.draw(tree, renderer, theme, style, layout, cursor, &bounds)
})
} }
} }
@ -306,8 +302,6 @@ impl<'a, Message: 'a> iced_core::Overlay<Message, crate::Theme, crate::Renderer>
for Overlay<'a, Message> for Overlay<'a, Message>
{ {
fn layout(&mut self, renderer: &crate::Renderer, bounds: Size) -> layout::Node { fn layout(&mut self, renderer: &crate::Renderer, bounds: Size) -> layout::Node {
let mut guard = self.state.lock().unwrap();
self._layout(renderer, bounds) self._layout(renderer, bounds)
} }
@ -341,8 +335,6 @@ impl<'a, Message: 'a> iced_core::Overlay<Message, crate::Theme, crate::Renderer>
layout: Layout<'_>, layout: Layout<'_>,
cursor: mouse::Cursor, cursor: mouse::Cursor,
) { ) {
let guard = self.state.lock().unwrap();
self._draw(renderer, theme, style, layout, cursor); self._draw(renderer, theme, style, layout, cursor);
} }
} }
@ -360,11 +352,10 @@ impl<'a, Message: 'a> crate::widget::Widget<Message, crate::Theme, crate::Render
renderer: &crate::Renderer, renderer: &crate::Renderer,
limits: &iced::Limits, limits: &iced::Limits,
) -> layout::Node { ) -> layout::Node {
let mut guard = self.state.lock().unwrap();
let limits = limits.width(self.width); 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( fn mouse_interaction(

View file

@ -8,48 +8,80 @@ use crate::Element;
use iced::{event, Length, Rectangle, Size}; use iced::{event, Length, Rectangle, Size};
use iced_core::{id::Id, widget, widget::tree, Widget}; use iced_core::{id::Id, widget, widget::tree, Widget};
#[derive(Clone)] #[derive(Debug)]
pub struct RcElementWrapper<M> { pub struct RcWrapper<T> {
pub(crate) element: Rc<RefCell<Element<'static, M>>>, pub(crate) data: Rc<RefCell<T>>,
pub(crate) thread_id: ThreadId, pub(crate) thread_id: ThreadId,
} }
impl<M> RcElementWrapper<M> { impl<T> Clone for RcWrapper<T> {
pub fn new(element: Element<'static, M>) -> Self { fn clone(&self) -> Self {
Self { Self {
element: Rc::new(RefCell::new(element)), data: self.data.clone(),
thread_id: self.thread_id,
}
}
}
unsafe impl<M: 'static> Send for RcWrapper<M> {}
unsafe impl<M: 'static> Sync for RcWrapper<M> {}
impl<T> RcWrapper<T> {
pub fn new(element: T) -> Self {
Self {
data: Rc::new(RefCell::new(element)),
thread_id: thread::current().id(), thread_id: thread::current().id(),
} }
} }
pub fn with_element<T>(&self, f: impl FnOnce(&Element<'static, M>) -> T) -> T { /// # Panics
///
/// Will panic if used outside of original thread.
pub fn with_data<O>(&self, f: impl FnOnce(&T) -> O) -> O {
assert_eq!(self.thread_id, thread::current().id()); 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) f(my_ref)
} }
pub fn with_element_mut<T>(&self, f: impl FnOnce(&mut Element<'static, M>) -> T) -> T { /// # Panics
///
/// Will panic if used outside of original thread.
pub fn with_data_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
assert_eq!(self.thread_id, thread::current().id()); 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) 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()); assert_eq!(self.thread_id, thread::current().id());
RefCell::as_ptr(self.element.as_ref()) RefCell::as_ptr(self.data.as_ref())
} }
} }
unsafe impl<M: 'static> Send for RcElementWrapper<M> {} #[derive(Clone)]
unsafe impl<M: 'static> Sync for RcElementWrapper<M> {} pub struct RcElementWrapper<M> {
pub(crate) element: RcWrapper<Element<'static, M>>,
}
impl<M> RcElementWrapper<M> {
#[must_use]
pub fn new(element: Element<'static, M>) -> Self {
RcElementWrapper {
element: RcWrapper::new(element),
}
}
}
impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> { impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
self.with_element(|e| e.as_widget().size()) self.element.with_data(|e| e.as_widget().size())
} }
fn size_hint(&self) -> Size<Length> { fn size_hint(&self) -> Size<Length> {
self.element.borrow_mut().as_widget().size_hint() self.element.with_data(move |e| e.as_widget().size_hint())
} }
fn layout( fn layout(
@ -58,7 +90,8 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
renderer: &crate::Renderer, renderer: &crate::Renderer,
limits: &crate::iced_core::layout::Limits, limits: &crate::iced_core::layout::Limits,
) -> crate::iced_core::layout::Node { ) -> 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( fn draw(
@ -71,26 +104,26 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
cursor: crate::iced_core::mouse::Cursor, cursor: crate::iced_core::mouse::Cursor,
viewport: &Rectangle, viewport: &Rectangle,
) { ) {
self.with_element(move |e| { self.element.with_data(move |e| {
e.as_widget() e.as_widget()
.draw(tree, renderer, theme, style, layout, cursor, viewport) .draw(tree, renderer, theme, style, layout, cursor, viewport);
}) });
} }
fn tag(&self) -> tree::Tag { 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 { 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<tree::Tree> { fn children(&self) -> Vec<tree::Tree> {
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) { 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( fn operate(
@ -100,9 +133,9 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
renderer: &crate::Renderer, renderer: &crate::Renderer,
operation: &mut dyn widget::Operation, operation: &mut dyn widget::Operation,
) { ) {
self.with_element(|e| { self.element.with_data(|e| {
e.as_widget().operate(state, layout, renderer, operation); e.as_widget().operate(state, layout, renderer, operation);
}) });
} }
fn on_event( fn on_event(
@ -116,7 +149,7 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
shell: &mut crate::iced_core::Shell<'_, M>, shell: &mut crate::iced_core::Shell<'_, M>,
viewport: &Rectangle, viewport: &Rectangle,
) -> event::Status { ) -> event::Status {
self.with_element_mut(|e| { self.element.with_data_mut(|e| {
e.as_widget_mut().on_event( e.as_widget_mut().on_event(
state, event, layout, cursor, renderer, clipboard, shell, viewport, state, event, layout, cursor, renderer, clipboard, shell, viewport,
) )
@ -131,7 +164,7 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
viewport: &Rectangle, viewport: &Rectangle,
renderer: &crate::Renderer, renderer: &crate::Renderer,
) -> crate::iced_core::mouse::Interaction { ) -> crate::iced_core::mouse::Interaction {
self.with_element(|e| { self.element.with_data(|e| {
e.as_widget() e.as_widget()
.mouse_interaction(state, layout, cursor, viewport, renderer) .mouse_interaction(state, layout, cursor, viewport, renderer)
}) })
@ -144,8 +177,8 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
renderer: &crate::Renderer, renderer: &crate::Renderer,
translation: crate::iced_core::Vector, translation: crate::iced_core::Vector,
) -> Option<crate::iced_core::overlay::Element<'a, M, crate::Theme, crate::Renderer>> { ) -> Option<crate::iced_core::overlay::Element<'a, M, crate::Theme, crate::Renderer>> {
assert_eq!(self.thread_id, thread::current().id()); assert_eq!(self.element.thread_id, thread::current().id());
Rc::get_mut(&mut self.element).and_then(|e| { Rc::get_mut(&mut self.element.data).and_then(|e| {
e.get_mut() e.get_mut()
.as_widget_mut() .as_widget_mut()
.overlay(state, layout, renderer, translation) .overlay(state, layout, renderer, translation)
@ -153,11 +186,11 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
} }
fn id(&self) -> Option<Id> { fn id(&self) -> Option<Id> {
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) { 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( fn drag_destinations(
@ -167,10 +200,10 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
renderer: &crate::Renderer, renderer: &crate::Renderer,
dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles, dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles,
) { ) {
self.with_element_mut(|e| { self.element.with_data_mut(|e| {
e.as_widget_mut() e.as_widget_mut()
.drag_destinations(state, layout, renderer, dnd_rectangles) .drag_destinations(state, layout, renderer, dnd_rectangles);
}) });
} }
} }