diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 182d56b3c28a623af5c52651d16b69c84ead3154..85cd865f2b827a73cc03f91a6fc1a59b72469f32 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -60,10 +60,6 @@ pub trait View: Entity + Sized { } } -pub trait Delegator: Entity { - type Delegation; -} - pub trait ReadModel { fn read_model(&self, handle: &ModelHandle) -> &T; } @@ -1156,34 +1152,32 @@ impl MutableAppContext { } } - pub fn become_delegate_internal(&mut self, handle: &H, mut callback: F) -> Subscription + fn become_delegate_internal(&mut self, handle: &H, mut callback: F) -> Subscription where E: Entity, - E::Event: 'static, H: Handle, - F: 'static + FnMut(H, &E::Event, &mut Self) -> bool, + F: 'static + FnMut(H, E::Event, &mut Self) -> bool, { let id = post_inc(&mut self.next_subscription_id); let emitter = handle.downgrade(); - self.subscriptions - .lock() - .entry(handle.id()) - .or_default() - .insert( + self.delegations.lock().insert( + handle.id(), + ( id, Box::new(move |payload, cx| { if let Some(emitter) = H::upgrade_from(&emitter, cx.as_ref()) { - let payload = payload.downcast_ref().expect("downcast is type safe"); + let payload = *payload.downcast().expect("downcast is type safe"); callback(emitter, payload, cx) } else { false } }), - ); - Subscription::Subscription { + ), + ); + Subscription::Delegation { id, entity_id: handle.id(), - subscriptions: Some(Arc::downgrade(&self.subscriptions)), + delegations: Some(Arc::downgrade(&self.delegations)), } } @@ -1726,6 +1720,17 @@ impl MutableAppContext { } } } + + let delegate = self.delegations.lock().remove(&entity_id); + if let Some((id, mut callback)) = delegate { + let alive = callback(payload, self); + if alive { + self.delegations + .lock() + .entry(entity_id) + .or_insert_with(|| (id, callback)); + } + } } fn notify_model_observers(&mut self, observed_id: usize) { @@ -2363,6 +2368,26 @@ impl<'a, T: Entity> ModelContext<'a, T> { }) } + pub fn become_delegate(&mut self, handle: &H, mut callback: F) -> Subscription + where + E: Entity, + H: Handle, + F: 'static + FnMut(&mut T, H, E::Event, &mut ModelContext), + { + let delegate = self.weak_handle(); + self.app + .become_delegate_internal(handle, move |emitter, event, cx| { + if let Some(delegate) = delegate.upgrade(cx) { + delegate.update(cx, |subscriber, cx| { + callback(subscriber, emitter, event, cx); + }); + true + } else { + false + } + }) + } + pub fn observe_release( &mut self, handle: &ModelHandle, @@ -2630,23 +2655,22 @@ impl<'a, T: View> ViewContext<'a, T> { pub fn become_delegate(&mut self, handle: &H, mut callback: F) -> Subscription where - E: Delegator, - E::Event: 'static, + E: Entity, H: Handle, F: 'static + FnMut(&mut T, H, E::Event, &mut ViewContext), { - // let subscriber = self.weak_handle(); - // self.app - // .subscribe_internal(handle, move |emitter, event, cx| { - // if let Some(subscriber) = subscriber.upgrade(cx) { - // subscriber.update(cx, |subscriber, cx| { - // callback(subscriber, emitter, event, cx); - // }); - // true - // } else { - // false - // } - // }) + let delegate = self.weak_handle(); + self.app + .become_delegate_internal(handle, move |emitter, event, cx| { + if let Some(delegate) = delegate.upgrade(cx) { + delegate.update(cx, |subscriber, cx| { + callback(subscriber, emitter, event, cx); + }); + true + } else { + false + } + }) } pub fn observe_release(&mut self, handle: &H, mut callback: F) -> Subscription @@ -3802,6 +3826,11 @@ pub enum Subscription { entity_id: usize, subscriptions: Option>>>>, }, + Delegation { + id: usize, + entity_id: usize, + delegations: Option>>>, + }, Observation { id: usize, entity_id: usize, @@ -3821,6 +3850,9 @@ impl Subscription { Subscription::Subscription { subscriptions, .. } => { subscriptions.take(); } + Subscription::Delegation { delegations, .. } => { + delegations.take(); + } Subscription::Observation { observations, .. } => { observations.take(); } @@ -3867,6 +3899,19 @@ impl Drop for Subscription { } } } + Subscription::Delegation { + id, + entity_id, + delegations, + } => { + if let Some(delegations) = delegations.as_ref().and_then(Weak::upgrade) { + if let Entry::Occupied(entry) = delegations.lock().entry(*entity_id) { + if *id == entry.get().0 { + let _ = entry.remove(); + } + } + } + } } } } @@ -4120,7 +4165,7 @@ mod tests { } #[crate::test(self)] - fn test_subscribe_and_emit_from_model(cx: &mut MutableAppContext) { + fn test_model_events(cx: &mut MutableAppContext) { #[derive(Default)] struct Model { events: Vec, @@ -4132,11 +4177,16 @@ mod tests { let handle_1 = cx.add_model(|_| Model::default()); let handle_2 = cx.add_model(|_| Model::default()); - handle_1.update(cx, |_, c| { - c.subscribe(&handle_2, move |model: &mut Model, emitter, event, c| { + handle_1.update(cx, |_, cx| { + cx.become_delegate(&handle_2, |model, _, event, _| { + model.events.push(event * 3); + }) + .detach(); + + cx.subscribe(&handle_2, move |model: &mut Model, emitter, event, cx| { model.events.push(*event); - c.subscribe(&emitter, |model, _, event, _| { + cx.subscribe(&emitter, |model, _, event, _| { model.events.push(*event * 2); }) .detach(); @@ -4145,10 +4195,10 @@ mod tests { }); handle_2.update(cx, |_, c| c.emit(7)); - assert_eq!(handle_1.read(cx).events, vec![7]); + assert_eq!(handle_1.read(cx).events, vec![7, 21]); handle_2.update(cx, |_, c| c.emit(5)); - assert_eq!(handle_1.read(cx).events, vec![7, 5, 10]); + assert_eq!(handle_1.read(cx).events, vec![7, 21, 5, 10, 15]); } #[crate::test(self)] @@ -4375,7 +4425,7 @@ mod tests { } #[crate::test(self)] - fn test_subscribe_and_emit_from_view(cx: &mut MutableAppContext) { + fn test_view_events(cx: &mut MutableAppContext) { #[derive(Default)] struct View { events: Vec, @@ -4405,31 +4455,36 @@ mod tests { let handle_2 = cx.add_view(window_id, |_| View::default()); let handle_3 = cx.add_model(|_| Model); - handle_1.update(cx, |_, c| { - c.subscribe(&handle_2, move |me, emitter, event, c| { + handle_1.update(cx, |_, cx| { + cx.become_delegate(&handle_2, |me, _, event, _| { + me.events.push(event * 3); + }) + .detach(); + + cx.subscribe(&handle_2, move |me, emitter, event, cx| { me.events.push(*event); - c.subscribe(&emitter, |me, _, event, _| { + cx.subscribe(&emitter, |me, _, event, _| { me.events.push(*event * 2); }) .detach(); }) .detach(); - c.subscribe(&handle_3, |me, _, event, _| { + cx.subscribe(&handle_3, |me, _, event, _| { me.events.push(*event); }) .detach(); }); handle_2.update(cx, |_, c| c.emit(7)); - assert_eq!(handle_1.read(cx).events, vec![7]); + assert_eq!(handle_1.read(cx).events, vec![7, 21]); handle_2.update(cx, |_, c| c.emit(5)); - assert_eq!(handle_1.read(cx).events, vec![7, 5, 10]); + assert_eq!(handle_1.read(cx).events, vec![7, 21, 5, 10, 15]); handle_3.update(cx, |_, c| c.emit(9)); - assert_eq!(handle_1.read(cx).events, vec![7, 5, 10, 9]); + assert_eq!(handle_1.read(cx).events, vec![7, 21, 5, 10, 15, 9]); } #[crate::test(self)]