Add the entity trait and implement for models, views, subscriptions, and observations

This commit is contained in:
Mikayla 2023-10-30 17:43:07 -07:00
parent 58446c2715
commit 327a2f9967
No known key found for this signature in database
13 changed files with 183 additions and 101 deletions

View file

@ -67,8 +67,8 @@ impl ActiveCall {
incoming_call: watch::channel(), incoming_call: watch::channel(),
_subscriptions: vec![ _subscriptions: vec![
client.add_request_handler(cx.weak_handle(), Self::handle_incoming_call), client.add_request_handler(cx.weak_model(), Self::handle_incoming_call),
client.add_message_handler(cx.weak_handle(), Self::handle_call_canceled), client.add_message_handler(cx.weak_model(), Self::handle_call_canceled),
], ],
client, client,
user_store, user_store,

View file

@ -122,9 +122,9 @@ impl UserStore {
let (mut current_user_tx, current_user_rx) = watch::channel(); let (mut current_user_tx, current_user_rx) = watch::channel();
let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded(); let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded();
let rpc_subscriptions = vec![ let rpc_subscriptions = vec![
client.add_message_handler(cx.weak_handle(), Self::handle_update_contacts), client.add_message_handler(cx.weak_model(), Self::handle_update_contacts),
client.add_message_handler(cx.weak_handle(), Self::handle_update_invite_info), client.add_message_handler(cx.weak_model(), Self::handle_update_invite_info),
client.add_message_handler(cx.weak_handle(), Self::handle_show_contacts), client.add_message_handler(cx.weak_model(), Self::handle_show_contacts),
]; ];
Self { Self {
users: Default::default(), users: Default::default(),

View file

@ -7,8 +7,8 @@ use async_tar::Archive;
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt}; use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
use gpui2::{ use gpui2::{
AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Model, ModelContext, Task, AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model, ModelContext,
WeakModel, Task, WeakModel,
}; };
use language2::{ use language2::{
language_settings::{all_language_settings, language_settings}, language_settings::{all_language_settings, language_settings},

View file

@ -726,7 +726,7 @@ impl Context for AppContext {
/// Update the entity referenced by the given model. The function is passed a mutable reference to the /// Update the entity referenced by the given model. The function is passed a mutable reference to the
/// entity along with a `ModelContext` for the entity. /// entity along with a `ModelContext` for the entity.
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
model: &Model<T>, model: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,

View file

@ -32,7 +32,7 @@ impl Context for AsyncAppContext {
Ok(lock.build_model(build_model)) Ok(lock.build_model(build_model))
} }
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
handle: &Model<T>, handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
@ -42,7 +42,7 @@ impl Context for AsyncAppContext {
.upgrade() .upgrade()
.ok_or_else(|| anyhow!("app was released"))?; .ok_or_else(|| anyhow!("app was released"))?;
let mut lock = app.lock(); // Need this to compile let mut lock = app.lock(); // Need this to compile
Ok(lock.update_entity(handle, update)) Ok(lock.update_model(handle, update))
} }
} }
@ -230,13 +230,13 @@ impl Context for AsyncWindowContext {
.update_window(self.window, |cx| cx.build_model(build_model)) .update_window(self.window, |cx| cx.build_model(build_model))
} }
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
handle: &Model<T>, handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Result<R> { ) -> Result<R> {
self.app self.app
.update_window(self.window, |cx| cx.update_entity(handle, update)) .update_window(self.window, |cx| cx.update_model(handle, update))
} }
} }

View file

@ -1,4 +1,4 @@
use crate::{AnyBox, AppContext, Context}; use crate::{private::Sealed, AnyBox, AppContext, Context, Entity};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use parking_lot::{RwLock, RwLockUpgradableReadGuard};
@ -253,6 +253,32 @@ pub struct Model<T> {
unsafe impl<T> Send for Model<T> {} unsafe impl<T> Send for Model<T> {}
unsafe impl<T> Sync for Model<T> {} unsafe impl<T> Sync for Model<T> {}
impl<T> Sealed for Model<T> {}
impl<T: 'static> Entity<T> for Model<T> {
type Weak = WeakModel<T>;
fn entity_id(&self) -> EntityId {
self.any_model.entity_id
}
fn downgrade(&self) -> Self::Weak {
WeakModel {
any_model: self.any_model.downgrade(),
entity_type: self.entity_type,
}
}
fn upgrade_from(weak: &Self::Weak) -> Option<Self>
where
Self: Sized,
{
Some(Model {
any_model: weak.any_model.upgrade()?,
entity_type: weak.entity_type,
})
}
}
impl<T: 'static> Model<T> { impl<T: 'static> Model<T> {
fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self
@ -265,11 +291,12 @@ impl<T: 'static> Model<T> {
} }
} }
/// Downgrade the this to a weak model reference
pub fn downgrade(&self) -> WeakModel<T> { pub fn downgrade(&self) -> WeakModel<T> {
WeakModel { // Delegate to the trait implementation to keep behavior in one place.
any_model: self.any_model.downgrade(), // This method was included to improve method resolution in the presence of
entity_type: self.entity_type, // the Model's deref
} Entity::downgrade(self)
} }
/// Convert this into a dynamically typed model. /// Convert this into a dynamically typed model.
@ -294,7 +321,7 @@ impl<T: 'static> Model<T> {
where where
C: Context, C: Context,
{ {
cx.update_entity(self, update) cx.update_model(self, update)
} }
} }
@ -334,7 +361,7 @@ impl<T> Eq for Model<T> {}
impl<T> PartialEq<WeakModel<T>> for Model<T> { impl<T> PartialEq<WeakModel<T>> for Model<T> {
fn eq(&self, other: &WeakModel<T>) -> bool { fn eq(&self, other: &WeakModel<T>) -> bool {
self.entity_id() == other.entity_id() self.any_model.entity_id() == other.entity_id()
} }
} }
@ -415,11 +442,10 @@ impl<T> Clone for WeakModel<T> {
} }
impl<T: 'static> WeakModel<T> { impl<T: 'static> WeakModel<T> {
/// Upgrade this weak model reference into a strong model reference
pub fn upgrade(&self) -> Option<Model<T>> { pub fn upgrade(&self) -> Option<Model<T>> {
Some(Model { // Delegate to the trait implementation to keep behavior in one place.
any_model: self.any_model.upgrade()?, Model::upgrade_from(self)
entity_type: self.entity_type,
})
} }
/// Update the entity referenced by this model with the given function if /// Update the entity referenced by this model with the given function if
@ -441,7 +467,7 @@ impl<T: 'static> WeakModel<T> {
crate::Flatten::flatten( crate::Flatten::flatten(
self.upgrade() self.upgrade()
.ok_or_else(|| anyhow!("entity release")) .ok_or_else(|| anyhow!("entity release"))
.map(|this| cx.update_entity(&this, update)), .map(|this| cx.update_model(&this, update)),
) )
} }
} }
@ -462,6 +488,6 @@ impl<T> Eq for WeakModel<T> {}
impl<T> PartialEq<Model<T>> for WeakModel<T> { impl<T> PartialEq<Model<T>> for WeakModel<T> {
fn eq(&self, other: &Model<T>) -> bool { fn eq(&self, other: &Model<T>) -> bool {
self.entity_id() == other.entity_id() self.entity_id() == other.any_model.entity_id()
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, MainThread, Model, AppContext, AsyncAppContext, Context, Effect, Entity, EntityId, EventEmitter, MainThread,
Reference, Subscription, Task, WeakModel, Model, Reference, Subscription, Task, WeakModel,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use futures::FutureExt; use futures::FutureExt;
@ -31,29 +31,32 @@ impl<'a, T: 'static> ModelContext<'a, T> {
} }
pub fn handle(&self) -> Model<T> { pub fn handle(&self) -> Model<T> {
self.weak_handle() self.weak_model()
.upgrade() .upgrade()
.expect("The entity must be alive if we have a model context") .expect("The entity must be alive if we have a model context")
} }
pub fn weak_handle(&self) -> WeakModel<T> { pub fn weak_model(&self) -> WeakModel<T> {
self.model_state.clone() self.model_state.clone()
} }
pub fn observe<T2: 'static>( pub fn observe<T2, E>(
&mut self, &mut self,
handle: &Model<T2>, entity: &E,
mut on_notify: impl FnMut(&mut T, Model<T2>, &mut ModelContext<'_, T>) + Send + 'static, mut on_notify: impl FnMut(&mut T, E, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription ) -> Subscription
where where
T: 'static + Send, T: 'static + Send,
T2: 'static,
E: Entity<T2>,
{ {
let this = self.weak_handle(); let this = self.weak_model();
let handle = handle.downgrade(); let entity_id = entity.entity_id();
let handle = entity.downgrade();
self.app.observers.insert( self.app.observers.insert(
handle.entity_id, entity_id,
Box::new(move |cx| { Box::new(move |cx| {
if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) { if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&handle)) {
this.update(cx, |this, cx| on_notify(this, handle, cx)); this.update(cx, |this, cx| on_notify(this, handle, cx));
true true
} else { } else {
@ -63,21 +66,24 @@ impl<'a, T: 'static> ModelContext<'a, T> {
) )
} }
pub fn subscribe<E: 'static + EventEmitter>( pub fn subscribe<T2, E>(
&mut self, &mut self,
handle: &Model<E>, entity: &E,
mut on_event: impl FnMut(&mut T, Model<E>, &E::Event, &mut ModelContext<'_, T>) + Send + 'static, mut on_event: impl FnMut(&mut T, E, &T2::Event, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription ) -> Subscription
where where
T: 'static + Send, T: 'static + Send,
T2: 'static + EventEmitter,
E: Entity<T2>,
{ {
let this = self.weak_handle(); let this = self.weak_model();
let handle = handle.downgrade(); let entity_id = entity.entity_id();
let entity = entity.downgrade();
self.app.event_listeners.insert( self.app.event_listeners.insert(
handle.entity_id, entity_id,
Box::new(move |event, cx| { Box::new(move |event, cx| {
let event: &E::Event = event.downcast_ref().expect("invalid event type"); let event: &T2::Event = event.downcast_ref().expect("invalid event type");
if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) { if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&entity)) {
this.update(cx, |this, cx| on_event(this, handle, event, cx)); this.update(cx, |this, cx| on_event(this, handle, event, cx));
true true
} else { } else {
@ -103,17 +109,20 @@ impl<'a, T: 'static> ModelContext<'a, T> {
) )
} }
pub fn observe_release<E: 'static>( pub fn observe_release<T2, E>(
&mut self, &mut self,
handle: &Model<E>, entity: &E,
mut on_release: impl FnMut(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + 'static, mut on_release: impl FnMut(&mut T, &mut T2, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription ) -> Subscription
where where
T: Any + Send, T: Any + Send,
T2: 'static,
E: Entity<T2>,
{ {
let this = self.weak_handle(); let entity_id = entity.entity_id();
let this = self.weak_model();
self.app.release_listeners.insert( self.app.release_listeners.insert(
handle.entity_id, entity_id,
Box::new(move |entity, cx| { Box::new(move |entity, cx| {
let entity = entity.downcast_mut().expect("invalid entity type"); let entity = entity.downcast_mut().expect("invalid entity type");
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
@ -130,7 +139,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
where where
T: 'static + Send, T: 'static + Send,
{ {
let handle = self.weak_handle(); let handle = self.weak_model();
self.global_observers.insert( self.global_observers.insert(
TypeId::of::<G>(), TypeId::of::<G>(),
Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()), Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
@ -145,7 +154,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
Fut: 'static + Future<Output = ()> + Send, Fut: 'static + Future<Output = ()> + Send,
T: 'static + Send, T: 'static + Send,
{ {
let handle = self.weak_handle(); let handle = self.weak_model();
self.app.quit_observers.insert( self.app.quit_observers.insert(
(), (),
Box::new(move |cx| { Box::new(move |cx| {
@ -191,7 +200,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
Fut: Future<Output = R> + Send + 'static, Fut: Future<Output = R> + Send + 'static,
R: Send + 'static, R: Send + 'static,
{ {
let this = self.weak_handle(); let this = self.weak_model();
self.app.spawn(|cx| f(this, cx)) self.app.spawn(|cx| f(this, cx))
} }
@ -203,7 +212,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
Fut: Future<Output = R> + 'static, Fut: Future<Output = R> + 'static,
R: Send + 'static, R: Send + 'static,
{ {
let this = self.weak_handle(); let this = self.weak_model();
self.app.spawn_on_main(|cx| f(this, cx)) self.app.spawn_on_main(|cx| f(this, cx))
} }
} }
@ -235,12 +244,12 @@ impl<'a, T> Context for ModelContext<'a, T> {
self.app.build_model(build_model) self.app.build_model(build_model)
} }
fn update_entity<U: 'static, R>( fn update_model<U: 'static, R>(
&mut self, &mut self,
handle: &Model<U>, handle: &Model<U>,
update: impl FnOnce(&mut U, &mut Self::ModelContext<'_, U>) -> R, update: impl FnOnce(&mut U, &mut Self::ModelContext<'_, U>) -> R,
) -> R { ) -> R {
self.app.update_entity(handle, update) self.app.update_model(handle, update)
} }
} }

View file

@ -26,13 +26,13 @@ impl Context for TestAppContext {
lock.build_model(build_model) lock.build_model(build_model)
} }
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
handle: &Model<T>, handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Self::Result<R> { ) -> Self::Result<R> {
let mut lock = self.app.lock(); let mut lock = self.app.lock();
lock.update_entity(handle, update) lock.update_model(handle, update)
} }
} }

View file

@ -24,6 +24,12 @@ mod util;
mod view; mod view;
mod window; mod window;
mod private {
/// A mechanism for restricting implementations of a trait to only those in GPUI.
/// See: https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/
pub trait Sealed {}
}
pub use action::*; pub use action::*;
pub use anyhow::Result; pub use anyhow::Result;
pub use app::*; pub use app::*;
@ -39,6 +45,7 @@ pub use image_cache::*;
pub use interactive::*; pub use interactive::*;
pub use keymap::*; pub use keymap::*;
pub use platform::*; pub use platform::*;
use private::Sealed;
pub use refineable::*; pub use refineable::*;
pub use scene::*; pub use scene::*;
pub use serde; pub use serde;
@ -80,7 +87,7 @@ pub trait Context {
where where
T: 'static + Send; T: 'static + Send;
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
handle: &Model<T>, handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
@ -104,6 +111,16 @@ pub trait VisualContext: Context {
) -> Self::Result<R>; ) -> Self::Result<R>;
} }
pub trait Entity<T>: Sealed {
type Weak: 'static + Send;
fn entity_id(&self) -> EntityId;
fn downgrade(&self) -> Self::Weak;
fn upgrade_from(weak: &Self::Weak) -> Option<Self>
where
Self: Sized;
}
pub enum GlobalKey { pub enum GlobalKey {
Numeric(usize), Numeric(usize),
View(EntityId), View(EntityId),
@ -149,12 +166,12 @@ impl<C: Context> Context for MainThread<C> {
}) })
} }
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
handle: &Model<T>, handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Self::Result<R> { ) -> Self::Result<R> {
self.0.update_entity(handle, |entity, cx| { self.0.update_model(handle, |entity, cx| {
let cx = unsafe { let cx = unsafe {
mem::transmute::< mem::transmute::<
&mut C::ModelContext<'_, T>, &mut C::ModelContext<'_, T>,

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, private::Sealed, AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow,
Element, ElementId, EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, Bounds, Component, Element, ElementId, Entity, EntityId, LayoutId, Model, Pixels, Size,
WeakModel, WindowContext, ViewContext, VisualContext, WeakModel, WindowContext,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::{any::TypeId, marker::PhantomData, sync::Arc}; use std::{any::TypeId, marker::PhantomData, sync::Arc};
@ -16,19 +16,42 @@ pub struct View<V> {
pub(crate) model: Model<V>, pub(crate) model: Model<V>,
} }
impl<V> Sealed for View<V> {}
impl<V: Render> View<V> { impl<V: Render> View<V> {
pub fn into_any(self) -> AnyView { pub fn into_any(self) -> AnyView {
AnyView(Arc::new(self)) AnyView(Arc::new(self))
} }
} }
impl<V: 'static> View<V> { impl<V: 'static> Entity<V> for View<V> {
pub fn downgrade(&self) -> WeakView<V> { type Weak = WeakView<V>;
fn entity_id(&self) -> EntityId {
self.model.entity_id
}
fn downgrade(&self) -> Self::Weak {
WeakView { WeakView {
model: self.model.downgrade(), model: self.model.downgrade(),
} }
} }
fn upgrade_from(weak: &Self::Weak) -> Option<Self>
where
Self: Sized,
{
let model = weak.model.upgrade()?;
Some(View { model })
}
}
impl<V: 'static> View<V> {
/// Convert this strong view reference into a weak view reference.
pub fn downgrade(&self) -> WeakView<V> {
Entity::downgrade(self)
}
pub fn update<C, R>( pub fn update<C, R>(
&self, &self,
cx: &mut C, cx: &mut C,
@ -111,8 +134,7 @@ pub struct WeakView<V> {
impl<V: 'static> WeakView<V> { impl<V: 'static> WeakView<V> {
pub fn upgrade(&self) -> Option<View<V>> { pub fn upgrade(&self) -> Option<View<V>> {
let model = self.model.upgrade()?; Entity::upgrade_from(self)
Some(View { model })
} }
pub fn update<R>( pub fn update<R>(
@ -200,7 +222,7 @@ where
} }
fn entity_id(&self) -> EntityId { fn entity_id(&self) -> EntityId {
self.model.entity_id Entity::entity_id(self)
} }
fn model(&self) -> AnyModel { fn model(&self) -> AnyModel {
@ -208,7 +230,7 @@ where
} }
fn initialize(&self, cx: &mut WindowContext) -> AnyBox { fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
cx.with_element_id(self.entity_id(), |_global_id, cx| { cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
self.update(cx, |state, cx| { self.update(cx, |state, cx| {
let mut any_element = Box::new(AnyElement::new(state.render(cx))); let mut any_element = Box::new(AnyElement::new(state.render(cx)));
any_element.initialize(state, cx); any_element.initialize(state, cx);
@ -218,7 +240,7 @@ where
} }
fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId { fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
cx.with_element_id(self.entity_id(), |_global_id, cx| { cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
self.update(cx, |state, cx| { self.update(cx, |state, cx| {
let element = element.downcast_mut::<AnyElement<V>>().unwrap(); let element = element.downcast_mut::<AnyElement<V>>().unwrap();
element.layout(state, cx) element.layout(state, cx)
@ -227,7 +249,7 @@ where
} }
fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) { fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
cx.with_element_id(self.entity_id(), |_global_id, cx| { cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
self.update(cx, |state, cx| { self.update(cx, |state, cx| {
let element = element.downcast_mut::<AnyElement<V>>().unwrap(); let element = element.downcast_mut::<AnyElement<V>>().unwrap();
element.paint(state, cx); element.paint(state, cx);

View file

@ -1,8 +1,8 @@
use crate::{ use crate::{
px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect,
EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId,
ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId,
MainThread, MainThreadOnly, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MainThread, MainThreadOnly, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformWindow, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformWindow,
Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
@ -1253,7 +1253,7 @@ impl Context for WindowContext<'_, '_> {
self.entities.insert(slot, model) self.entities.insert(slot, model)
} }
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
model: &Model<T>, model: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
@ -1568,23 +1568,25 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
self.window_cx.on_next_frame(move |cx| view.update(cx, f)); self.window_cx.on_next_frame(move |cx| view.update(cx, f));
} }
pub fn observe<E>( pub fn observe<V2, E>(
&mut self, &mut self,
handle: &Model<E>, entity: &E,
mut on_notify: impl FnMut(&mut V, Model<E>, &mut ViewContext<'_, '_, V>) + Send + 'static, mut on_notify: impl FnMut(&mut V, E, &mut ViewContext<'_, '_, V>) + Send + 'static,
) -> Subscription ) -> Subscription
where where
E: 'static, V2: 'static,
V: Any + Send, V: Any + Send,
E: Entity<V2>,
{ {
let view = self.view(); let view = self.view();
let handle = handle.downgrade(); let entity_id = entity.entity_id();
let entity = entity.downgrade();
let window_handle = self.window.handle; let window_handle = self.window.handle;
self.app.observers.insert( self.app.observers.insert(
handle.entity_id, entity_id,
Box::new(move |cx| { Box::new(move |cx| {
cx.update_window(window_handle.id, |cx| { cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade() { if let Some(handle) = E::upgrade_from(&entity) {
view.update(cx, |this, cx| on_notify(this, handle, cx)) view.update(cx, |this, cx| on_notify(this, handle, cx))
.is_ok() .is_ok()
} else { } else {
@ -1596,21 +1598,24 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
) )
} }
pub fn subscribe<E: EventEmitter>( pub fn subscribe<V2, E>(
&mut self, &mut self,
handle: &Model<E>, entity: &E,
mut on_event: impl FnMut(&mut V, Model<E>, &E::Event, &mut ViewContext<'_, '_, V>) mut on_event: impl FnMut(&mut V, E, &V2::Event, &mut ViewContext<'_, '_, V>) + Send + 'static,
+ Send ) -> Subscription
+ 'static, where
) -> Subscription { V2: EventEmitter,
E: Entity<V2>,
{
let view = self.view(); let view = self.view();
let handle = handle.downgrade(); let entity_id = entity.entity_id();
let handle = entity.downgrade();
let window_handle = self.window.handle; let window_handle = self.window.handle;
self.app.event_listeners.insert( self.app.event_listeners.insert(
handle.entity_id, entity_id,
Box::new(move |event, cx| { Box::new(move |event, cx| {
cx.update_window(window_handle.id, |cx| { cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade() { if let Some(handle) = E::upgrade_from(&handle) {
let event = event.downcast_ref().expect("invalid event type"); let event = event.downcast_ref().expect("invalid event type");
view.update(cx, |this, cx| on_event(this, handle, event, cx)) view.update(cx, |this, cx| on_event(this, handle, event, cx))
.is_ok() .is_ok()
@ -1638,18 +1643,21 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
) )
} }
pub fn observe_release<T: 'static>( pub fn observe_release<V2, E>(
&mut self, &mut self,
handle: &Model<T>, entity: &E,
mut on_release: impl FnMut(&mut V, &mut T, &mut ViewContext<'_, '_, V>) + Send + 'static, mut on_release: impl FnMut(&mut V, &mut V2, &mut ViewContext<'_, '_, V>) + Send + 'static,
) -> Subscription ) -> Subscription
where where
V: Any + Send, V: Any + Send,
V2: 'static,
E: Entity<V2>,
{ {
let view = self.view(); let view = self.view();
let entity_id = entity.entity_id();
let window_handle = self.window.handle; let window_handle = self.window.handle;
self.app.release_listeners.insert( self.app.release_listeners.insert(
handle.entity_id, entity_id,
Box::new(move |entity, cx| { Box::new(move |entity, cx| {
let entity = entity.downcast_mut().expect("invalid entity type"); let entity = entity.downcast_mut().expect("invalid entity type");
let _ = cx.update_window(window_handle.id, |cx| { let _ = cx.update_window(window_handle.id, |cx| {
@ -1864,12 +1872,12 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
self.window_cx.build_model(build_model) self.window_cx.build_model(build_model)
} }
fn update_entity<T: 'static, R>( fn update_model<T: 'static, R>(
&mut self, &mut self,
model: &Model<T>, model: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> R { ) -> R {
self.window_cx.update_entity(model, update) self.window_cx.update_model(model, update)
} }
} }

View file

@ -26,8 +26,8 @@ use futures::{
}; };
use globset::{Glob, GlobSet, GlobSetBuilder}; use globset::{Glob, GlobSet, GlobSetBuilder};
use gpui2::{ use gpui2::{
AnyModel, AppContext, AsyncAppContext, Context, EventEmitter, Executor, Model, ModelContext, AnyModel, AppContext, AsyncAppContext, Context, Entity, EventEmitter, Executor, Model,
Task, WeakModel, ModelContext, Task, WeakModel,
}; };
use itertools::Itertools; use itertools::Itertools;
use language2::{ use language2::{
@ -2491,7 +2491,7 @@ impl Project {
delay delay
} else { } else {
if first_insertion { if first_insertion {
let this = cx.weak_handle(); let this = cx.weak_model();
cx.defer(move |cx| { cx.defer(move |cx| {
if let Some(this) = this.upgrade() { if let Some(this) = this.upgrade() {
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
@ -8650,7 +8650,7 @@ fn subscribe_for_copilot_events(
// Another event wants to re-add the server that was already added and subscribed to, avoid doing it again. // Another event wants to re-add the server that was already added and subscribed to, avoid doing it again.
if !copilot_server.has_notification_handler::<copilot2::request::LogMessage>() { if !copilot_server.has_notification_handler::<copilot2::request::LogMessage>() {
let new_server_id = copilot_server.server_id(); let new_server_id = copilot_server.server_id();
let weak_project = cx.weak_handle(); let weak_project = cx.weak_model();
let copilot_log_subscription = copilot_server let copilot_log_subscription = copilot_server
.on_notification::<copilot2::request::LogMessage, _>( .on_notification::<copilot2::request::LogMessage, _>(
move |params, mut cx| { move |params, mut cx| {

View file

@ -1,5 +1,5 @@
use crate::Project; use crate::Project;
use gpui2::{AnyWindowHandle, Context, Model, ModelContext, WeakModel}; use gpui2::{AnyWindowHandle, Context, Entity, Model, ModelContext, WeakModel};
use settings2::Settings; use settings2::Settings;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use terminal2::{ use terminal2::{