From 24918b5cbc89c446ee5fef50c684ce8f80b1048a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 30 Sep 2021 17:17:33 -0700 Subject: [PATCH 1/5] Remove type parameters from Cursor::seek_internal Instead, use trait objects for the target dimension and aggregation --- gpui/src/sum_tree/cursor.rs | 187 +++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 87 deletions(-) diff --git a/gpui/src/sum_tree/cursor.rs b/gpui/src/sum_tree/cursor.rs index f6f6f9a599c1d502e6a892bbebe70b6b66e92c9f..21855933288e0b84b62b95f09210443eca265923 100644 --- a/gpui/src/sum_tree/cursor.rs +++ b/gpui/src/sum_tree/cursor.rs @@ -1,6 +1,6 @@ use super::*; use arrayvec::ArrayVec; -use std::{cmp::Ordering, sync::Arc}; +use std::{cmp::Ordering, mem, sync::Arc}; #[derive(Clone)] struct StackEntry<'a, T: Item, D> { @@ -324,7 +324,7 @@ where Target: SeekTarget<'a, T::Summary, D>, { self.reset(); - self.seek_internal::<_, ()>(pos, bias, &mut SeekAggregate::None, cx) + self.seek_internal(pos, bias, &mut (), cx) } pub fn seek_forward( @@ -336,7 +336,7 @@ where where Target: SeekTarget<'a, T::Summary, D>, { - self.seek_internal::<_, ()>(pos, bias, &mut SeekAggregate::None, cx) + self.seek_internal(pos, bias, &mut (), cx) } pub fn slice( @@ -348,23 +348,18 @@ where where Target: SeekTarget<'a, T::Summary, D>, { - let mut slice = SeekAggregate::Slice(SumTree::new()); - self.seek_internal::<_, ()>(end, bias, &mut slice, cx); - if let SeekAggregate::Slice(slice) = slice { - slice - } else { - unreachable!() - } + let mut slice = SliceSeekAggregate { + tree: SumTree::new(), + leaf_items: ArrayVec::new(), + leaf_item_summaries: ArrayVec::new(), + leaf_summary: T::Summary::default(), + }; + self.seek_internal(end, bias, &mut slice, cx); + slice.tree } pub fn suffix(&mut self, cx: &::Context) -> SumTree { - let mut slice = SeekAggregate::Slice(SumTree::new()); - self.seek_internal::<_, ()>(&End::new(), Bias::Right, &mut slice, cx); - if let SeekAggregate::Slice(slice) = slice { - slice - } else { - unreachable!() - } + self.slice(&End::new(), Bias::Right, cx) } pub fn summary( @@ -377,26 +372,18 @@ where Target: SeekTarget<'a, T::Summary, D>, Output: Dimension<'a, T::Summary>, { - let mut summary = SeekAggregate::Summary(Output::default()); + let mut summary = SummarySeekAggregate(Output::default()); self.seek_internal(end, bias, &mut summary, cx); - if let SeekAggregate::Summary(summary) = summary { - summary - } else { - unreachable!() - } + summary.0 } - fn seek_internal( + fn seek_internal( &mut self, - target: &Target, + target: &dyn SeekTarget<'a, T::Summary, D>, bias: Bias, - aggregate: &mut SeekAggregate, + aggregate: &mut dyn SeekAggregate<'a, T>, cx: &::Context, - ) -> bool - where - Target: SeekTarget<'a, T::Summary, D>, - Output: Dimension<'a, T::Summary>, - { + ) -> bool { debug_assert!( target.cmp(&self.position, cx) >= Ordering::Equal, "cannot seek backward from {:?} to {:?}", @@ -437,15 +424,7 @@ where || (comparison == Ordering::Equal && bias == Bias::Right) { self.position = child_end; - match aggregate { - SeekAggregate::None => {} - SeekAggregate::Slice(slice) => { - slice.push_tree(child_tree.clone(), cx); - } - SeekAggregate::Summary(summary) => { - summary.add_summary(child_summary, cx); - } - } + aggregate.push_tree(child_tree, child_summary, cx); entry.index += 1; entry.position = self.position.clone(); } else { @@ -464,12 +443,7 @@ where ref item_summaries, .. } => { - let mut slice_items = ArrayVec::::new(); - let mut slice_item_summaries = ArrayVec::::new(); - let mut slice_items_summary = match aggregate { - SeekAggregate::Slice(_) => Some(T::Summary::default()), - _ => None, - }; + aggregate.begin_leaf(); for (item, item_summary) in items[entry.index..] .iter() @@ -483,49 +457,15 @@ where || (comparison == Ordering::Equal && bias == Bias::Right) { self.position = child_end; - match aggregate { - SeekAggregate::None => {} - SeekAggregate::Slice(_) => { - slice_items.push(item.clone()); - slice_item_summaries.push(item_summary.clone()); - ::add_summary( - slice_items_summary.as_mut().unwrap(), - item_summary, - cx, - ); - } - SeekAggregate::Summary(summary) => { - summary.add_summary(item_summary, cx); - } - } + aggregate.push_item(item, item_summary, cx); entry.index += 1; } else { - if let SeekAggregate::Slice(slice) = aggregate { - slice.push_tree( - SumTree(Arc::new(Node::Leaf { - summary: slice_items_summary.unwrap(), - items: slice_items, - item_summaries: slice_item_summaries, - })), - cx, - ); - } + aggregate.end_leaf(cx); break 'outer; } } - if let SeekAggregate::Slice(slice) = aggregate { - if !slice_items.is_empty() { - slice.push_tree( - SumTree(Arc::new(Node::Leaf { - summary: slice_items_summary.unwrap(), - items: slice_items, - item_summaries: slice_item_summaries, - })), - cx, - ); - } - } + aggregate.end_leaf(cx); } } @@ -625,8 +565,81 @@ where } } -enum SeekAggregate { - None, - Slice(SumTree), - Summary(D), +trait SeekAggregate<'a, T: Item> { + fn begin_leaf(&mut self); + fn end_leaf(&mut self, cx: &::Context); + fn push_item( + &mut self, + item: &'a T, + summary: &'a T::Summary, + cx: &::Context, + ); + fn push_tree( + &mut self, + tree: &'a SumTree, + summary: &'a T::Summary, + cx: &::Context, + ); +} + +struct SliceSeekAggregate { + tree: SumTree, + leaf_items: ArrayVec, + leaf_item_summaries: ArrayVec, + leaf_summary: T::Summary, +} + +struct SummarySeekAggregate(D); + +impl<'a, T: Item> SeekAggregate<'a, T> for () { + fn begin_leaf(&mut self) {} + fn end_leaf(&mut self, _: &::Context) {} + fn push_item(&mut self, _: &T, _: &T::Summary, _: &::Context) {} + fn push_tree(&mut self, _: &SumTree, _: &T::Summary, _: &::Context) {} +} + +impl<'a, T: Item> SeekAggregate<'a, T> for SliceSeekAggregate { + fn begin_leaf(&mut self) {} + fn end_leaf(&mut self, cx: &::Context) { + self.tree.push_tree( + SumTree(Arc::new(Node::Leaf { + summary: mem::take(&mut self.leaf_summary), + items: mem::take(&mut self.leaf_items), + item_summaries: mem::take(&mut self.leaf_item_summaries), + })), + cx, + ); + } + fn push_item(&mut self, item: &T, summary: &T::Summary, cx: &::Context) { + self.leaf_items.push(item.clone()); + self.leaf_item_summaries.push(summary.clone()); + Summary::add_summary(&mut self.leaf_summary, summary, cx); + } + fn push_tree( + &mut self, + tree: &SumTree, + _: &T::Summary, + cx: &::Context, + ) { + self.tree.push_tree(tree.clone(), cx); + } +} + +impl<'a, T: Item, D> SeekAggregate<'a, T> for SummarySeekAggregate +where + D: Dimension<'a, T::Summary>, +{ + fn begin_leaf(&mut self) {} + fn end_leaf(&mut self, _: &::Context) {} + fn push_item(&mut self, _: &T, summary: &'a T::Summary, cx: &::Context) { + self.0.add_summary(summary, cx); + } + fn push_tree( + &mut self, + _: &SumTree, + summary: &'a T::Summary, + cx: &::Context, + ) { + self.0.add_summary(summary, cx); + } } From 7577a2be32959e48905ad82159dabe20d3dea4e4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 1 Oct 2021 10:07:27 -0700 Subject: [PATCH 2/5] Box futures before passing them to async_task APIs This reduces the number of copies of each async_task function that get compiled. Co-Authored-By: Nathan Sobo --- gpui/src/executor.rs | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/gpui/src/executor.rs b/gpui/src/executor.rs index 9c7681e19e2830babb03092d9b53b630322cd659..0eba748f33d5ffd4334803a3a7bbb2d82156c37b 100644 --- a/gpui/src/executor.rs +++ b/gpui/src/executor.rs @@ -77,10 +77,9 @@ impl Deterministic { } } - pub fn spawn_from_foreground(&self, future: F) -> Task + fn spawn_from_foreground(&self, future: Pin>>) -> Task where T: 'static, - F: Future + 'static, { let backtrace = Backtrace::new_unresolved(); let scheduled_once = AtomicBool::new(false); @@ -100,10 +99,9 @@ impl Deterministic { task } - pub fn spawn(&self, future: F) -> Task + fn spawn(&self, future: Pin>>) -> Task where T: 'static + Send, - F: 'static + Send + Future, { let backtrace = Backtrace::new_unresolved(); let state = self.state.clone(); @@ -119,13 +117,11 @@ impl Deterministic { task } - pub fn run(&self, future: F) -> T + fn run(&self, mut future: Pin>>) -> T where T: 'static, - F: Future + 'static, { let woken = Arc::new(AtomicBool::new(false)); - let mut future = Box::pin(future); loop { if let Some(result) = self.run_internal(woken.clone(), &mut future) { return result; @@ -142,15 +138,17 @@ impl Deterministic { fn run_until_parked(&self) { let woken = Arc::new(AtomicBool::new(false)); - let future = std::future::pending::<()>(); - smol::pin!(future); - self.run_internal(woken, future); + let mut future = std::future::pending::<()>().boxed_local(); + self.run_internal(woken, &mut future); } - pub fn run_internal(&self, woken: Arc, mut future: F) -> Option + fn run_internal( + &self, + woken: Arc, + future: &mut Pin>>, + ) -> Option where T: 'static, - F: Future + Unpin, { let unparker = self.parker.lock().unparker(); let waker = waker_fn(move || { @@ -396,6 +394,7 @@ impl Foreground { } pub fn spawn(&self, future: impl Future + 'static) -> Task { + let future = future.boxed_local(); match self { Self::Platform { dispatcher, .. } => { let dispatcher = dispatcher.clone(); @@ -410,6 +409,7 @@ impl Foreground { } pub fn run(&self, future: impl 'static + Future) -> T { + let future = future.boxed_local(); match self { Self::Platform { .. } => panic!("you can't call run on a platform foreground executor"), Self::Test(executor) => smol::block_on(executor.run(future)), @@ -500,23 +500,27 @@ impl Background { T: 'static + Send, F: Send + Future + 'static, { + let future = future.boxed(); match self { Self::Production { executor, .. } => executor.spawn(future), Self::Deterministic(executor) => executor.spawn(future), } } - pub fn block_with_timeout(&self, timeout: Duration, mut future: F) -> Result + pub fn block_with_timeout( + &self, + timeout: Duration, + future: F, + ) -> Result>>> where T: 'static, F: 'static + Unpin + Future, { + let mut future = future.boxed_local(); if !timeout.is_zero() { let output = match self { - Self::Production { .. } => { - smol::block_on(util::timeout(timeout, Pin::new(&mut future))).ok() - } - Self::Deterministic(executor) => executor.block_on(Pin::new(&mut future)), + Self::Production { .. } => smol::block_on(util::timeout(timeout, &mut future)).ok(), + Self::Deterministic(executor) => executor.block_on(&mut future), }; if let Some(output) = output { return Ok(output); From 48f9bc972ad12c048bfb3498999e91e98e36b475 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 1 Oct 2021 11:13:17 -0700 Subject: [PATCH 3/5] Box future outputs before passing them to async_task Co-Authored-By: Nathan Sobo --- gpui/src/app.rs | 3 +- gpui/src/executor.rs | 152 +++++++++++++++++++++++++++++++------------ 2 files changed, 111 insertions(+), 44 deletions(-) diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 5536b78bf583a5483ae9052587ec88e179ed9960..1156ec40d4f90fb795d2a74d1375a48199f74033 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -1,6 +1,6 @@ use crate::{ elements::ElementBox, - executor, + executor::{self, Task}, keymap::{self, Keystroke}, platform::{self, CursorStyle, Platform, PromptLevel, WindowOptions}, presenter::Presenter, @@ -8,7 +8,6 @@ use crate::{ AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache, }; use anyhow::{anyhow, Result}; -use async_task::Task; use keymap::MatchResult; use parking_lot::Mutex; use platform::Event; diff --git a/gpui/src/executor.rs b/gpui/src/executor.rs index 0eba748f33d5ffd4334803a3a7bbb2d82156c37b..ba5a88e68ec7160c13429bd0eebda1da26386636 100644 --- a/gpui/src/executor.rs +++ b/gpui/src/executor.rs @@ -1,12 +1,12 @@ use anyhow::{anyhow, Result}; use async_task::Runnable; -pub use async_task::Task; use backtrace::{Backtrace, BacktraceFmt, BytesOrWideString}; use parking_lot::Mutex; use postage::{barrier, prelude::Stream as _}; use rand::prelude::*; use smol::{channel, prelude::*, Executor, Timer}; use std::{ + any::Any, fmt::{self, Debug}, marker::PhantomData, mem, @@ -42,6 +42,24 @@ pub enum Background { }, } +type AnyLocalFuture = Pin>>>; +type AnyFuture = Pin>>>; +type AnyTask = async_task::Task>; +type AnyLocalTask = async_task::Task>; + +pub enum Task { + Local { + any_task: AnyLocalTask, + result_type: PhantomData, + }, + Send { + any_task: AnyTask, + result_type: PhantomData, + }, +} + +unsafe impl Send for Task {} + struct DeterministicState { rng: StdRng, seed: u64, @@ -77,10 +95,7 @@ impl Deterministic { } } - fn spawn_from_foreground(&self, future: Pin>>) -> Task - where - T: 'static, - { + fn spawn_from_foreground(&self, future: AnyLocalFuture) -> AnyLocalTask { let backtrace = Backtrace::new_unresolved(); let scheduled_once = AtomicBool::new(false); let state = self.state.clone(); @@ -99,10 +114,7 @@ impl Deterministic { task } - fn spawn(&self, future: Pin>>) -> Task - where - T: 'static + Send, - { + fn spawn(&self, future: AnyFuture) -> AnyTask { let backtrace = Backtrace::new_unresolved(); let state = self.state.clone(); let unparker = self.parker.lock().unparker(); @@ -117,10 +129,7 @@ impl Deterministic { task } - fn run(&self, mut future: Pin>>) -> T - where - T: 'static, - { + fn run(&self, mut future: AnyLocalFuture) -> Box { let woken = Arc::new(AtomicBool::new(false)); loop { if let Some(result) = self.run_internal(woken.clone(), &mut future) { @@ -138,18 +147,15 @@ impl Deterministic { fn run_until_parked(&self) { let woken = Arc::new(AtomicBool::new(false)); - let mut future = std::future::pending::<()>().boxed_local(); + let mut future = any_local_future(std::future::pending::<()>()); self.run_internal(woken, &mut future); } - fn run_internal( + fn run_internal( &self, woken: Arc, - future: &mut Pin>>, - ) -> Option - where - T: 'static, - { + future: &mut AnyLocalFuture, + ) -> Option> { let unparker = self.parker.lock().unparker(); let waker = waker_fn(move || { woken.store(true, SeqCst); @@ -203,13 +209,7 @@ impl Deterministic { } } - pub fn block_on(&self, future: F) -> Option - where - T: 'static, - F: Future, - { - smol::pin!(future); - + fn block_on(&self, future: &mut AnyLocalFuture) -> Option> { let unparker = self.parker.lock().unparker(); let waker = waker_fn(move || { unparker.unpark(); @@ -394,8 +394,9 @@ impl Foreground { } pub fn spawn(&self, future: impl Future + 'static) -> Task { - let future = future.boxed_local(); - match self { + let future = any_local_future(future); + let any_task = match self { + Self::Deterministic(executor) => executor.spawn_from_foreground(future), Self::Platform { dispatcher, .. } => { let dispatcher = dispatcher.clone(); let schedule = move |runnable: Runnable| dispatcher.run_on_main_thread(runnable); @@ -404,17 +405,18 @@ impl Foreground { task } Self::Test(executor) => executor.spawn(future), - Self::Deterministic(executor) => executor.spawn_from_foreground(future), - } + }; + Task::local(any_task) } pub fn run(&self, future: impl 'static + Future) -> T { - let future = future.boxed_local(); - match self { + let future = any_local_future(future); + let any_value = match self { + Self::Deterministic(executor) => executor.run(future), Self::Platform { .. } => panic!("you can't call run on a platform foreground executor"), Self::Test(executor) => smol::block_on(executor.run(future)), - Self::Deterministic(executor) => executor.run(future), - } + }; + *any_value.downcast().unwrap() } pub fn forbid_parking(&self) { @@ -500,33 +502,34 @@ impl Background { T: 'static + Send, F: Send + Future + 'static, { - let future = future.boxed(); - match self { + let future = any_future(future); + let any_task = match self { Self::Production { executor, .. } => executor.spawn(future), Self::Deterministic(executor) => executor.spawn(future), - } + }; + Task::send(any_task) } pub fn block_with_timeout( &self, timeout: Duration, future: F, - ) -> Result>>> + ) -> Result> where T: 'static, F: 'static + Unpin + Future, { - let mut future = future.boxed_local(); + let mut future = any_local_future(future); if !timeout.is_zero() { let output = match self { Self::Production { .. } => smol::block_on(util::timeout(timeout, &mut future)).ok(), Self::Deterministic(executor) => executor.block_on(&mut future), }; if let Some(output) = output { - return Ok(output); + return Ok(*output.downcast().unwrap()); } } - Err(future) + Err(async { *future.await.downcast().unwrap() }) } pub async fn scoped<'scope, F>(&self, scheduler: F) @@ -576,3 +579,68 @@ pub fn deterministic(seed: u64) -> (Rc, Arc) { Arc::new(Background::Deterministic(executor)), ) } + +impl Task { + fn local(any_task: AnyLocalTask) -> Self { + Self::Local { + any_task, + result_type: PhantomData, + } + } + + pub fn detach(self) { + match self { + Task::Local { any_task, .. } => any_task.detach(), + Task::Send { any_task, .. } => any_task.detach(), + } + } +} + +impl Task { + fn send(any_task: AnyTask) -> Self { + Self::Send { + any_task, + result_type: PhantomData, + } + } +} + +impl fmt::Debug for Task { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Task::Local { any_task, .. } => any_task.fmt(f), + Task::Send { any_task, .. } => any_task.fmt(f), + } + } +} + +impl Future for Task { + type Output = T; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match unsafe { self.get_unchecked_mut() } { + Task::Local { any_task, .. } => { + any_task.poll(cx).map(|value| *value.downcast().unwrap()) + } + Task::Send { any_task, .. } => { + any_task.poll(cx).map(|value| *value.downcast().unwrap()) + } + } + } +} + +fn any_future(future: F) -> AnyFuture +where + T: 'static + Send, + F: Future + Send + 'static, +{ + async { Box::new(future.await) as Box }.boxed() +} + +fn any_local_future(future: F) -> AnyLocalFuture +where + T: 'static, + F: Future + 'static, +{ + async { Box::new(future.await) as Box }.boxed_local() +} From 8370b3075ee15c0bb946cdd719effe0182aefedd Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 1 Oct 2021 12:00:37 -0700 Subject: [PATCH 4/5] Avoid spawn_local instantiations due to different scheduling closure Co-Authored-By: Nathan Sobo --- gpui/src/executor.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/gpui/src/executor.rs b/gpui/src/executor.rs index ba5a88e68ec7160c13429bd0eebda1da26386636..01338c8a0ac5f5d5a6e50b67500e088b12c52d7a 100644 --- a/gpui/src/executor.rs +++ b/gpui/src/executor.rs @@ -23,7 +23,10 @@ use std::{ }; use waker_fn::waker_fn; -use crate::{platform, util}; +use crate::{ + platform::{self, Dispatcher}, + util, +}; pub enum Foreground { Platform { @@ -398,11 +401,18 @@ impl Foreground { let any_task = match self { Self::Deterministic(executor) => executor.spawn_from_foreground(future), Self::Platform { dispatcher, .. } => { - let dispatcher = dispatcher.clone(); - let schedule = move |runnable: Runnable| dispatcher.run_on_main_thread(runnable); - let (runnable, task) = async_task::spawn_local(future, schedule); - runnable.schedule(); - task + fn spawn_inner( + future: AnyLocalFuture, + dispatcher: &Arc, + ) -> AnyLocalTask { + let dispatcher = dispatcher.clone(); + let schedule = + move |runnable: Runnable| dispatcher.run_on_main_thread(runnable); + let (runnable, task) = async_task::spawn_local(future, schedule); + runnable.schedule(); + task + } + spawn_inner(future, dispatcher) } Self::Test(executor) => executor.spawn(future), }; From 514d1b66c36cbf9a84184931a244cea6e03835d8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 1 Oct 2021 15:23:35 -0600 Subject: [PATCH 5/5] Reduce generic instantiations in read/update_view/model Co-Authored-By: Max Brunsfeld --- gpui/src/app.rs | 165 ++++++++++++++++++++++++++---------------- gpui/src/presenter.rs | 12 +-- 2 files changed, 104 insertions(+), 73 deletions(-) diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 1156ec40d4f90fb795d2a74d1375a48199f74033..0cf10697387a905c8adc91cfc3b03038b4e72fd5 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -57,18 +57,19 @@ pub trait ReadModel { } pub trait ReadModelWith { - fn read_model_with T, T>( + fn read_model_with( &self, handle: &ModelHandle, - read: F, + read: &mut dyn FnMut(&E, &AppContext) -> T, ) -> T; } pub trait UpdateModel { - fn update_model(&mut self, handle: &ModelHandle, update: F) -> S - where - T: Entity, - F: FnOnce(&mut T, &mut ModelContext) -> S; + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, + ) -> O; } pub trait UpgradeModelHandle { @@ -81,17 +82,23 @@ pub trait ReadView { } pub trait ReadViewWith { - fn read_view_with(&self, handle: &ViewHandle, read: F) -> T + fn read_view_with( + &self, + handle: &ViewHandle, + read: &mut dyn FnMut(&V, &AppContext) -> T, + ) -> T where - V: View, - F: FnOnce(&V, &AppContext) -> T; + V: View; } pub trait UpdateView { - fn update_view(&mut self, handle: &ViewHandle, update: F) -> S + fn update_view( + &mut self, + handle: &ViewHandle, + update: &mut dyn FnMut(&mut T, &mut ViewContext) -> S, + ) -> S where - T: View, - F: FnOnce(&mut T, &mut ViewContext) -> S; + T: View; } pub trait Action: 'static + AnyAction { @@ -531,11 +538,11 @@ impl AsyncAppContext { } impl UpdateModel for AsyncAppContext { - fn update_model(&mut self, handle: &ModelHandle, update: F) -> S - where - T: Entity, - F: FnOnce(&mut T, &mut ModelContext) -> S, - { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut E, &mut ModelContext) -> O, + ) -> O { let mut state = self.0.borrow_mut(); state.pending_flushes += 1; let result = state.update_model(handle, update); @@ -554,10 +561,10 @@ impl UpgradeModelHandle for AsyncAppContext { } impl ReadModelWith for AsyncAppContext { - fn read_model_with T, T>( + fn read_model_with( &self, handle: &ModelHandle, - read: F, + read: &mut dyn FnMut(&E, &AppContext) -> T, ) -> T { let cx = self.0.borrow(); let cx = cx.as_ref(); @@ -566,10 +573,13 @@ impl ReadModelWith for AsyncAppContext { } impl UpdateView for AsyncAppContext { - fn update_view(&mut self, handle: &ViewHandle, update: F) -> S + fn update_view( + &mut self, + handle: &ViewHandle, + update: &mut dyn FnMut(&mut T, &mut ViewContext) -> S, + ) -> S where T: View, - F: FnOnce(&mut T, &mut ViewContext) -> S, { let mut state = self.0.borrow_mut(); state.pending_flushes += 1; @@ -580,10 +590,13 @@ impl UpdateView for AsyncAppContext { } impl ReadViewWith for AsyncAppContext { - fn read_view_with(&self, handle: &ViewHandle, read: F) -> T + fn read_view_with( + &self, + handle: &ViewHandle, + read: &mut dyn FnMut(&V, &AppContext) -> T, + ) -> T where V: View, - F: FnOnce(&V, &AppContext) -> T, { let cx = self.0.borrow(); let cx = cx.as_ref(); @@ -592,11 +605,11 @@ impl ReadViewWith for AsyncAppContext { } impl UpdateModel for TestAppContext { - fn update_model(&mut self, handle: &ModelHandle, update: F) -> S - where - T: Entity, - F: FnOnce(&mut T, &mut ModelContext) -> S, - { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, + ) -> O { let mut state = self.cx.borrow_mut(); state.pending_flushes += 1; let result = state.update_model(handle, update); @@ -606,10 +619,10 @@ impl UpdateModel for TestAppContext { } impl ReadModelWith for TestAppContext { - fn read_model_with T, T>( + fn read_model_with( &self, handle: &ModelHandle, - read: F, + read: &mut dyn FnMut(&E, &AppContext) -> T, ) -> T { let cx = self.cx.borrow(); let cx = cx.as_ref(); @@ -618,10 +631,13 @@ impl ReadModelWith for TestAppContext { } impl UpdateView for TestAppContext { - fn update_view(&mut self, handle: &ViewHandle, update: F) -> S + fn update_view( + &mut self, + handle: &ViewHandle, + update: &mut dyn FnMut(&mut T, &mut ViewContext) -> S, + ) -> S where T: View, - F: FnOnce(&mut T, &mut ViewContext) -> S, { let mut state = self.cx.borrow_mut(); state.pending_flushes += 1; @@ -632,10 +648,13 @@ impl UpdateView for TestAppContext { } impl ReadViewWith for TestAppContext { - fn read_view_with(&self, handle: &ViewHandle, read: F) -> T + fn read_view_with( + &self, + handle: &ViewHandle, + read: &mut dyn FnMut(&V, &AppContext) -> T, + ) -> T where V: View, - F: FnOnce(&V, &AppContext) -> T, { let cx = self.cx.borrow(); let cx = cx.as_ref(); @@ -1629,11 +1648,11 @@ impl ReadModel for MutableAppContext { } impl UpdateModel for MutableAppContext { - fn update_model(&mut self, handle: &ModelHandle, update: F) -> S - where - T: Entity, - F: FnOnce(&mut T, &mut ModelContext) -> S, - { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> V, + ) -> V { if let Some(mut model) = self.cx.models.remove(&handle.model_id) { self.pending_flushes += 1; let mut cx = ModelContext::new(self, handle.model_id); @@ -1673,10 +1692,13 @@ impl ReadView for MutableAppContext { } impl UpdateView for MutableAppContext { - fn update_view(&mut self, handle: &ViewHandle, update: F) -> S + fn update_view( + &mut self, + handle: &ViewHandle, + update: &mut dyn FnMut(&mut T, &mut ViewContext) -> S, + ) -> S where T: View, - F: FnOnce(&mut T, &mut ViewContext) -> S, { self.pending_flushes += 1; let mut view = self @@ -2083,11 +2105,11 @@ impl ReadModel for ModelContext<'_, M> { } impl UpdateModel for ModelContext<'_, M> { - fn update_model(&mut self, handle: &ModelHandle, update: F) -> S - where - T: Entity, - F: FnOnce(&mut T, &mut ModelContext) -> S, - { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> V, + ) -> V { self.app.update_model(handle, update) } } @@ -2344,11 +2366,11 @@ impl ReadModel for RenderContext<'_, V> { } impl UpdateModel for RenderContext<'_, V> { - fn update_model(&mut self, handle: &ModelHandle, update: F) -> S - where - T: Entity, - F: FnOnce(&mut T, &mut ModelContext) -> S, - { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, + ) -> O { self.app.update_model(handle, update) } } @@ -2395,11 +2417,11 @@ impl UpgradeModelHandle for ViewContext<'_, V> { } impl UpdateModel for ViewContext<'_, V> { - fn update_model(&mut self, handle: &ModelHandle, update: F) -> S - where - T: Entity, - F: FnOnce(&mut T, &mut ModelContext) -> S, - { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, + ) -> O { self.app.update_model(handle, update) } } @@ -2411,10 +2433,13 @@ impl ReadView for ViewContext<'_, V> { } impl UpdateView for ViewContext<'_, V> { - fn update_view(&mut self, handle: &ViewHandle, update: F) -> S + fn update_view( + &mut self, + handle: &ViewHandle, + update: &mut dyn FnMut(&mut T, &mut ViewContext) -> S, + ) -> S where T: View, - F: FnOnce(&mut T, &mut ViewContext) -> S, { self.app.update_view(handle, update) } @@ -2469,7 +2494,11 @@ impl ModelHandle { C: ReadModelWith, F: FnOnce(&T, &AppContext) -> S, { - cx.read_model_with(self, read) + let mut read = Some(read); + cx.read_model_with(self, &mut |model, cx| { + let read = read.take().unwrap(); + read(model, cx) + }) } pub fn update(&self, cx: &mut C, update: F) -> S @@ -2477,7 +2506,11 @@ impl ModelHandle { C: UpdateModel, F: FnOnce(&mut T, &mut ModelContext) -> S, { - cx.update_model(self, update) + let mut update = Some(update); + cx.update_model(self, &mut |model, cx| { + let update = update.take().unwrap(); + update(model, cx) + }) } pub fn next_notification(&self, cx: &TestAppContext) -> impl Future { @@ -2743,7 +2776,11 @@ impl ViewHandle { C: ReadViewWith, F: FnOnce(&T, &AppContext) -> S, { - cx.read_view_with(self, read) + let mut read = Some(read); + cx.read_view_with(self, &mut |view, cx| { + let read = read.take().unwrap(); + read(view, cx) + }) } pub fn update(&self, cx: &mut C, update: F) -> S @@ -2751,7 +2788,11 @@ impl ViewHandle { C: UpdateView, F: FnOnce(&mut T, &mut ViewContext) -> S, { - cx.update_view(self, update) + let mut update = Some(update); + cx.update_view(self, &mut |view, cx| { + let update = update.take().unwrap(); + update(view, cx) + }) } pub fn is_focused(&self, cx: &AppContext) -> bool { diff --git a/gpui/src/presenter.rs b/gpui/src/presenter.rs index 8bcdd08aadcd779b0fbb1f4eb894bd3d8f267c21..354f0a0f821af81040581a7afedb2eb4652acbc2 100644 --- a/gpui/src/presenter.rs +++ b/gpui/src/presenter.rs @@ -7,7 +7,7 @@ use crate::{ platform::Event, text_layout::TextLayoutCache, Action, AnyAction, AssetCache, ElementBox, Entity, FontSystem, ModelHandle, ReadModel, - ReadView, Scene, UpdateView, View, ViewHandle, + ReadView, Scene, View, ViewHandle, }; use pathfinder_geometry::vector::{vec2f, Vector2F}; use serde_json::json; @@ -264,16 +264,6 @@ impl<'a> ReadView for LayoutContext<'a> { } } -impl<'a> UpdateView for LayoutContext<'a> { - fn update_view(&mut self, handle: &ViewHandle, update: F) -> S - where - T: View, - F: FnOnce(&mut T, &mut crate::ViewContext) -> S, - { - self.app.update_view(handle, update) - } -} - impl<'a> ReadModel for LayoutContext<'a> { fn read_model(&self, handle: &ModelHandle) -> &T { self.app.read_model(handle)