From 2970e934da2cb823cc59834ca25993fdc2257e4d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 5 Apr 2021 20:04:04 -0600 Subject: [PATCH] Use handles to obtain entities in future callbacks This guarantees that the spawning entity will be present and simplifies the logic for obtaining the entity. Now we can forward the results of spawned futures and streams in the same way regardless of whether what spawned them was a model or a view. --- gpui/src/app.rs | 319 +++++++++------------------------- zed/src/editor/buffer_view.rs | 2 +- zed/src/file_finder.rs | 2 +- 3 files changed, 83 insertions(+), 240 deletions(-) diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 125f749c53..20560fe6fe 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -967,7 +967,7 @@ impl MutableAppContext { self.flush_effects(); } - fn spawn(&mut self, future: F) -> EntityTask> + fn spawn(&mut self, future: F) -> EntityTask where F: 'static + Future, T: 'static, @@ -978,9 +978,10 @@ impl MutableAppContext { let app = app.clone(); self.foreground.spawn(async move { let output = future.await; - app.borrow_mut() + *app.borrow_mut() .handle_future_output(task_id, Box::new(output)) - .map(|result| *result.downcast::().unwrap()) + .downcast::() + .unwrap() }) }; EntityTask::new( @@ -991,35 +992,33 @@ impl MutableAppContext { ) } - fn spawn_stream(&mut self, mut stream: F) -> EntityTask> + fn spawn_stream(&mut self, mut stream: F) -> EntityTask where F: 'static + Stream + Unpin, T: 'static, { let task_id = post_inc(&mut self.next_task_id); let app = self.weak_self.as_ref().unwrap().upgrade().unwrap(); - let task = { - let app = app.clone(); - self.foreground.spawn(async move { - loop { - match stream.next().await { - Some(item) => { - let mut app = app.borrow_mut(); - if app.handle_stream_item(task_id, Box::new(item)) { - break; - } - } - None => { + let task = self.foreground.spawn(async move { + loop { + match stream.next().await { + Some(item) => { + let mut app = app.borrow_mut(); + if app.handle_stream_item(task_id, Box::new(item)) { break; } } + None => { + break; + } } + } - app.borrow_mut() - .stream_completed(task_id) - .map(|result| *result.downcast::().unwrap()) - }) - }; + *app.borrow_mut() + .stream_completed(task_id) + .downcast::() + .unwrap() + }); EntityTask::new( task_id, @@ -1029,45 +1028,10 @@ impl MutableAppContext { ) } - fn handle_future_output( - &mut self, - task_id: usize, - output: Box, - ) -> Option> { + fn handle_future_output(&mut self, task_id: usize, output: Box) -> Box { self.pending_flushes += 1; let future_callback = self.future_handlers.borrow_mut().remove(&task_id).unwrap(); - - let mut result = None; - - match future_callback { - FutureHandler::Model { model_id, callback } => { - if let Some(mut model) = self.ctx.models.remove(&model_id) { - result = Some(callback(model.as_any_mut(), output, self, model_id)); - self.ctx.models.insert(model_id, model); - } - } - FutureHandler::View { - window_id, - view_id, - callback, - } => { - if let Some(mut view) = self - .ctx - .windows - .get_mut(&window_id) - .and_then(|w| w.views.remove(&view_id)) - { - result = Some(callback(view.as_mut(), output, self, window_id, view_id)); - self.ctx - .windows - .get_mut(&window_id) - .unwrap() - .views - .insert(view_id, view); - } - } - }; - + let result = future_callback(output, self); self.flush_effects(); self.task_done.notify_all(); result @@ -1077,95 +1041,18 @@ impl MutableAppContext { self.pending_flushes += 1; let mut handler = self.stream_handlers.borrow_mut().remove(&task_id).unwrap(); - let halt = match &mut handler { - StreamHandler::Model { - model_id, - item_callback, - .. - } => { - if let Some(mut model) = self.ctx.models.remove(&model_id) { - let halt = item_callback(model.as_any_mut(), output, self, *model_id); - self.ctx.models.insert(*model_id, model); - self.stream_handlers.borrow_mut().insert(task_id, handler); - halt - } else { - true - } - } - StreamHandler::View { - window_id, - view_id, - item_callback, - .. - } => { - if let Some(mut view) = self - .ctx - .windows - .get_mut(&window_id) - .and_then(|w| w.views.remove(&view_id)) - { - let halt = item_callback(view.as_mut(), output, self, *window_id, *view_id); - self.ctx - .windows - .get_mut(&window_id) - .unwrap() - .views - .insert(*view_id, view); - self.stream_handlers.borrow_mut().insert(task_id, handler); - halt - } else { - true - } - } - }; + let halt = (handler.item_callback)(output, self); + self.stream_handlers.borrow_mut().insert(task_id, handler); self.flush_effects(); halt } - fn stream_completed(&mut self, task_id: usize) -> Option> { + fn stream_completed(&mut self, task_id: usize) -> Box { self.pending_flushes += 1; - let stream_handler = self.stream_handlers.borrow_mut().remove(&task_id).unwrap(); - let result = match stream_handler { - StreamHandler::Model { - model_id, - done_callback, - .. - } => { - if let Some(mut model) = self.ctx.models.remove(&model_id) { - let result = done_callback(model.as_any_mut(), self, model_id); - self.ctx.models.insert(model_id, model); - Some(result) - } else { - None - } - } - StreamHandler::View { - window_id, - view_id, - done_callback, - .. - } => { - if let Some(mut view) = self - .ctx - .windows - .get_mut(&window_id) - .and_then(|w| w.views.remove(&view_id)) - { - let result = done_callback(view.as_mut(), self, window_id, view_id); - self.ctx - .windows - .get_mut(&window_id) - .unwrap() - .views - .insert(view_id, view); - Some(result) - } else { - None - } - } - }; + let handler = self.stream_handlers.borrow_mut().remove(&task_id).unwrap(); + let result = (handler.done_callback)(self); self.flush_effects(); self.task_done.notify_all(); @@ -1562,28 +1449,25 @@ impl<'a, T: Entity> ModelContext<'a, T> { }); } - pub fn spawn(&mut self, future: S, callback: F) -> EntityTask> + fn handle(&self) -> ModelHandle { + ModelHandle::new(self.model_id, &self.app.ctx.ref_counts) + } + + pub fn spawn(&mut self, future: S, callback: F) -> EntityTask where S: 'static + Future, F: 'static + FnOnce(&mut T, S::Output, &mut ModelContext) -> U, U: 'static, { + let handle = self.handle(); let task = self.app.spawn::(future); self.app.future_handlers.borrow_mut().insert( task.id, - FutureHandler::Model { - model_id: self.model_id, - callback: Box::new(move |model, output, app, model_id| { - let model = model.downcast_mut().unwrap(); - let output = *output.downcast().unwrap(); - Box::new(callback( - model, - output, - &mut ModelContext::new(app, model_id), - )) - }), - }, + Box::new(move |output, ctx| { + let output = *output.downcast().unwrap(); + handle.update(ctx, |model, ctx| Box::new(callback(model, output, ctx))) + }), ); task @@ -1594,32 +1478,32 @@ impl<'a, T: Entity> ModelContext<'a, T> { stream: S, mut item_callback: F, done_callback: G, - ) -> EntityTask> + ) -> EntityTask where S: 'static + Stream + Unpin, F: 'static + FnMut(&mut T, S::Item, &mut ModelContext), G: 'static + FnOnce(&mut T, &mut ModelContext) -> U, U: 'static + Any, { + let handle = self.handle(); let task = self.app.spawn_stream(stream); + self.app.stream_handlers.borrow_mut().insert( task.id, - StreamHandler::Model { - model_id: self.model_id, - item_callback: Box::new(move |model, output, app, model_id| { - let model = model.downcast_mut().unwrap(); - let output = *output.downcast().unwrap(); - let mut ctx = ModelContext::new(app, model_id); - item_callback(model, output, &mut ctx); - ctx.halt_stream + StreamHandler { + item_callback: { + let handle = handle.clone(); + Box::new(move |output, app| { + let output = *output.downcast().unwrap(); + handle.update(app, |model, ctx| { + item_callback(model, output, ctx); + ctx.halt_stream + }) + }) + }, + done_callback: Box::new(move |app| { + handle.update(app, |model, ctx| Box::new(done_callback(model, ctx))) }), - done_callback: Box::new( - move |model: &mut dyn Any, app: &mut MutableAppContext, model_id| { - let model = model.downcast_mut().unwrap(); - let mut ctx = ModelContext::new(app, model_id); - Box::new(done_callback(model, &mut ctx)) - }, - ), }, ); @@ -1664,8 +1548,8 @@ impl<'a, T: View> ViewContext<'a, T> { } } - pub fn handle(&self) -> WeakViewHandle { - WeakViewHandle::new(self.window_id, self.view_id) + pub fn handle(&self) -> ViewHandle { + ViewHandle::new(self.window_id, self.view_id, &self.app.ctx.ref_counts) } pub fn window_id(&self) -> usize { @@ -1822,29 +1706,21 @@ impl<'a, T: View> ViewContext<'a, T> { self.halt_stream = true; } - pub fn spawn(&mut self, future: S, callback: F) -> EntityTask> + pub fn spawn(&mut self, future: S, callback: F) -> EntityTask where S: 'static + Future, F: 'static + FnOnce(&mut T, S::Output, &mut ViewContext) -> U, U: 'static, { + let handle = self.handle(); let task = self.app.spawn(future); self.app.future_handlers.borrow_mut().insert( task.id, - FutureHandler::View { - window_id: self.window_id, - view_id: self.view_id, - callback: Box::new(move |view, output, app, window_id, view_id| { - let view = view.as_any_mut().downcast_mut().unwrap(); - let output = *output.downcast().unwrap(); - Box::new(callback( - view, - output, - &mut ViewContext::new(app, window_id, view_id), - )) - }), - }, + Box::new(move |output, app| { + let output = *output.downcast().unwrap(); + handle.update(app, |view, ctx| Box::new(callback(view, output, ctx))) + }), ); task @@ -1855,30 +1731,30 @@ impl<'a, T: View> ViewContext<'a, T> { stream: S, mut item_callback: F, done_callback: G, - ) -> EntityTask> + ) -> EntityTask where S: 'static + Stream + Unpin, F: 'static + FnMut(&mut T, S::Item, &mut ViewContext), G: 'static + FnOnce(&mut T, &mut ViewContext) -> U, U: 'static + Any, { + let handle = self.handle(); let task = self.app.spawn_stream(stream); self.app.stream_handlers.borrow_mut().insert( task.id, - StreamHandler::View { - window_id: self.window_id, - view_id: self.view_id, - item_callback: Box::new(move |view, output, app, window_id, view_id| { - let view = view.as_any_mut().downcast_mut().unwrap(); - let output = *output.downcast().unwrap(); - let mut ctx = ViewContext::new(app, window_id, view_id); - item_callback(view, output, &mut ctx); - ctx.halt_stream - }), - done_callback: Box::new(move |view, app, window_id, view_id| { - let view = view.as_any_mut().downcast_mut().unwrap(); - let mut ctx = ViewContext::new(app, window_id, view_id); - Box::new(done_callback(view, &mut ctx)) + StreamHandler { + item_callback: { + let handle = handle.clone(); + Box::new(move |output, app| { + let output = *output.downcast().unwrap(); + handle.update(app, |view, ctx| { + item_callback(view, output, ctx); + ctx.halt_stream + }) + }) + }, + done_callback: Box::new(move |app| { + handle.update(app, |view, ctx| Box::new(done_callback(view, ctx))) }), }, ); @@ -2076,7 +1952,7 @@ impl ViewHandle { } } - fn downgrade(&self) -> WeakViewHandle { + pub fn downgrade(&self) -> WeakViewHandle { WeakViewHandle::new(self.window_id, self.view_id) } @@ -2322,44 +2198,11 @@ enum Observation { }, } -enum FutureHandler { - Model { - model_id: usize, - callback: Box< - dyn FnOnce(&mut dyn Any, Box, &mut MutableAppContext, usize) -> Box, - >, - }, - View { - window_id: usize, - view_id: usize, - callback: Box< - dyn FnOnce( - &mut dyn AnyView, - Box, - &mut MutableAppContext, - usize, - usize, - ) -> Box, - >, - }, -} +type FutureHandler = Box, &mut MutableAppContext) -> Box>; -enum StreamHandler { - Model { - model_id: usize, - item_callback: - Box, &mut MutableAppContext, usize) -> bool>, - done_callback: Box Box>, - }, - View { - window_id: usize, - view_id: usize, - item_callback: Box< - dyn FnMut(&mut dyn AnyView, Box, &mut MutableAppContext, usize, usize) -> bool, - >, - done_callback: - Box Box>, - }, +struct StreamHandler { + item_callback: Box, &mut MutableAppContext) -> bool>, + done_callback: Box Box>, } #[must_use] diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index f744ee8a19..d0861fa92a 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -138,7 +138,7 @@ impl BufferView { let buffer_ref = buffer.as_ref(ctx); Self { - handle: ctx.handle(), + handle: ctx.handle().downgrade(), buffer, display_map, selections: vec![Selection { diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 354a0b4641..296e910b63 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -275,7 +275,7 @@ impl FileFinder { settings.notify_view_on_change(ctx); Self { - handle: ctx.handle(), + handle: ctx.handle().downgrade(), settings, workspace, query_buffer,