Reduce the need for Send + Sync bounds on generics

This commit is contained in:
Nathan Sobo
2023-10-24 14:20:01 +02:00
parent 4d621f355d
commit 0910760b76
17 changed files with 405 additions and 362 deletions
+37 -20
View File
@@ -5,7 +5,7 @@ use crate::{
use anyhow::anyhow;
use derive_more::{Deref, DerefMut};
use parking_lot::Mutex;
use std::{future::Future, sync::Weak};
use std::{any::Any, future::Future, sync::Weak};
#[derive(Clone)]
pub struct AsyncAppContext {
@@ -14,13 +14,16 @@ pub struct AsyncAppContext {
}
impl Context for AsyncAppContext {
type EntityContext<'a, 'w, T: 'static + Send + Sync> = ModelContext<'a, T>;
type EntityContext<'a, 'w, T> = ModelContext<'a, T>;
type Result<T> = Result<T>;
fn entity<T: Send + Sync + 'static>(
fn entity<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
) -> Self::Result<Handle<T>> {
) -> Self::Result<Handle<T>>
where
T: Any + Send + Sync,
{
let app = self
.app
.upgrade()
@@ -29,7 +32,7 @@ impl Context for AsyncAppContext {
Ok(lock.entity(build_entity))
}
fn update_entity<T: Send + Sync + 'static, R>(
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
@@ -129,7 +132,7 @@ impl AsyncAppContext {
Ok(app_context.run_on_main(f))
}
pub fn has_global<G: 'static + Send + Sync>(&self) -> Result<bool> {
pub fn has_global<G: 'static>(&self) -> Result<bool> {
let app = self
.app
.upgrade()
@@ -138,10 +141,7 @@ impl AsyncAppContext {
Ok(lock.has_global::<G>())
}
pub fn read_global<G: 'static + Send + Sync, R>(
&self,
read: impl FnOnce(&G, &AppContext) -> R,
) -> Result<R> {
pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
let app = self
.app
.upgrade()
@@ -150,7 +150,7 @@ impl AsyncAppContext {
Ok(read(lock.global(), &lock))
}
pub fn try_read_global<G: 'static + Send + Sync, R>(
pub fn try_read_global<G: 'static, R>(
&self,
read: impl FnOnce(&G, &AppContext) -> R,
) -> Option<R> {
@@ -159,7 +159,7 @@ impl AsyncAppContext {
Some(read(lock.try_global()?, &lock))
}
pub fn update_global<G: 'static + Send + Sync, R>(
pub fn update_global<G: 'static, R>(
&mut self,
update: impl FnOnce(&mut G, &mut AppContext) -> R,
) -> Result<R> {
@@ -195,7 +195,7 @@ impl AsyncWindowContext {
.ok();
}
pub fn read_global<G: 'static + Send + Sync, R>(
pub fn read_global<G: 'static, R>(
&self,
read: impl FnOnce(&G, &WindowContext) -> R,
) -> Result<R> {
@@ -203,28 +203,34 @@ impl AsyncWindowContext {
.read_window(self.window, |cx| read(cx.global(), cx))
}
pub fn update_global<G: 'static + Send + Sync, R>(
pub fn update_global<G, R>(
&mut self,
update: impl FnOnce(&mut G, &mut WindowContext) -> R,
) -> Result<R> {
) -> Result<R>
where
G: 'static,
{
self.app
.update_window(self.window, |cx| cx.update_global(update))
}
}
impl Context for AsyncWindowContext {
type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
type EntityContext<'a, 'w, T> = ViewContext<'a, 'w, T>;
type Result<T> = Result<T>;
fn entity<R: Send + Sync + 'static>(
fn entity<T>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, R>) -> R,
) -> Result<Handle<R>> {
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
) -> Result<Handle<T>>
where
T: Any + Send + Sync,
{
self.app
.update_window(self.window, |cx| cx.entity(build_entity))
}
fn update_entity<T: Send + Sync + 'static, R>(
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
@@ -233,3 +239,14 @@ impl Context for AsyncWindowContext {
.update_window(self.window, |cx| cx.update_entity(handle, update))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_async_app_context_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<AsyncAppContext>();
}
}
+80 -78
View File
@@ -1,4 +1,4 @@
use crate::{AppContext, Context};
use crate::{AnyBox, AppContext, Context};
use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut};
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
@@ -30,7 +30,7 @@ impl Display for EntityId {
}
pub(crate) struct EntityMap {
entities: SecondaryMap<EntityId, Box<dyn Any + Send + Sync>>,
entities: SecondaryMap<EntityId, AnyBox>,
ref_counts: Arc<RwLock<EntityRefCounts>>,
}
@@ -51,56 +51,46 @@ impl EntityMap {
}
/// Reserve a slot for an entity, which you can subsequently use with `insert`.
pub fn reserve<T: 'static + Send + Sync>(&self) -> Slot<T> {
pub fn reserve<T: 'static>(&self) -> Slot<T> {
let id = self.ref_counts.write().counts.insert(1.into());
Slot(Handle::new(id, Arc::downgrade(&self.ref_counts)))
}
/// Insert an entity into a slot obtained by calling `reserve`.
pub fn insert<T: 'static + Any + Send + Sync>(
&mut self,
slot: Slot<T>,
entity: T,
) -> Handle<T> {
pub fn insert<T>(&mut self, slot: Slot<T>, entity: T) -> Handle<T>
where
T: Any + Send + Sync,
{
let handle = slot.0;
self.entities.insert(handle.entity_id, Box::new(entity));
handle
}
/// Move an entity to the stack.
pub fn lease<'a, T: 'static + Send + Sync>(&mut self, handle: &'a Handle<T>) -> Lease<'a, T> {
pub fn lease<'a, T>(&mut self, handle: &'a Handle<T>) -> Lease<'a, T> {
let entity = Some(
self.entities
.remove(handle.entity_id)
.expect("Circular entity lease. Is the entity already being updated?")
.downcast::<T>()
.unwrap(),
.expect("Circular entity lease. Is the entity already being updated?"),
);
Lease { handle, entity }
}
/// Return an entity after moving it to the stack.
pub fn end_lease<T: 'static + Send + Sync>(&mut self, mut lease: Lease<T>) {
self.entities
.insert(lease.handle.entity_id, lease.entity.take().unwrap());
}
pub fn read<T: 'static + Send + Sync>(&self, handle: &Handle<T>) -> &T {
self.entities[handle.entity_id].downcast_ref().unwrap()
}
pub fn weak_handle<T: 'static + Send + Sync>(&self, id: EntityId) -> WeakHandle<T> {
WeakHandle {
any_handle: AnyWeakHandle {
entity_id: id,
entity_type: TypeId::of::<T>(),
entity_ref_counts: Arc::downgrade(&self.ref_counts),
},
Lease {
handle,
entity,
entity_type: PhantomData,
}
}
pub fn take_dropped(&mut self) -> Vec<(EntityId, Box<dyn Any + Send + Sync>)> {
/// Return an entity after moving it to the stack.
pub fn end_lease<T>(&mut self, mut lease: Lease<T>) {
self.entities
.insert(lease.handle.entity_id, lease.entity.take().unwrap());
}
pub fn read<T>(&self, handle: &Handle<T>) -> &T {
(handle.downcast_entity)(&self.entities[handle.entity_id])
}
pub fn take_dropped(&mut self) -> Vec<(EntityId, AnyBox)> {
let dropped_entity_ids = mem::take(&mut self.ref_counts.write().dropped_entity_ids);
dropped_entity_ids
.into_iter()
@@ -109,35 +99,27 @@ impl EntityMap {
}
}
pub struct Lease<'a, T: Send + Sync> {
entity: Option<Box<T>>,
pub struct Lease<'a, T> {
entity: Option<AnyBox>,
pub handle: &'a Handle<T>,
entity_type: PhantomData<T>,
}
impl<'a, T> core::ops::Deref for Lease<'a, T>
where
T: Send + Sync,
{
impl<'a, T> core::ops::Deref for Lease<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.entity.as_ref().unwrap()
(self.handle.downcast_entity)(self.entity.as_ref().unwrap())
}
}
impl<'a, T> core::ops::DerefMut for Lease<'a, T>
where
T: Send + Sync,
{
impl<'a, T> core::ops::DerefMut for Lease<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.entity.as_mut().unwrap()
(self.handle.downcast_entity_mut)(self.entity.as_mut().unwrap())
}
}
impl<'a, T> Drop for Lease<'a, T>
where
T: Send + Sync,
{
impl<'a, T> Drop for Lease<'a, T> {
fn drop(&mut self) {
if self.entity.is_some() {
// We don't panic here, because other panics can cause us to drop the lease without ending it cleanly.
@@ -147,7 +129,7 @@ where
}
#[derive(Deref, DerefMut)]
pub struct Slot<T: Send + Sync + 'static>(Handle<T>);
pub struct Slot<T>(Handle<T>);
pub struct AnyHandle {
pub(crate) entity_id: EntityId,
@@ -176,14 +158,13 @@ impl AnyHandle {
}
}
pub fn downcast<T>(&self) -> Option<Handle<T>>
where
T: 'static + Send + Sync,
{
pub fn downcast<T: 'static>(&self) -> Option<Handle<T>> {
if TypeId::of::<T>() == self.entity_type {
Some(Handle {
any_handle: self.clone(),
entity_type: PhantomData,
downcast_entity: |any| any.downcast_ref().unwrap(),
downcast_entity_mut: |any| any.downcast_mut().unwrap(),
})
} else {
None
@@ -231,10 +212,7 @@ impl Drop for AnyHandle {
}
}
impl<T> From<Handle<T>> for AnyHandle
where
T: 'static + Send + Sync,
{
impl<T> From<Handle<T>> for AnyHandle {
fn from(handle: Handle<T>) -> Self {
handle.any_handle
}
@@ -255,18 +233,28 @@ impl PartialEq for AnyHandle {
impl Eq for AnyHandle {}
#[derive(Deref, DerefMut)]
pub struct Handle<T: Send + Sync> {
pub struct Handle<T> {
#[deref]
#[deref_mut]
any_handle: AnyHandle,
entity_type: PhantomData<T>,
downcast_entity: fn(&dyn Any) -> &T,
downcast_entity_mut: fn(&mut dyn Any) -> &mut T,
}
impl<T: 'static + Send + Sync> Handle<T> {
fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self {
unsafe impl<T> Send for Handle<T> {}
unsafe impl<T> Sync for Handle<T> {}
impl<T: 'static> Handle<T> {
fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self
where
T: 'static,
{
Self {
any_handle: AnyHandle::new(id, TypeId::of::<T>(), entity_map),
entity_type: PhantomData,
downcast_entity: |any| any.downcast_ref().unwrap(),
downcast_entity_mut: |any| any.downcast_mut().unwrap(),
}
}
@@ -274,6 +262,8 @@ impl<T: 'static + Send + Sync> Handle<T> {
WeakHandle {
any_handle: self.any_handle.downgrade(),
entity_type: self.entity_type,
downcast_entity: self.downcast_entity,
downcast_entity_mut: self.downcast_entity_mut,
}
}
@@ -286,25 +276,30 @@ impl<T: 'static + Send + Sync> Handle<T> {
/// The update function receives a context appropriate for its environment.
/// When updating in an `AppContext`, it receives a `ModelContext`.
/// When updating an a `WindowContext`, it receives a `ViewContext`.
pub fn update<C: Context, R>(
pub fn update<C, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
) -> C::Result<R> {
) -> C::Result<R>
where
C: Context,
{
cx.update_entity(self, update)
}
}
impl<T: Send + Sync> Clone for Handle<T> {
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Self {
any_handle: self.any_handle.clone(),
entity_type: self.entity_type,
downcast_entity: self.downcast_entity,
downcast_entity_mut: self.downcast_entity_mut,
}
}
}
impl<T: 'static + Send + Sync> std::fmt::Debug for Handle<T> {
impl<T> std::fmt::Debug for Handle<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
@@ -315,19 +310,19 @@ impl<T: 'static + Send + Sync> std::fmt::Debug for Handle<T> {
}
}
impl<T: Send + Sync + 'static> Hash for Handle<T> {
impl<T> Hash for Handle<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.any_handle.hash(state);
}
}
impl<T: Send + Sync + 'static> PartialEq for Handle<T> {
impl<T> PartialEq for Handle<T> {
fn eq(&self, other: &Self) -> bool {
self.any_handle == other.any_handle
}
}
impl<T: Send + Sync + 'static> Eq for Handle<T> {}
impl<T> Eq for Handle<T> {}
#[derive(Clone)]
pub struct AnyWeakHandle {
@@ -365,10 +360,7 @@ impl AnyWeakHandle {
}
}
impl<T> From<WeakHandle<T>> for AnyWeakHandle
where
T: 'static + Send + Sync,
{
impl<T> From<WeakHandle<T>> for AnyWeakHandle {
fn from(handle: WeakHandle<T>) -> Self {
handle.any_handle
}
@@ -394,22 +386,31 @@ pub struct WeakHandle<T> {
#[deref_mut]
any_handle: AnyWeakHandle,
entity_type: PhantomData<T>,
downcast_entity: fn(&dyn Any) -> &T,
pub(crate) downcast_entity_mut: fn(&mut dyn Any) -> &mut T,
}
impl<T: 'static + Send + Sync> Clone for WeakHandle<T> {
unsafe impl<T> Send for WeakHandle<T> {}
unsafe impl<T> Sync for WeakHandle<T> {}
impl<T> Clone for WeakHandle<T> {
fn clone(&self) -> Self {
Self {
any_handle: self.any_handle.clone(),
entity_type: self.entity_type,
downcast_entity: self.downcast_entity,
downcast_entity_mut: self.downcast_entity_mut,
}
}
}
impl<T: Send + Sync + 'static> WeakHandle<T> {
impl<T: 'static> WeakHandle<T> {
pub fn upgrade(&self) -> Option<Handle<T>> {
Some(Handle {
any_handle: self.any_handle.upgrade()?,
entity_type: self.entity_type,
downcast_entity: self.downcast_entity,
downcast_entity_mut: self.downcast_entity_mut,
})
}
@@ -420,12 +421,13 @@ impl<T: Send + Sync + 'static> WeakHandle<T> {
/// The update function receives a context appropriate for its environment.
/// When updating in an `AppContext`, it receives a `ModelContext`.
/// When updating an a `WindowContext`, it receives a `ViewContext`.
pub fn update<C: Context, R>(
pub fn update<C, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
) -> Result<R>
where
C: Context,
Result<C::Result<R>>: crate::Flatten<R>,
{
crate::Flatten::flatten(
@@ -436,16 +438,16 @@ impl<T: Send + Sync + 'static> WeakHandle<T> {
}
}
impl<T: Send + Sync + 'static> Hash for WeakHandle<T> {
impl<T> Hash for WeakHandle<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.any_handle.hash(state);
}
}
impl<T: Send + Sync + 'static> PartialEq for WeakHandle<T> {
impl<T> PartialEq for WeakHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.any_handle == other.any_handle
}
}
impl<T: Send + Sync + 'static> Eq for WeakHandle<T> {}
impl<T> Eq for WeakHandle<T> {}
+60 -31
View File
@@ -4,28 +4,29 @@ use crate::{
};
use derive_more::{Deref, DerefMut};
use futures::FutureExt;
use std::{any::TypeId, future::Future, marker::PhantomData};
use std::{
any::{Any, TypeId},
future::Future,
};
#[derive(Deref, DerefMut)]
pub struct ModelContext<'a, T> {
#[deref]
#[deref_mut]
app: Reference<'a, AppContext>,
entity_type: PhantomData<T>,
entity_id: EntityId,
model_state: WeakHandle<T>,
}
impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
impl<'a, T: 'static> ModelContext<'a, T> {
pub(crate) fn mutable(app: &'a mut AppContext, model_state: WeakHandle<T>) -> Self {
Self {
app: Reference::Mutable(app),
entity_type: PhantomData,
entity_id,
model_state,
}
}
pub fn entity_id(&self) -> EntityId {
self.entity_id
self.model_state.entity_id
}
pub fn handle(&self) -> Handle<T> {
@@ -35,14 +36,17 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
}
pub fn weak_handle(&self) -> WeakHandle<T> {
self.app.entities.weak_handle(self.entity_id)
self.model_state.clone()
}
pub fn observe<E: Send + Sync + 'static>(
pub fn observe<T2: 'static>(
&mut self,
handle: &Handle<E>,
on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
) -> Subscription {
handle: &Handle<T2>,
on_notify: impl Fn(&mut T, Handle<T2>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
) -> Subscription
where
T: Any + Send + Sync,
{
let this = self.weak_handle();
let handle = handle.downgrade();
self.app.observers.insert(
@@ -58,14 +62,17 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
)
}
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
pub fn subscribe<E: 'static + EventEmitter>(
&mut self,
handle: &Handle<E>,
on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
+ Send
+ Sync
+ 'static,
) -> Subscription {
) -> Subscription
where
T: Any + Send + Sync,
{
let this = self.weak_handle();
let handle = handle.downgrade();
self.app.event_listeners.insert(
@@ -85,9 +92,12 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
pub fn on_release(
&mut self,
on_release: impl Fn(&mut T, &mut AppContext) + Send + Sync + 'static,
) -> Subscription {
) -> Subscription
where
T: 'static,
{
self.app.release_listeners.insert(
self.entity_id,
self.model_state.entity_id,
Box::new(move |this, cx| {
let this = this.downcast_mut().expect("invalid entity type");
on_release(this, cx);
@@ -95,11 +105,14 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
)
}
pub fn observe_release<E: Send + Sync + 'static>(
pub fn observe_release<E: 'static>(
&mut self,
handle: &Handle<E>,
on_release: impl Fn(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static,
) -> Subscription {
) -> Subscription
where
T: Any + Send + Sync,
{
let this = self.weak_handle();
self.app.release_listeners.insert(
handle.entity_id,
@@ -115,7 +128,10 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
pub fn observe_global<G: 'static>(
&mut self,
f: impl Fn(&mut T, &mut ModelContext<'_, T>) + Send + Sync + 'static,
) -> Subscription {
) -> Subscription
where
T: Any + Send + Sync,
{
let handle = self.weak_handle();
self.global_observers.insert(
TypeId::of::<G>(),
@@ -129,6 +145,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
) -> Subscription
where
Fut: 'static + Future<Output = ()> + Send,
T: Any + Send + Sync,
{
let handle = self.weak_handle();
self.app.quit_observers.insert(
@@ -146,9 +163,13 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
}
pub fn notify(&mut self) {
if self.app.pending_notifications.insert(self.entity_id) {
if self
.app
.pending_notifications
.insert(self.model_state.entity_id)
{
self.app.pending_effects.push_back(Effect::Notify {
emitter: self.entity_id,
emitter: self.model_state.entity_id,
});
}
}
@@ -158,8 +179,8 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
G: 'static + Send + Sync,
{
let mut global = self.app.lease_global::<G>();
let result = f(global.as_mut(), self);
self.app.restore_global(global);
let result = f(&mut global, self);
self.app.end_global_lease(global);
result
}
@@ -168,6 +189,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
f: impl FnOnce(WeakHandle<T>, AsyncAppContext) -> Fut + Send + 'static,
) -> Task<R>
where
T: 'static,
Fut: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
@@ -176,27 +198,34 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
}
}
impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
impl<'a, T> ModelContext<'a, T>
where
T: EventEmitter,
T::Event: Send + Sync,
{
pub fn emit(&mut self, event: T::Event) {
self.app.pending_effects.push_back(Effect::Emit {
emitter: self.entity_id,
emitter: self.model_state.entity_id,
event: Box::new(event),
});
}
}
impl<'a, T: 'static> Context for ModelContext<'a, T> {
type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
impl<'a, T> Context for ModelContext<'a, T> {
type EntityContext<'b, 'c, U> = ModelContext<'b, U>;
type Result<U> = U;
fn entity<U: Send + Sync + 'static>(
fn entity<U>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
) -> Handle<U> {
) -> Handle<U>
where
U: 'static + Send + Sync,
{
self.app.entity(build_entity)
}
fn update_entity<U: Send + Sync + 'static, R>(
fn update_entity<U: 'static, R>(
&mut self,
handle: &Handle<U>,
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,