crates/gpui3/src/app.rs 🔗
@@ -1,9 +1,9 @@
mod async_context;
-mod entities;
+mod entity_map;
mod model_context;
pub use async_context::*;
-pub use entities::*;
+pub use entity_map::*;
pub use model_context::*;
use crate::{
Nathan Sobo created
crates/gpui3/src/app.rs | 4
crates/gpui3/src/app/entity_map.rs | 68 +++++++++++++++++++++-------
crates/gpui3/src/app/model_context.rs | 5 -
crates/gpui3/src/view.rs | 13 +++-
crates/gpui3/src/window.rs | 5 -
5 files changed, 63 insertions(+), 32 deletions(-)
@@ -1,9 +1,9 @@
mod async_context;
-mod entities;
+mod entity_map;
mod model_context;
pub use async_context::*;
-pub use entities::*;
+pub use entity_map::*;
pub use model_context::*;
use crate::{
@@ -1,9 +1,16 @@
use crate::Context;
use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut};
-use parking_lot::Mutex;
+use parking_lot::{Mutex, RwLock};
use slotmap::{SecondaryMap, SlotMap};
-use std::{any::Any, marker::PhantomData, sync::Arc};
+use std::{
+ any::Any,
+ marker::PhantomData,
+ sync::{
+ atomic::{AtomicUsize, Ordering::SeqCst},
+ Arc, Weak,
+ },
+};
slotmap::new_key_type! { pub struct EntityId; }
@@ -16,24 +23,21 @@ pub struct Lease<T> {
}
pub(crate) struct EntityMap {
- ref_counts: Arc<Mutex<SlotMap<EntityId, usize>>>,
+ ref_counts: Arc<RwLock<RefCounts>>,
entities: Arc<Mutex<SecondaryMap<EntityId, Box<dyn Any + Send + Sync>>>>,
}
impl EntityMap {
pub fn new() -> Self {
Self {
- ref_counts: Arc::new(Mutex::new(SlotMap::with_key())),
+ ref_counts: Arc::new(RwLock::new(SlotMap::with_key())),
entities: Arc::new(Mutex::new(SecondaryMap::new())),
}
}
- pub fn reserve<T>(&self) -> Slot<T> {
- let id = self.ref_counts.lock().insert(1);
- Slot(Handle {
- id,
- entity_type: PhantomData,
- })
+ pub fn reserve<T: 'static + Send + Sync>(&self) -> Slot<T> {
+ let id = self.ref_counts.write().insert(1.into());
+ Slot(Handle::new(id, Arc::downgrade(&self.ref_counts)))
}
pub fn redeem<T: 'static + Any + Send + Sync>(&self, slot: Slot<T>, entity: T) -> Handle<T> {
@@ -42,7 +46,7 @@ impl EntityMap {
handle
}
- pub fn lease<T: 'static>(&self, handle: &Handle<T>) -> Lease<T> {
+ pub fn lease<T: 'static + Send + Sync>(&self, handle: &Handle<T>) -> Lease<T> {
let id = handle.id;
let entity = self
.entities
@@ -57,21 +61,33 @@ impl EntityMap {
pub fn end_lease<T: 'static + Send + Sync>(&mut self, lease: Lease<T>) {
self.entities.lock().insert(lease.id, lease.entity);
}
+
+ pub fn weak_handle<T: 'static + Send + Sync>(&self, id: EntityId) -> WeakHandle<T> {
+ WeakHandle {
+ id,
+ entity_type: PhantomData,
+ ref_counts: Arc::downgrade(&self.ref_counts),
+ }
+ }
}
#[derive(Deref, DerefMut)]
-pub struct Slot<T>(Handle<T>);
+pub struct Slot<T: Send + Sync + 'static>(Handle<T>);
-pub struct Handle<T> {
+pub struct Handle<T: Send + Sync> {
pub(crate) id: EntityId,
- pub(crate) entity_type: PhantomData<T>,
+ entity_type: PhantomData<T>,
+ ref_counts: Weak<RwLock<RefCounts>>,
}
-impl<T: Send + Sync + 'static> Handle<T> {
- pub fn new(id: EntityId) -> Self {
+type RefCounts = SlotMap<EntityId, AtomicUsize>;
+
+impl<T: 'static + Send + Sync> Handle<T> {
+ pub fn new(id: EntityId, ref_counts: Weak<RwLock<RefCounts>>) -> Self {
Self {
id,
entity_type: PhantomData,
+ ref_counts,
}
}
@@ -79,6 +95,7 @@ impl<T: Send + Sync + 'static> Handle<T> {
WeakHandle {
id: self.id,
entity_type: self.entity_type,
+ ref_counts: self.ref_counts.clone(),
}
}
@@ -96,11 +113,23 @@ impl<T: Send + Sync + 'static> Handle<T> {
}
}
-impl<T> Clone for Handle<T> {
+impl<T: Send + Sync> Clone for Handle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
entity_type: PhantomData,
+ ref_counts: self.ref_counts.clone(),
+ }
+ }
+}
+
+impl<T: Send + Sync> Drop for Handle<T> {
+ fn drop(&mut self) {
+ if let Some(ref_counts) = self.ref_counts.upgrade() {
+ if let Some(count) = ref_counts.read().get(self.id) {
+ let prev_count = count.fetch_sub(1, SeqCst);
+ assert_ne!(prev_count, 0, "Detected over-release of a handle.");
+ }
}
}
}
@@ -108,14 +137,17 @@ impl<T> Clone for Handle<T> {
pub struct WeakHandle<T> {
pub(crate) id: EntityId,
pub(crate) entity_type: PhantomData<T>,
+ pub(crate) ref_counts: Weak<RwLock<RefCounts>>,
}
impl<T: Send + Sync + 'static> WeakHandle<T> {
pub fn upgrade(&self, _: &impl Context) -> Option<Handle<T>> {
- // todo!("Actually upgrade")
+ let ref_counts = self.ref_counts.upgrade()?;
+ ref_counts.read().get(self.id).unwrap().fetch_add(1, SeqCst);
Some(Handle {
id: self.id,
entity_type: self.entity_type,
+ ref_counts: self.ref_counts.clone(),
})
}
@@ -35,10 +35,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
// }
pub fn handle(&self) -> WeakHandle<T> {
- WeakHandle {
- id: self.entity_id,
- entity_type: PhantomData,
- }
+ self.app.entities.weak_handle(self.entity_id)
}
pub fn observe<E: Send + Sync + 'static>(
@@ -6,7 +6,7 @@ use crate::{
};
use std::{any::Any, marker::PhantomData, sync::Arc};
-pub struct View<S, P> {
+pub struct View<S: Send + Sync, P> {
state: Handle<S>,
render: Arc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S> + Send + Sync + 'static>,
parent_state_type: PhantomData<P>,
@@ -21,7 +21,7 @@ impl<S: 'static + Send + Sync, P: 'static + Send> View<S, P> {
}
}
-impl<S, P> Clone for View<S, P> {
+impl<S: Send + Sync, P> Clone for View<S, P> {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
@@ -33,10 +33,15 @@ impl<S, P> Clone for View<S, P> {
pub type RootView<S> = View<S, ()>;
-pub fn view<S: 'static, P: 'static, E: Element<State = S>>(
+pub fn view<S, P, E>(
state: Handle<S>,
render: impl Fn(&mut S, &mut ViewContext<S>) -> E + Send + Sync + 'static,
-) -> View<S, P> {
+) -> View<S, P>
+where
+ S: 'static + Send + Sync,
+ P: 'static,
+ E: Element<State = S>,
+{
View {
state,
render: Arc::new(move |state, cx| render(state, cx).into_any()),
@@ -275,10 +275,7 @@ impl<'a, 'w, T: Send + Sync + 'static> ViewContext<'a, 'w, T> {
}
pub fn handle(&self) -> WeakHandle<T> {
- WeakHandle {
- id: self.entity_id,
- entity_type: PhantomData,
- }
+ self.entities.weak_handle(self.entity_id)
}
pub fn observe<E: Send + Sync + 'static>(