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::{
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor, LayoutId,
MainThread, MainThreadOnly, Platform, PlatformDisplayLinker, RootView, SvgRenderer, Task,
TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
MainThread, MainThreadOnly, Platform, PlatformDisplayLinker, RootView, SubscriberSet,
SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext,
WindowHandle, WindowId,
};
use anyhow::{anyhow, Result};
use collections::{HashMap, VecDeque};
use futures::Future;
use parking_lot::Mutex;
use slotmap::SlotMap;
use smallvec::SmallVec;
use std::{
any::{type_name, Any, TypeId},
mem,
@ -67,8 +67,8 @@ impl App {
entities,
windows: SlotMap::with_key(),
pending_effects: Default::default(),
observers: Default::default(),
event_handlers: Default::default(),
observers: SubscriberSet::new(),
event_handlers: SubscriberSet::new(),
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 EventHandlers =
SmallVec<[Arc<dyn Fn(&dyn Any, &mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
type Handler = Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>;
type EventHandler = Arc<dyn Fn(&dyn Any, &mut AppContext) -> bool + Send + Sync + 'static>;
type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
pub struct AppContext {
@ -109,8 +108,8 @@ pub struct AppContext {
pub(crate) entities: EntityMap,
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
pub(crate) pending_effects: VecDeque<Effect>,
pub(crate) observers: HashMap<EntityId, Handlers>,
pub(crate) event_handlers: HashMap<EntityId, EventHandlers>,
pub(crate) observers: SubscriberSet<EntityId, Handler>,
pub(crate) event_handlers: SubscriberSet<EntityId, EventHandler>,
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) {
if let Some(mut handlers) = self.observers.remove(&updated_entity) {
handlers.retain(|handler| handler(self));
if let Some(new_handlers) = self.observers.remove(&updated_entity) {
handlers.extend(new_handlers);
}
self.observers.insert(updated_entity, handlers);
}
self.observers
.clone()
.retain(&updated_entity, |handler| handler(self));
}
fn apply_emit_effect(&mut self, updated_entity: EntityId, event: Box<dyn Any>) {
if let Some(mut handlers) = self.event_handlers.remove(&updated_entity) {
handlers.retain(|handler| handler(&event, self));
if let Some(new_handlers) = self.event_handlers.remove(&updated_entity) {
handlers.extend(new_handlers);
}
self.event_handlers.insert(updated_entity, handlers);
}
self.event_handlers
.clone()
.retain(&updated_entity, |handler| handler(&event, self));
}
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};
pub struct ModelContext<'a, T> {
@ -42,21 +45,20 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
&mut self,
handle: &Handle<E>,
on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
) {
) -> Subscription {
let this = self.handle();
let handle = handle.downgrade();
self.app
.observers
.entry(handle.id)
.or_default()
.push(Arc::new(move |cx| {
self.app.observers.insert(
handle.id,
Arc::new(move |cx| {
if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
this.update(cx, |this, cx| on_notify(this, handle, cx));
true
} else {
false
}
}));
}),
)
}
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
@ -66,14 +68,12 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
+ Send
+ Sync
+ 'static,
) {
) -> Subscription {
let this = self.handle();
let handle = handle.downgrade();
self.app
.event_handlers
.entry(handle.id)
.or_default()
.push(Arc::new(move |event, cx| {
self.app.event_handlers.insert(
handle.id,
Arc::new(move |event, cx| {
let event = event.downcast_ref().expect("invalid event type");
if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(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 {
false
}
}));
}),
)
}
pub fn notify(&mut self) {

View file

@ -13,6 +13,7 @@ mod scene;
mod style;
mod style_helpers;
mod styled;
mod subscription;
mod svg_renderer;
mod taffy;
mod text_system;
@ -42,6 +43,7 @@ pub use smol::Timer;
pub use style::*;
pub use style_helpers::*;
pub use styled::*;
pub use subscription::*;
pub use svg_renderer::*;
pub use taffy::{AvailableSpace, LayoutId};
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,
PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
SUBPIXEL_VARIANTS,
Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle,
WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::Result;
use collections::HashMap;
@ -903,15 +903,13 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
&mut self,
handle: &Handle<E>,
on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
) {
) -> Subscription {
let this = self.handle();
let handle = handle.downgrade();
let window_handle = self.window.handle;
self.app
.observers
.entry(handle.id)
.or_default()
.push(Arc::new(move |cx| {
self.app.observers.insert(
handle.id,
Arc::new(move |cx| {
cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade(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)
}));
}),
)
}
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
@ -931,15 +930,13 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
+ Send
+ Sync
+ 'static,
) {
) -> Subscription {
let this = self.handle();
let handle = handle.downgrade();
let window_handle = self.window.handle;
self.app
.event_handlers
.entry(handle.id)
.or_default()
.push(Arc::new(move |event, cx| {
self.app.event_handlers.insert(
handle.id,
Arc::new(move |event, cx| {
cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade(cx) {
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)
}));
}),
)
}
pub fn notify(&mut self) {