From 26fc36ee0e47da3097ab9429bd58685f4d4afa91 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 8 Nov 2023 16:34:38 -0800 Subject: [PATCH] First pass at allowing multiple event types to be emitted by an entity --- crates/gpui2/src/app.rs | 54 +++++++++----- crates/gpui2/src/app/model_context.rs | 19 +++-- crates/gpui2/src/app/test_context.rs | 13 ++-- crates/gpui2/src/gpui2.rs | 6 +- crates/gpui2/src/subscription.rs | 2 + crates/gpui2/src/window.rs | 103 ++++++++++++++++---------- 6 files changed, 123 insertions(+), 74 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 8fa70d9c9e0c4ef71c86afaf7186d8bc643e460f..9673f946a8623cae364130ef354bd1fec07205eb 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -201,7 +201,8 @@ pub struct AppContext { pub(crate) pending_notifications: HashSet, pub(crate) pending_global_notifications: HashSet, pub(crate) observers: SubscriberSet, - pub(crate) event_listeners: SubscriberSet, + // (Entity, Event Type) + pub(crate) event_listeners: SubscriberSet, pub(crate) release_listeners: SubscriberSet, pub(crate) global_observers: SubscriberSet, pub(crate) quit_observers: SubscriberSet<(), QuitHandler>, @@ -351,14 +352,15 @@ impl AppContext { ) } - pub fn subscribe( + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(E, &T::Event, &mut AppContext) + 'static, + mut on_event: impl FnMut(E, &Evt, &mut AppContext) + 'static, ) -> Subscription where - T: 'static + EventEmitter, + T: 'static + EventEmitter, E: Entity, + Evt: 'static, { self.subscribe_internal(entity, move |entity, event, cx| { on_event(entity, event, cx); @@ -366,27 +368,32 @@ impl AppContext { }) } - pub(crate) fn subscribe_internal( + pub(crate) fn subscribe_internal( &mut self, entity: &E, - mut on_event: impl FnMut(E, &T::Event, &mut AppContext) -> bool + 'static, + mut on_event: impl FnMut(E, &Evt, &mut AppContext) -> bool + 'static, ) -> Subscription where - T: 'static + EventEmitter, + T: 'static + EventEmitter, E: Entity, + Evt: 'static, { let entity_id = entity.entity_id(); let entity = entity.downgrade(); + self.event_listeners.insert( entity_id, - Box::new(move |event, cx| { - let event: &T::Event = event.downcast_ref().expect("invalid event type"); - if let Some(handle) = E::upgrade_from(&entity) { - on_event(handle, event, cx) - } else { - false - } - }), + ( + TypeId::of::(), + Box::new(move |event, cx| { + let event: &Evt = event.downcast_ref().expect("invalid event type"); + if let Some(handle) = E::upgrade_from(&entity) { + on_event(handle, event, cx) + } else { + false + } + }), + ), ) } @@ -509,7 +516,11 @@ impl AppContext { Effect::Notify { emitter } => { self.apply_notify_effect(emitter); } - Effect::Emit { emitter, event } => self.apply_emit_effect(emitter, event), + Effect::Emit { + emitter, + event_type, + event, + } => self.apply_emit_effect(emitter, event_type, event), Effect::FocusChanged { window_handle, focused, @@ -604,10 +615,16 @@ impl AppContext { .retain(&emitter, |handler| handler(self)); } - fn apply_emit_effect(&mut self, emitter: EntityId, event: Box) { + fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: Box) { self.event_listeners .clone() - .retain(&emitter, |handler| handler(event.as_ref(), self)); + .retain(&emitter, |(stored_type, handler)| { + if *stored_type == event_type { + handler(event.as_ref(), self) + } else { + true + } + }); } fn apply_focus_changed_effect( @@ -978,6 +995,7 @@ pub(crate) enum Effect { }, Emit { emitter: EntityId, + event_type: TypeId, event: Box, }, FocusChanged { diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 35d41ab362989d27ed00d99e13bb557702d43862..44a3337f0321d926d21934864e18377214287b37 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -59,15 +59,16 @@ impl<'a, T: 'static> ModelContext<'a, T> { }) } - pub fn subscribe( + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(&mut T, E, &T2::Event, &mut ModelContext<'_, T>) + 'static, + mut on_event: impl FnMut(&mut T, E, &Evt, &mut ModelContext<'_, T>) + 'static, ) -> Subscription where T: 'static, - T2: 'static + EventEmitter, + T2: 'static + EventEmitter, E: Entity, + Evt: 'static, { let this = self.weak_model(); self.app.subscribe_internal(entity, move |e, event, cx| { @@ -189,13 +190,15 @@ impl<'a, T: 'static> ModelContext<'a, T> { } } -impl<'a, T> ModelContext<'a, T> -where - T: EventEmitter, -{ - pub fn emit(&mut self, event: T::Event) { +impl<'a, T> ModelContext<'a, T> { + pub fn emit(&mut self, event: Evt) + where + T: EventEmitter, + Evt: 'static, + { self.app.pending_effects.push_back(Effect::Emit { emitter: self.model_state.entity_id, + event_type: TypeId::of::(), event: Box::new(event), }); } diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index eb5ce283a570123d059d5fa52249abc6e5037097..7b5ab5f7d76dc728556d66925dc67ca086c37893 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -197,12 +197,12 @@ impl TestAppContext { rx } - pub fn events( + pub fn events>( &mut self, entity: &Model, - ) -> futures::channel::mpsc::UnboundedReceiver + ) -> futures::channel::mpsc::UnboundedReceiver where - T::Event: 'static + Clone, + Evt: 'static + Clone, { let (tx, rx) = futures::channel::mpsc::unbounded(); entity @@ -240,10 +240,11 @@ impl TestAppContext { } } -impl Model { - pub fn next_event(&self, cx: &mut TestAppContext) -> T::Event +impl Model { + pub fn next_event(&self, cx: &mut TestAppContext) -> Evt where - T::Event: Send + Clone, + Evt: Send + Clone + 'static, + T: EventEmitter, { let (tx, mut rx) = futures::channel::mpsc::unbounded(); let _subscription = self.update(cx, |_, cx| { diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index e253872ed4b8f0ba1e3c375c480b6ecad6bd87ec..71ea77bd634e0ba3f5f99c37f78c951eff0b3441 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -138,6 +138,8 @@ pub trait Entity: Sealed { Self: Sized; } +pub trait EventEmitter: 'static {} + pub enum GlobalKey { Numeric(usize), View(EntityId), @@ -171,10 +173,6 @@ where } } -pub trait EventEmitter: 'static { - type Event: Any; -} - pub trait Flatten { fn flatten(self) -> Result; } diff --git a/crates/gpui2/src/subscription.rs b/crates/gpui2/src/subscription.rs index 2f4ec0d2f13212440fe7d23585781bac7b2be069..7cb023a9074094b27d16b6effa27c68b967f30c8 100644 --- a/crates/gpui2/src/subscription.rs +++ b/crates/gpui2/src/subscription.rs @@ -75,6 +75,8 @@ where .flatten() } + /// Call the given callback for each subscriber to the given emitter. + /// If the callback returns false, the subscriber is removed. pub fn retain(&self, emitter: &EmitterKey, mut f: F) where F: FnMut(&mut Callback) -> bool, diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index fbaeae322b7180bd52f808ad9801998138bb895d..0392c0e83cb1d8af76f54141dbbcf3680203f4de 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -439,33 +439,37 @@ impl<'a> WindowContext<'a> { }); } - pub fn subscribe( + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(E, &Emitter::Event, &mut WindowContext<'_>) + 'static, + mut on_event: impl FnMut(E, &Evt, &mut WindowContext<'_>) + 'static, ) -> Subscription where - Emitter: EventEmitter, + Emitter: EventEmitter, E: Entity, + Evt: 'static, { let entity_id = entity.entity_id(); let entity = entity.downgrade(); let window_handle = self.window.handle; self.app.event_listeners.insert( entity_id, - Box::new(move |event, cx| { - window_handle - .update(cx, |_, cx| { - if let Some(handle) = E::upgrade_from(&entity) { - let event = event.downcast_ref().expect("invalid event type"); - on_event(handle, event, cx); - true - } else { - false - } - }) - .unwrap_or(false) - }), + ( + TypeId::of::(), + Box::new(move |event, cx| { + window_handle + .update(cx, |_, cx| { + if let Some(handle) = E::upgrade_from(&entity) { + let event = event.downcast_ref().expect("invalid event type"); + on_event(handle, event, cx); + true + } else { + false + } + }) + .unwrap_or(false) + }), + ), ) } @@ -1809,14 +1813,33 @@ impl<'a, V: 'static> ViewContext<'a, V> { ) } - pub fn subscribe( + // Options for simplifying this new event API: + // + // - Make a new stlye of API which does partial application of the arguments to capture + // the types involved e.g. + // `cx.for_entity(handle).subscribe::(..)` + // + // - Make it so there are less types: + // - Bail on this idea all together, go back to associated types. + // causes our event enums to be a blob of anything that could happen ever, and + // makes applications have some translation boilerplate + // + // - Move some of the types into the method names, + // `cx.subscribe_model::<_, ItemEvents>(handle)` + // + // - Do something drastic like removing views and models, or removing the multiple + // kind of contexts. (Not going to happen, we already tried this before.) + // + // - Accept it, and use `cx.subscribe::<_, _, ItemEvents>(handle, ...)` + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(&mut V, E, &V2::Event, &mut ViewContext<'_, V>) + 'static, + mut on_event: impl FnMut(&mut V, E, &Evt, &mut ViewContext<'_, V>) + 'static, ) -> Subscription where - V2: EventEmitter, + V2: EventEmitter, E: Entity, + Evt: 'static, { let view = self.view().downgrade(); let entity_id = entity.entity_id(); @@ -1824,19 +1847,22 @@ impl<'a, V: 'static> ViewContext<'a, V> { let window_handle = self.window.handle; self.app.event_listeners.insert( entity_id, - Box::new(move |event, cx| { - window_handle - .update(cx, |_, cx| { - if let Some(handle) = E::upgrade_from(&handle) { - let event = event.downcast_ref().expect("invalid event type"); - view.update(cx, |this, cx| on_event(this, handle, event, cx)) - .is_ok() - } else { - false - } - }) - .unwrap_or(false) - }), + ( + TypeId::of::(), + Box::new(move |event, cx| { + window_handle + .update(cx, |_, cx| { + if let Some(handle) = E::upgrade_from(&handle) { + let event = event.downcast_ref().expect("invalid event type"); + view.update(cx, |this, cx| on_event(this, handle, event, cx)) + .is_ok() + } else { + false + } + }) + .unwrap_or(false) + }), + ), ) } @@ -2181,15 +2207,16 @@ where } } -impl ViewContext<'_, V> -where - V: EventEmitter, - V::Event: 'static, -{ - pub fn emit(&mut self, event: V::Event) { +impl ViewContext<'_, V> { + pub fn emit(&mut self, event: Evt) + where + Evt: 'static, + V: EventEmitter, + { let emitter = self.view.model.entity_id; self.app.push_effect(Effect::Emit { emitter, + event_type: TypeId::of::(), event: Box::new(event), }); }