Checkpoint

This commit is contained in:
Antonio Scandurra 2023-10-11 12:45:09 +02:00
parent b6a3d9ce59
commit a9c69bf774
5 changed files with 150 additions and 55 deletions

View file

@ -9,15 +9,15 @@ use refineable::Refineable;
use crate::{ use crate::{
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor, LayoutId, current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor, LayoutId,
MainThread, MainThreadOnly, Platform, PlatformDisplayLinker, RootView, SvgRenderer, Task, MainThread, MainThreadOnly, Platform, PlatformDisplayLinker, RootView, SubscriberSet,
TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext,
WindowHandle, WindowId,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::{HashMap, VecDeque}; use collections::{HashMap, VecDeque};
use futures::Future; use futures::Future;
use parking_lot::Mutex; use parking_lot::Mutex;
use slotmap::SlotMap; use slotmap::SlotMap;
use smallvec::SmallVec;
use std::{ use std::{
any::{type_name, Any, TypeId}, any::{type_name, Any, TypeId},
mem, mem,
@ -67,8 +67,8 @@ impl App {
entities, entities,
windows: SlotMap::with_key(), windows: SlotMap::with_key(),
pending_effects: Default::default(), pending_effects: Default::default(),
observers: Default::default(), observers: SubscriberSet::new(),
event_handlers: Default::default(), event_handlers: SubscriberSet::new(),
layout_id_buffer: Default::default(), layout_id_buffer: Default::default(),
}) })
})) }))
@ -88,9 +88,8 @@ impl App {
} }
} }
type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>; type Handler = Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>;
type EventHandlers = type EventHandler = Arc<dyn Fn(&dyn Any, &mut AppContext) -> bool + Send + Sync + 'static>;
SmallVec<[Arc<dyn Fn(&dyn Any, &mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>; type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
pub struct AppContext { pub struct AppContext {
@ -109,8 +108,8 @@ pub struct AppContext {
pub(crate) entities: EntityMap, pub(crate) entities: EntityMap,
pub(crate) windows: SlotMap<WindowId, Option<Window>>, pub(crate) windows: SlotMap<WindowId, Option<Window>>,
pub(crate) pending_effects: VecDeque<Effect>, pub(crate) pending_effects: VecDeque<Effect>,
pub(crate) observers: HashMap<EntityId, Handlers>, pub(crate) observers: SubscriberSet<EntityId, Handler>,
pub(crate) event_handlers: HashMap<EntityId, EventHandlers>, pub(crate) event_handlers: SubscriberSet<EntityId, EventHandler>,
pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests. pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
} }
@ -176,23 +175,15 @@ impl AppContext {
} }
fn apply_notify_effect(&mut self, updated_entity: EntityId) { fn apply_notify_effect(&mut self, updated_entity: EntityId) {
if let Some(mut handlers) = self.observers.remove(&updated_entity) { self.observers
handlers.retain(|handler| handler(self)); .clone()
if let Some(new_handlers) = self.observers.remove(&updated_entity) { .retain(&updated_entity, |handler| handler(self));
handlers.extend(new_handlers);
}
self.observers.insert(updated_entity, handlers);
}
} }
fn apply_emit_effect(&mut self, updated_entity: EntityId, event: Box<dyn Any>) { fn apply_emit_effect(&mut self, updated_entity: EntityId, event: Box<dyn Any>) {
if let Some(mut handlers) = self.event_handlers.remove(&updated_entity) { self.event_handlers
handlers.retain(|handler| handler(&event, self)); .clone()
if let Some(new_handlers) = self.event_handlers.remove(&updated_entity) { .retain(&updated_entity, |handler| handler(&event, self));
handlers.extend(new_handlers);
}
self.event_handlers.insert(updated_entity, handlers);
}
} }
pub fn to_async(&self) -> AsyncAppContext { pub fn to_async(&self) -> AsyncAppContext {

View file

@ -1,4 +1,7 @@
use crate::{AppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, WeakHandle}; use crate::{
AppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, Subscription,
WeakHandle,
};
use std::{marker::PhantomData, sync::Arc}; use std::{marker::PhantomData, sync::Arc};
pub struct ModelContext<'a, T> { pub struct ModelContext<'a, T> {
@ -42,21 +45,20 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
&mut self, &mut self,
handle: &Handle<E>, handle: &Handle<E>,
on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static, on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
) { ) -> Subscription {
let this = self.handle(); let this = self.handle();
let handle = handle.downgrade(); let handle = handle.downgrade();
self.app self.app.observers.insert(
.observers handle.id,
.entry(handle.id) Arc::new(move |cx| {
.or_default()
.push(Arc::new(move |cx| {
if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) { if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
this.update(cx, |this, cx| on_notify(this, handle, cx)); this.update(cx, |this, cx| on_notify(this, handle, cx));
true true
} else { } else {
false false
} }
})); }),
)
} }
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>( pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
@ -66,14 +68,12 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
+ Send + Send
+ Sync + Sync
+ 'static, + 'static,
) { ) -> Subscription {
let this = self.handle(); let this = self.handle();
let handle = handle.downgrade(); let handle = handle.downgrade();
self.app self.app.event_handlers.insert(
.event_handlers handle.id,
.entry(handle.id) Arc::new(move |event, cx| {
.or_default()
.push(Arc::new(move |event, cx| {
let event = event.downcast_ref().expect("invalid event type"); let event = event.downcast_ref().expect("invalid event type");
if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) { if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
this.update(cx, |this, cx| on_event(this, handle, event, cx)); this.update(cx, |this, cx| on_event(this, handle, event, cx));
@ -81,7 +81,8 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
} else { } else {
false false
} }
})); }),
)
} }
pub fn notify(&mut self) { pub fn notify(&mut self) {

View file

@ -13,6 +13,7 @@ mod scene;
mod style; mod style;
mod style_helpers; mod style_helpers;
mod styled; mod styled;
mod subscription;
mod svg_renderer; mod svg_renderer;
mod taffy; mod taffy;
mod text_system; mod text_system;
@ -42,6 +43,7 @@ pub use smol::Timer;
pub use style::*; pub use style::*;
pub use style_helpers::*; pub use style_helpers::*;
pub use styled::*; pub use styled::*;
pub use subscription::*;
pub use svg_renderer::*; pub use svg_renderer::*;
pub use taffy::{AvailableSpace, LayoutId}; pub use taffy::{AvailableSpace, LayoutId};
pub use text_system::*; pub use text_system::*;

View file

@ -0,0 +1,103 @@
use collections::{BTreeMap, BTreeSet};
use parking_lot::Mutex;
use std::{fmt::Debug, mem, sync::Arc};
use util::post_inc;
#[derive(Clone)]
pub(crate) struct SubscriberSet<EmitterKey, Callback>(
Arc<Mutex<SubscriberSetState<EmitterKey, Callback>>>,
);
struct SubscriberSetState<EmitterKey, Callback> {
subscribers: BTreeMap<EmitterKey, BTreeMap<usize, Callback>>,
dropped_subscribers: BTreeSet<(EmitterKey, usize)>,
next_subscriber_id: usize,
}
impl<EmitterKey, Callback> SubscriberSet<EmitterKey, Callback>
where
EmitterKey: 'static + Ord + Clone + Debug,
Callback: 'static,
{
pub fn new() -> Self {
Self(Arc::new(Mutex::new(SubscriberSetState {
subscribers: Default::default(),
dropped_subscribers: Default::default(),
next_subscriber_id: 0,
})))
}
pub fn insert(&self, emitter: EmitterKey, callback: Callback) -> Subscription {
let mut lock = self.0.lock();
let subscriber_id = post_inc(&mut lock.next_subscriber_id);
lock.subscribers
.entry(emitter.clone())
.or_default()
.insert(subscriber_id, callback);
let this = self.0.clone();
Subscription {
unsubscribe: Some(Box::new(move || {
let mut lock = this.lock();
if let Some(subscribers) = lock.subscribers.get_mut(&emitter) {
subscribers.remove(&subscriber_id);
if subscribers.is_empty() {
lock.subscribers.remove(&emitter);
return;
}
}
// We didn't manage to remove the subscription, which means it was dropped
// while invoking the callback. Mark it as dropped so that we can remove it
// later.
lock.dropped_subscribers.insert((emitter, subscriber_id));
})),
}
}
pub fn retain<F>(&self, emitter: &EmitterKey, mut f: F)
where
F: FnMut(&mut Callback) -> bool,
{
let entry = self.0.lock().subscribers.remove_entry(emitter);
if let Some((emitter, mut subscribers)) = entry {
subscribers.retain(|_, callback| f(callback));
let mut lock = self.0.lock();
// Add any new subscribers that were added while invoking the callback.
if let Some(new_subscribers) = lock.subscribers.remove(&emitter) {
subscribers.extend(new_subscribers);
}
// Remove any dropped subscriptions that were dropped while invoking the callback.
for (dropped_emitter, dropped_subscription_id) in
mem::take(&mut lock.dropped_subscribers)
{
debug_assert_eq!(emitter, dropped_emitter);
subscribers.remove(&dropped_subscription_id);
}
if !subscribers.is_empty() {
lock.subscribers.insert(emitter, subscribers);
}
}
}
}
#[must_use]
pub struct Subscription {
unsubscribe: Option<Box<dyn FnOnce()>>,
}
impl Subscription {
pub fn detach(mut self) {
self.unsubscribe.take();
}
}
impl Drop for Subscription {
fn drop(&mut self) {
if let Some(unsubscribe) = self.unsubscribe.take() {
unsubscribe();
}
}
}

View file

@ -5,8 +5,8 @@ use crate::{
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels,
PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions, Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle,
SUBPIXEL_VARIANTS, WindowOptions, SUBPIXEL_VARIANTS,
}; };
use anyhow::Result; use anyhow::Result;
use collections::HashMap; use collections::HashMap;
@ -903,15 +903,13 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
&mut self, &mut self,
handle: &Handle<E>, handle: &Handle<E>,
on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static, on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
) { ) -> Subscription {
let this = self.handle(); let this = self.handle();
let handle = handle.downgrade(); let handle = handle.downgrade();
let window_handle = self.window.handle; let window_handle = self.window.handle;
self.app self.app.observers.insert(
.observers handle.id,
.entry(handle.id) Arc::new(move |cx| {
.or_default()
.push(Arc::new(move |cx| {
cx.update_window(window_handle.id, |cx| { cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade(cx) { if let Some(handle) = handle.upgrade(cx) {
this.update(cx, |this, cx| on_notify(this, handle, cx)) this.update(cx, |this, cx| on_notify(this, handle, cx))
@ -921,7 +919,8 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
} }
}) })
.unwrap_or(false) .unwrap_or(false)
})); }),
)
} }
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>( pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
@ -931,15 +930,13 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
+ Send + Send
+ Sync + Sync
+ 'static, + 'static,
) { ) -> Subscription {
let this = self.handle(); let this = self.handle();
let handle = handle.downgrade(); let handle = handle.downgrade();
let window_handle = self.window.handle; let window_handle = self.window.handle;
self.app self.app.event_handlers.insert(
.event_handlers handle.id,
.entry(handle.id) Arc::new(move |event, cx| {
.or_default()
.push(Arc::new(move |event, cx| {
cx.update_window(window_handle.id, |cx| { cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade(cx) { if let Some(handle) = handle.upgrade(cx) {
let event = event.downcast_ref().expect("invalid event type"); let event = event.downcast_ref().expect("invalid event type");
@ -950,7 +947,8 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
} }
}) })
.unwrap_or(false) .unwrap_or(false)
})); }),
)
} }
pub fn notify(&mut self) { pub fn notify(&mut self) {