From 2257abd7dd89493c2e4f2001c789b28439764959 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 25 Jun 2021 10:35:06 -0600 Subject: [PATCH] Add Entity release hooks Co-Authored-By: Max Brunsfeld --- gpui/src/app.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 8 deletions(-) diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 809776e32a9dd91be42ee1785cd04ca3976d0734..8517d45f717da4ef8d6af54e8e28017e63b9feab 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -30,6 +30,8 @@ use std::{ pub trait Entity: 'static + Send + Sync { type Event; + + fn release(&mut self, _: &mut MutableAppContext) {} } pub trait View: Entity { @@ -374,8 +376,8 @@ impl TestAppContext { self.cx.borrow().foreground().clone() } - pub fn background_executor(&self) -> Arc { - self.cx.borrow().background_executor().clone() + pub fn background(&self) -> Arc { + self.cx.borrow().background().clone() } pub fn simulate_new_path_selection(&self, result: impl FnOnce(PathBuf) -> Option) { @@ -429,7 +431,7 @@ impl AsyncAppContext { self.0.borrow().platform() } - pub fn background_executor(&self) -> Arc { + pub fn background(&self) -> Arc { self.0.borrow().cx.background.clone() } } @@ -622,7 +624,7 @@ impl MutableAppContext { &self.foreground } - pub fn background_executor(&self) -> &Arc { + pub fn background(&self) -> &Arc { &self.cx.background } @@ -1087,15 +1089,17 @@ impl MutableAppContext { } for model_id in dropped_models { - self.cx.models.remove(&model_id); self.subscriptions.remove(&model_id); self.model_observations.remove(&model_id); + let mut model = self.cx.models.remove(&model_id).unwrap(); + model.release(self); } for (window_id, view_id) in dropped_views { self.subscriptions.remove(&view_id); self.model_observations.remove(&view_id); - self.cx.views.remove(&(window_id, view_id)); + let mut view = self.cx.views.remove(&(window_id, view_id)).unwrap(); + view.release(self); let change_focus_to = self.cx.windows.get_mut(&window_id).and_then(|window| { window .invalidation @@ -1496,7 +1500,7 @@ impl AppContext { .collect::>() } - pub fn background_executor(&self) -> &Arc { + pub fn background(&self) -> &Arc { &self.background } @@ -1574,6 +1578,7 @@ pub enum Effect { pub trait AnyModel: Send + Sync { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; + fn release(&mut self, cx: &mut MutableAppContext); } impl AnyModel for T @@ -1587,11 +1592,16 @@ where fn as_any_mut(&mut self) -> &mut dyn Any { self } + + fn release(&mut self, cx: &mut MutableAppContext) { + self.release(cx); + } } pub trait AnyView: Send + Sync { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; + fn release(&mut self, cx: &mut MutableAppContext); fn ui_name(&self) -> &'static str; fn render<'a>(&self, cx: &AppContext) -> ElementBox; fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize); @@ -1611,6 +1621,10 @@ where self } + fn release(&mut self, cx: &mut MutableAppContext) { + self.release(cx); + } + fn ui_name(&self) -> &'static str { T::ui_name() } @@ -1651,7 +1665,7 @@ impl<'a, T: Entity> ModelContext<'a, T> { } } - pub fn background_executor(&self) -> &Arc { + pub fn background(&self) -> &Arc { &self.app.cx.background } @@ -2949,6 +2963,65 @@ mod tests { assert!(cx.model_observations.is_empty()); } + #[crate::test(self)] + fn test_entity_release_hooks(cx: &mut MutableAppContext) { + struct Model { + released: Arc>, + } + + struct View { + released: Arc>, + } + + impl Entity for Model { + type Event = (); + + fn release(&mut self, _: &mut MutableAppContext) { + *self.released.lock() = true; + } + } + + impl Entity for View { + type Event = (); + + fn release(&mut self, _: &mut MutableAppContext) { + *self.released.lock() = true; + } + } + + impl super::View for View { + fn ui_name() -> &'static str { + "View" + } + + fn render<'a>(&self, _: &AppContext) -> ElementBox { + Empty::new().boxed() + } + } + + let model_released = Arc::new(Mutex::new(false)); + let view_released = Arc::new(Mutex::new(false)); + + let model = cx.add_model(|_| Model { + released: model_released.clone(), + }); + + let (window_id, _) = cx.add_window(|_| View { + released: view_released.clone(), + }); + + assert!(!*model_released.lock()); + assert!(!*view_released.lock()); + + cx.update(move || { + drop(model); + }); + assert!(*model_released.lock()); + + drop(cx.remove_window(window_id)); + assert!(*view_released.lock()); + } + #[crate::test(self)] fn test_subscribe_and_emit_from_view(cx: &mut MutableAppContext) { #[derive(Default)]