Use a `WeakViewHandle` in `Client` for view message handlers

Antonio Scandurra created

Change summary

crates/client/src/client.rs       | 30 ++++++++++++++----------------
crates/gpui/src/app.rs            | 15 +++++++++++++++
crates/workspace/src/workspace.rs |  6 +++---
3 files changed, 32 insertions(+), 19 deletions(-)

Detailed changes

crates/client/src/client.rs 🔗

@@ -18,8 +18,8 @@ use gpui::{
     actions,
     platform::AppVersion,
     serde_json::{self, Value},
-    AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext,
-    AsyncAppContext, Entity, ModelHandle, Task, View, ViewContext, ViewHandle,
+    AnyModelHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity,
+    ModelHandle, Task, View, ViewContext, WeakViewHandle,
 };
 use lazy_static::lazy_static;
 use parking_lot::RwLock;
@@ -221,7 +221,7 @@ enum WeakSubscriber {
 
 enum Subscriber {
     Model(AnyModelHandle),
-    View(AnyViewHandle),
+    View(AnyWeakViewHandle),
 }
 
 #[derive(Clone, Debug)]
@@ -567,7 +567,7 @@ impl Client {
         H: 'static
             + Send
             + Sync
-            + Fn(ViewHandle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
+            + Fn(WeakViewHandle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
         F: 'static + Future<Output = Result<()>>,
     {
         self.add_entity_message_handler::<M, E, _, _>(move |handle, message, client, cx| {
@@ -666,7 +666,7 @@ impl Client {
         H: 'static
             + Send
             + Sync
-            + Fn(ViewHandle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
+            + Fn(WeakViewHandle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
         F: 'static + Future<Output = Result<M::Response>>,
     {
         self.add_view_message_handler(move |entity, envelope, client, cx| {
@@ -1273,7 +1273,15 @@ impl Client {
                     pending.push(message);
                     return;
                 }
-                Some(weak_subscriber @ _) => subscriber = weak_subscriber.upgrade(cx),
+                Some(weak_subscriber @ _) => match weak_subscriber {
+                    WeakSubscriber::Model(handle) => {
+                        subscriber = handle.upgrade(cx).map(Subscriber::Model);
+                    }
+                    WeakSubscriber::View(handle) => {
+                        subscriber = Some(Subscriber::View(handle.clone()));
+                    }
+                    WeakSubscriber::Pending(_) => {}
+                },
                 _ => {}
             }
         }
@@ -1357,16 +1365,6 @@ impl Client {
     }
 }
 
-impl WeakSubscriber {
-    fn upgrade(&self, cx: &AsyncAppContext) -> Option<Subscriber> {
-        match self {
-            WeakSubscriber::Model(handle) => handle.upgrade(cx).map(Subscriber::Model),
-            WeakSubscriber::View(handle) => handle.upgrade(cx).map(Subscriber::View),
-            WeakSubscriber::Pending(_) => None,
-        }
-    }
-}
-
 fn read_credentials_from_keychain(cx: &AsyncAppContext) -> Option<Credentials> {
     if IMPERSONATE_LOGIN.is_some() {
         return None;

crates/gpui/src/app.rs 🔗

@@ -4156,9 +4156,24 @@ impl AnyWeakViewHandle {
         self.view_id
     }
 
+    fn is<T: 'static>(&self) -> bool {
+        TypeId::of::<T>() == self.view_type
+    }
+
     pub fn upgrade(&self, cx: &impl BorrowAppContext) -> Option<AnyViewHandle> {
         cx.read_with(|cx| cx.upgrade_any_view_handle(self))
     }
+
+    pub fn downcast<T: View>(self) -> Option<WeakViewHandle<T>> {
+        if self.is::<T>() {
+            Some(WeakViewHandle {
+                any_handle: self,
+                view_type: PhantomData,
+            })
+        } else {
+            None
+        }
+    }
 }
 
 impl Hash for AnyWeakViewHandle {

crates/workspace/src/workspace.rs 🔗

@@ -2219,7 +2219,7 @@ impl Workspace {
     // RPC handlers
 
     async fn handle_follow(
-        this: ViewHandle<Self>,
+        this: WeakViewHandle<Self>,
         envelope: TypedEnvelope<proto::Follow>,
         _: Arc<Client>,
         mut cx: AsyncAppContext,
@@ -2267,7 +2267,7 @@ impl Workspace {
     }
 
     async fn handle_unfollow(
-        this: ViewHandle<Self>,
+        this: WeakViewHandle<Self>,
         envelope: TypedEnvelope<proto::Unfollow>,
         _: Arc<Client>,
         mut cx: AsyncAppContext,
@@ -2282,7 +2282,7 @@ impl Workspace {
     }
 
     async fn handle_update_followers(
-        this: ViewHandle<Self>,
+        this: WeakViewHandle<Self>,
         envelope: TypedEnvelope<proto::UpdateFollowers>,
         _: Arc<Client>,
         cx: AsyncAppContext,