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
+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> {}