Provide mut access to allocated arena struct via non-cloneable ArenaBox
This commit also allows turning an `ArenaBox` into an `ArenaRef` when non-mutable access is required, which makes `ArenaRef: Clone`. This fixes a bug that prevented the command palette from reading all the available actions while the `command_palette::Toggle` action was being dispatched.
This commit is contained in:
parent
ca091f3d34
commit
73682daf38
4 changed files with 70 additions and 73 deletions
|
@ -52,7 +52,7 @@ impl Arena {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn alloc<T>(&mut self, f: impl FnOnce() -> T) -> ArenaRef<T> {
|
pub fn alloc<T>(&mut self, f: impl FnOnce() -> T) -> ArenaBox<T> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn inner_writer<T, F>(ptr: *mut T, f: F)
|
unsafe fn inner_writer<T, F>(ptr: *mut T, f: F)
|
||||||
where
|
where
|
||||||
|
@ -70,7 +70,7 @@ impl Arena {
|
||||||
let next_offset = self.offset.add(layout.size());
|
let next_offset = self.offset.add(layout.size());
|
||||||
assert!(next_offset <= self.end);
|
assert!(next_offset <= self.end);
|
||||||
|
|
||||||
let result = ArenaRef {
|
let result = ArenaBox {
|
||||||
ptr: self.offset.cast(),
|
ptr: self.offset.cast(),
|
||||||
valid: self.valid.clone(),
|
valid: self.valid.clone(),
|
||||||
};
|
};
|
||||||
|
@ -93,15 +93,15 @@ impl Drop for Arena {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ArenaRef<T: ?Sized> {
|
pub struct ArenaBox<T: ?Sized> {
|
||||||
ptr: *mut T,
|
ptr: *mut T,
|
||||||
valid: Rc<Cell<bool>>,
|
valid: Rc<Cell<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> ArenaRef<T> {
|
impl<T: ?Sized> ArenaBox<T> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn map<U: ?Sized>(mut self, f: impl FnOnce(&mut T) -> &mut U) -> ArenaRef<U> {
|
pub fn map<U: ?Sized>(mut self, f: impl FnOnce(&mut T) -> &mut U) -> ArenaBox<U> {
|
||||||
ArenaRef {
|
ArenaBox {
|
||||||
ptr: f(&mut self),
|
ptr: f(&mut self),
|
||||||
valid: self.valid,
|
valid: self.valid,
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ impl<T: ?Sized> ArenaRef<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> Deref for ArenaRef<T> {
|
impl<T: ?Sized> Deref for ArenaBox<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -125,7 +125,7 @@ impl<T: ?Sized> Deref for ArenaRef<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> DerefMut for ArenaRef<T> {
|
impl<T: ?Sized> DerefMut for ArenaBox<T> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.validate();
|
self.validate();
|
||||||
|
@ -133,6 +133,32 @@ impl<T: ?Sized> DerefMut for ArenaRef<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ArenaRef<T: ?Sized>(ArenaBox<T>);
|
||||||
|
|
||||||
|
impl<T: ?Sized> From<ArenaBox<T>> for ArenaRef<T> {
|
||||||
|
fn from(value: ArenaBox<T>) -> Self {
|
||||||
|
ArenaRef(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Clone for ArenaRef<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(ArenaBox {
|
||||||
|
ptr: self.0.ptr,
|
||||||
|
valid: self.0.valid.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Deref for ArenaRef<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.0.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{cell::Cell, rc::Rc};
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ArenaRef, AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size,
|
ArenaBox, AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size,
|
||||||
ViewContext, WindowContext, ELEMENT_ARENA,
|
ViewContext, WindowContext, ELEMENT_ARENA,
|
||||||
};
|
};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -405,7 +405,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AnyElement(ArenaRef<dyn ElementObject>);
|
pub struct AnyElement(ArenaBox<dyn ElementObject>);
|
||||||
|
|
||||||
impl AnyElement {
|
impl AnyElement {
|
||||||
pub fn new<E>(element: E) -> Self
|
pub fn new<E>(element: E) -> Self
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub(crate) struct DispatchNode {
|
||||||
|
|
||||||
type KeyListener = ArenaRef<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>;
|
type KeyListener = ArenaRef<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub(crate) struct DispatchActionListener {
|
pub(crate) struct DispatchActionListener {
|
||||||
pub(crate) action_type: TypeId,
|
pub(crate) action_type: TypeId,
|
||||||
pub(crate) listener: ArenaRef<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>,
|
pub(crate) listener: ArenaRef<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>,
|
||||||
|
@ -268,10 +269,6 @@ impl DispatchTree {
|
||||||
&self.nodes[node_id.0]
|
&self.nodes[node_id.0]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_mut(&mut self, node_id: DispatchNodeId) -> &mut DispatchNode {
|
|
||||||
&mut self.nodes[node_id.0]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn active_node(&mut self) -> &mut DispatchNode {
|
fn active_node(&mut self) -> &mut DispatchNode {
|
||||||
let active_node_id = self.active_node_id();
|
let active_node_id = self.active_node_id();
|
||||||
&mut self.nodes[active_node_id.0]
|
&mut self.nodes[active_node_id.0]
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
arena::{Arena, ArenaRef},
|
px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, ArenaBox, ArenaRef,
|
||||||
key_dispatch::DispatchActionListener,
|
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
|
||||||
px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, AsyncWindowContext,
|
DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
|
||||||
AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchNodeId,
|
Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
|
||||||
DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten,
|
ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId,
|
||||||
FontId, GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyBinding, KeyContext,
|
Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent,
|
||||||
KeyDownEvent, KeystrokeEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite,
|
Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
||||||
MouseButton, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
|
PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams,
|
||||||
PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
|
RenderSvgParams, ScaledPixels, Scene, SceneBuilder, Shadow, SharedString, Size, Style,
|
||||||
RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, Scene, SceneBuilder,
|
SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View,
|
||||||
Shadow, SharedString, Size, Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine,
|
VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||||
Task, Underline, UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions,
|
|
||||||
SUBPIXEL_VARIANTS,
|
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context as _, Result};
|
use anyhow::{anyhow, Context as _, Result};
|
||||||
use collections::FxHashMap;
|
use collections::FxHashMap;
|
||||||
|
@ -96,7 +94,7 @@ impl DispatchPhase {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
|
type AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
|
||||||
type AnyMouseListener = ArenaRef<dyn FnMut(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
|
type AnyMouseListener = ArenaBox<dyn FnMut(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
|
||||||
type AnyWindowFocusListener = Box<dyn FnMut(&FocusEvent, &mut WindowContext) -> bool + 'static>;
|
type AnyWindowFocusListener = Box<dyn FnMut(&FocusEvent, &mut WindowContext) -> bool + 'static>;
|
||||||
|
|
||||||
struct FocusEvent {
|
struct FocusEvent {
|
||||||
|
@ -906,7 +904,10 @@ impl<'a> WindowContext<'a> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|handler| handler as _);
|
.map(|handler| handler as _);
|
||||||
self.window.next_frame.dispatch_tree.on_key_event(listener);
|
self.window
|
||||||
|
.next_frame
|
||||||
|
.dispatch_tree
|
||||||
|
.on_key_event(ArenaRef::from(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register an action listener on the window for the next frame. The type of action
|
/// Register an action listener on the window for the next frame. The type of action
|
||||||
|
@ -928,7 +929,7 @@ impl<'a> WindowContext<'a> {
|
||||||
self.window
|
self.window
|
||||||
.next_frame
|
.next_frame
|
||||||
.dispatch_tree
|
.dispatch_tree
|
||||||
.on_action(action_type, listener);
|
.on_action(action_type, ArenaRef::from(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_action_available(&self, action: &dyn Action) -> bool {
|
pub fn is_action_available(&self, action: &dyn Action) -> bool {
|
||||||
|
@ -1339,7 +1340,7 @@ impl<'a> WindowContext<'a> {
|
||||||
cx.window
|
cx.window
|
||||||
.next_frame
|
.next_frame
|
||||||
.dispatch_tree
|
.dispatch_tree
|
||||||
.on_action(*action_type, listener)
|
.on_action(*action_type, ArenaRef::from(listener))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1583,43 +1584,30 @@ impl<'a> WindowContext<'a> {
|
||||||
self.propagate_event = true;
|
self.propagate_event = true;
|
||||||
|
|
||||||
for node_id in &dispatch_path {
|
for node_id in &dispatch_path {
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||||
|
|
||||||
if let Some(context) = node.context.clone() {
|
if let Some(context) = node.context.clone() {
|
||||||
context_stack.push(context);
|
context_stack.push(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
let key_listeners = mem::take(&mut node.key_listeners);
|
for key_listener in node.key_listeners.clone() {
|
||||||
for key_listener in &key_listeners {
|
|
||||||
key_listener(event, DispatchPhase::Capture, self);
|
key_listener(event, DispatchPhase::Capture, self);
|
||||||
if !self.propagate_event {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
|
||||||
node.key_listeners = key_listeners;
|
|
||||||
|
|
||||||
if !self.propagate_event {
|
if !self.propagate_event {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bubble phase
|
// Bubble phase
|
||||||
for node_id in dispatch_path.iter().rev() {
|
for node_id in dispatch_path.iter().rev() {
|
||||||
// Handle low level key events
|
// Handle low level key events
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||||
let key_listeners = mem::take(&mut node.key_listeners);
|
for key_listener in node.key_listeners.clone() {
|
||||||
for key_listener in &key_listeners {
|
|
||||||
key_listener(event, DispatchPhase::Bubble, self);
|
key_listener(event, DispatchPhase::Bubble, self);
|
||||||
if !self.propagate_event {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
|
||||||
node.key_listeners = key_listeners;
|
|
||||||
|
|
||||||
if !self.propagate_event {
|
if !self.propagate_event {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Match keystrokes
|
// Match keystrokes
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||||
|
@ -1667,54 +1655,40 @@ impl<'a> WindowContext<'a> {
|
||||||
|
|
||||||
// Capture phase
|
// Capture phase
|
||||||
for node_id in &dispatch_path {
|
for node_id in &dispatch_path {
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||||
let action_listeners = mem::take(&mut node.action_listeners);
|
|
||||||
for DispatchActionListener {
|
for DispatchActionListener {
|
||||||
action_type,
|
action_type,
|
||||||
listener,
|
listener,
|
||||||
} in &action_listeners
|
} in node.action_listeners.clone()
|
||||||
{
|
{
|
||||||
let any_action = action.as_any();
|
let any_action = action.as_any();
|
||||||
if *action_type == any_action.type_id() {
|
if action_type == any_action.type_id() {
|
||||||
listener(any_action, DispatchPhase::Capture, self);
|
listener(any_action, DispatchPhase::Capture, self);
|
||||||
if !self.propagate_event {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
|
||||||
node.action_listeners = action_listeners;
|
|
||||||
|
|
||||||
if !self.propagate_event {
|
if !self.propagate_event {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Bubble phase
|
// Bubble phase
|
||||||
for node_id in dispatch_path.iter().rev() {
|
for node_id in dispatch_path.iter().rev() {
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
|
||||||
let action_listeners = mem::take(&mut node.action_listeners);
|
|
||||||
for DispatchActionListener {
|
for DispatchActionListener {
|
||||||
action_type,
|
action_type,
|
||||||
listener,
|
listener,
|
||||||
} in &action_listeners
|
} in node.action_listeners.clone()
|
||||||
{
|
{
|
||||||
let any_action = action.as_any();
|
let any_action = action.as_any();
|
||||||
if *action_type == any_action.type_id() {
|
if action_type == any_action.type_id() {
|
||||||
self.propagate_event = false; // Actions stop propagation by default during the bubble phase
|
self.propagate_event = false; // Actions stop propagation by default during the bubble phase
|
||||||
listener(any_action, DispatchPhase::Bubble, self);
|
listener(any_action, DispatchPhase::Bubble, self);
|
||||||
if !self.propagate_event {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let node = self.window.rendered_frame.dispatch_tree.node_mut(*node_id);
|
|
||||||
node.action_listeners = action_listeners;
|
|
||||||
if !self.propagate_event {
|
if !self.propagate_event {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Register the given handler to be invoked whenever the global of the given type
|
/// Register the given handler to be invoked whenever the global of the given type
|
||||||
/// is updated.
|
/// is updated.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue