entity_map.rs

   1use crate::{App, AppContext, GpuiBorrow, VisualContext, Window, seal::Sealed};
   2use anyhow::{Context as _, Result};
   3use collections::FxHashSet;
   4use derive_more::{Deref, DerefMut};
   5use parking_lot::{RwLock, RwLockUpgradableReadGuard};
   6use slotmap::{KeyData, SecondaryMap, SlotMap};
   7use std::{
   8    any::{Any, TypeId, type_name},
   9    cell::RefCell,
  10    cmp::Ordering,
  11    fmt::{self, Display},
  12    hash::{Hash, Hasher},
  13    marker::PhantomData,
  14    num::NonZeroU64,
  15    sync::{
  16        Arc, Weak,
  17        atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
  18    },
  19    thread::panicking,
  20};
  21
  22use super::Context;
  23use crate::util::atomic_incr_if_not_zero;
  24#[cfg(any(test, feature = "leak-detection"))]
  25use collections::HashMap;
  26
  27slotmap::new_key_type! {
  28    /// A unique identifier for a entity across the application.
  29    pub struct EntityId;
  30}
  31
  32impl From<u64> for EntityId {
  33    fn from(value: u64) -> Self {
  34        Self(KeyData::from_ffi(value))
  35    }
  36}
  37
  38impl EntityId {
  39    /// Converts this entity id to a [NonZeroU64]
  40    pub fn as_non_zero_u64(self) -> NonZeroU64 {
  41        NonZeroU64::new(self.0.as_ffi()).unwrap()
  42    }
  43
  44    /// Converts this entity id to a [u64]
  45    pub fn as_u64(self) -> u64 {
  46        self.0.as_ffi()
  47    }
  48}
  49
  50impl Display for EntityId {
  51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  52        write!(f, "{}", self.as_u64())
  53    }
  54}
  55
  56pub(crate) struct EntityMap {
  57    entities: SecondaryMap<EntityId, Box<dyn Any>>,
  58    pub accessed_entities: RefCell<FxHashSet<EntityId>>,
  59    ref_counts: Arc<RwLock<EntityRefCounts>>,
  60}
  61
  62struct EntityRefCounts {
  63    counts: SlotMap<EntityId, AtomicUsize>,
  64    dropped_entity_ids: Vec<EntityId>,
  65    #[cfg(any(test, feature = "leak-detection"))]
  66    leak_detector: LeakDetector,
  67}
  68
  69impl EntityMap {
  70    pub fn new() -> Self {
  71        Self {
  72            entities: SecondaryMap::new(),
  73            accessed_entities: RefCell::new(FxHashSet::default()),
  74            ref_counts: Arc::new(RwLock::new(EntityRefCounts {
  75                counts: SlotMap::with_key(),
  76                dropped_entity_ids: Vec::new(),
  77                #[cfg(any(test, feature = "leak-detection"))]
  78                leak_detector: LeakDetector {
  79                    next_handle_id: 0,
  80                    entity_handles: HashMap::default(),
  81                },
  82            })),
  83        }
  84    }
  85
  86    #[doc(hidden)]
  87    pub fn ref_counts_drop_handle(&self) -> impl Sized + use<> {
  88        self.ref_counts.clone()
  89    }
  90
  91    /// Captures a snapshot of all entities that currently have alive handles.
  92    ///
  93    /// The returned [`LeakDetectorSnapshot`] can later be passed to
  94    /// [`assert_no_new_leaks`](Self::assert_no_new_leaks) to verify that no
  95    /// entities created after the snapshot are still alive.
  96    #[cfg(any(test, feature = "leak-detection"))]
  97    pub fn leak_detector_snapshot(&self) -> LeakDetectorSnapshot {
  98        self.ref_counts.read().leak_detector.snapshot()
  99    }
 100
 101    /// Asserts that no entities created after `snapshot` still have alive handles.
 102    ///
 103    /// See [`LeakDetector::assert_no_new_leaks`] for details.
 104    #[cfg(any(test, feature = "leak-detection"))]
 105    pub fn assert_no_new_leaks(&self, snapshot: &LeakDetectorSnapshot) {
 106        self.ref_counts
 107            .read()
 108            .leak_detector
 109            .assert_no_new_leaks(snapshot)
 110    }
 111
 112    /// Reserve a slot for an entity, which you can subsequently use with `insert`.
 113    pub fn reserve<T: 'static>(&self) -> Slot<T> {
 114        let id = self.ref_counts.write().counts.insert(1.into());
 115        Slot(Entity::new(id, Arc::downgrade(&self.ref_counts)))
 116    }
 117
 118    /// Insert an entity into a slot obtained by calling `reserve`.
 119    pub fn insert<T>(&mut self, slot: Slot<T>, entity: T) -> Entity<T>
 120    where
 121        T: 'static,
 122    {
 123        let mut accessed_entities = self.accessed_entities.get_mut();
 124        accessed_entities.insert(slot.entity_id);
 125
 126        let handle = slot.0;
 127        self.entities.insert(handle.entity_id, Box::new(entity));
 128        handle
 129    }
 130
 131    /// Move an entity to the stack.
 132    #[track_caller]
 133    pub fn lease<T>(&mut self, pointer: &Entity<T>) -> Lease<T> {
 134        self.assert_valid_context(pointer);
 135        let mut accessed_entities = self.accessed_entities.get_mut();
 136        accessed_entities.insert(pointer.entity_id);
 137
 138        let entity = Some(
 139            self.entities
 140                .remove(pointer.entity_id)
 141                .unwrap_or_else(|| double_lease_panic::<T>("update")),
 142        );
 143        Lease {
 144            entity,
 145            id: pointer.entity_id,
 146            entity_type: PhantomData,
 147        }
 148    }
 149
 150    /// Returns an entity after moving it to the stack.
 151    pub fn end_lease<T>(&mut self, mut lease: Lease<T>) {
 152        self.entities.insert(lease.id, lease.entity.take().unwrap());
 153    }
 154
 155    pub fn read<T: 'static>(&self, entity: &Entity<T>) -> &T {
 156        self.assert_valid_context(entity);
 157        let mut accessed_entities = self.accessed_entities.borrow_mut();
 158        accessed_entities.insert(entity.entity_id);
 159
 160        self.entities
 161            .get(entity.entity_id)
 162            .and_then(|entity| entity.downcast_ref())
 163            .unwrap_or_else(|| double_lease_panic::<T>("read"))
 164    }
 165
 166    fn assert_valid_context(&self, entity: &AnyEntity) {
 167        debug_assert!(
 168            Weak::ptr_eq(&entity.entity_map, &Arc::downgrade(&self.ref_counts)),
 169            "used a entity with the wrong context"
 170        );
 171    }
 172
 173    pub fn extend_accessed(&mut self, entities: &FxHashSet<EntityId>) {
 174        self.accessed_entities
 175            .get_mut()
 176            .extend(entities.iter().copied());
 177    }
 178
 179    pub fn clear_accessed(&mut self) {
 180        self.accessed_entities.get_mut().clear();
 181    }
 182
 183    pub fn take_dropped(&mut self) -> Vec<(EntityId, Box<dyn Any>)> {
 184        let mut ref_counts = &mut *self.ref_counts.write();
 185        let dropped_entity_ids = ref_counts.dropped_entity_ids.drain(..);
 186        let mut accessed_entities = self.accessed_entities.get_mut();
 187
 188        dropped_entity_ids
 189            .filter_map(|entity_id| {
 190                let count = ref_counts.counts.remove(entity_id).unwrap();
 191                debug_assert_eq!(
 192                    count.load(SeqCst),
 193                    0,
 194                    "dropped an entity that was referenced"
 195                );
 196                accessed_entities.remove(&entity_id);
 197                // If the EntityId was allocated with `Context::reserve`,
 198                // the entity may not have been inserted.
 199                Some((entity_id, self.entities.remove(entity_id)?))
 200            })
 201            .collect()
 202    }
 203}
 204
 205#[track_caller]
 206fn double_lease_panic<T>(operation: &str) -> ! {
 207    panic!(
 208        "cannot {operation} {} while it is already being updated",
 209        std::any::type_name::<T>()
 210    )
 211}
 212
 213pub(crate) struct Lease<T> {
 214    entity: Option<Box<dyn Any>>,
 215    pub id: EntityId,
 216    entity_type: PhantomData<T>,
 217}
 218
 219impl<T: 'static> core::ops::Deref for Lease<T> {
 220    type Target = T;
 221
 222    fn deref(&self) -> &Self::Target {
 223        self.entity.as_ref().unwrap().downcast_ref().unwrap()
 224    }
 225}
 226
 227impl<T: 'static> core::ops::DerefMut for Lease<T> {
 228    fn deref_mut(&mut self) -> &mut Self::Target {
 229        self.entity.as_mut().unwrap().downcast_mut().unwrap()
 230    }
 231}
 232
 233impl<T> Drop for Lease<T> {
 234    fn drop(&mut self) {
 235        if self.entity.is_some() && !panicking() {
 236            panic!("Leases must be ended with EntityMap::end_lease")
 237        }
 238    }
 239}
 240
 241#[derive(Deref, DerefMut)]
 242pub(crate) struct Slot<T>(Entity<T>);
 243
 244/// A dynamically typed reference to a entity, which can be downcast into a `Entity<T>`.
 245pub struct AnyEntity {
 246    pub(crate) entity_id: EntityId,
 247    pub(crate) entity_type: TypeId,
 248    entity_map: Weak<RwLock<EntityRefCounts>>,
 249    #[cfg(any(test, feature = "leak-detection"))]
 250    handle_id: HandleId,
 251}
 252
 253impl AnyEntity {
 254    fn new(
 255        id: EntityId,
 256        entity_type: TypeId,
 257        entity_map: Weak<RwLock<EntityRefCounts>>,
 258        #[cfg(any(test, feature = "leak-detection"))] type_name: &'static str,
 259    ) -> Self {
 260        Self {
 261            entity_id: id,
 262            entity_type,
 263            #[cfg(any(test, feature = "leak-detection"))]
 264            handle_id: entity_map
 265                .clone()
 266                .upgrade()
 267                .unwrap()
 268                .write()
 269                .leak_detector
 270                .handle_created(id, Some(type_name)),
 271            entity_map,
 272        }
 273    }
 274
 275    /// Returns the id associated with this entity.
 276    #[inline]
 277    pub fn entity_id(&self) -> EntityId {
 278        self.entity_id
 279    }
 280
 281    /// Returns the [TypeId] associated with this entity.
 282    #[inline]
 283    pub fn entity_type(&self) -> TypeId {
 284        self.entity_type
 285    }
 286
 287    /// Converts this entity handle into a weak variant, which does not prevent it from being released.
 288    pub fn downgrade(&self) -> AnyWeakEntity {
 289        AnyWeakEntity {
 290            entity_id: self.entity_id,
 291            entity_type: self.entity_type,
 292            entity_ref_counts: self.entity_map.clone(),
 293        }
 294    }
 295
 296    /// Converts this entity handle into a strongly-typed entity handle of the given type.
 297    /// If this entity handle is not of the specified type, returns itself as an error variant.
 298    pub fn downcast<T: 'static>(self) -> Result<Entity<T>, AnyEntity> {
 299        if TypeId::of::<T>() == self.entity_type {
 300            Ok(Entity {
 301                any_entity: self,
 302                entity_type: PhantomData,
 303            })
 304        } else {
 305            Err(self)
 306        }
 307    }
 308}
 309
 310impl Clone for AnyEntity {
 311    fn clone(&self) -> Self {
 312        if let Some(entity_map) = self.entity_map.upgrade() {
 313            let entity_map = entity_map.read();
 314            let count = entity_map
 315                .counts
 316                .get(self.entity_id)
 317                .expect("detected over-release of a entity");
 318            let prev_count = count.fetch_add(1, SeqCst);
 319            assert_ne!(prev_count, 0, "Detected over-release of a entity.");
 320        }
 321
 322        Self {
 323            entity_id: self.entity_id,
 324            entity_type: self.entity_type,
 325            entity_map: self.entity_map.clone(),
 326            #[cfg(any(test, feature = "leak-detection"))]
 327            handle_id: self
 328                .entity_map
 329                .upgrade()
 330                .unwrap()
 331                .write()
 332                .leak_detector
 333                .handle_created(self.entity_id, None),
 334        }
 335    }
 336}
 337
 338impl Drop for AnyEntity {
 339    fn drop(&mut self) {
 340        if let Some(entity_map) = self.entity_map.upgrade() {
 341            let entity_map = entity_map.upgradable_read();
 342            let count = entity_map
 343                .counts
 344                .get(self.entity_id)
 345                .expect("detected over-release of a handle.");
 346            let prev_count = count.fetch_sub(1, SeqCst);
 347            assert_ne!(prev_count, 0, "Detected over-release of a entity.");
 348            if prev_count == 1 {
 349                // We were the last reference to this entity, so we can remove it.
 350                let mut entity_map = RwLockUpgradableReadGuard::upgrade(entity_map);
 351                entity_map.dropped_entity_ids.push(self.entity_id);
 352            }
 353        }
 354
 355        #[cfg(any(test, feature = "leak-detection"))]
 356        if let Some(entity_map) = self.entity_map.upgrade() {
 357            entity_map
 358                .write()
 359                .leak_detector
 360                .handle_released(self.entity_id, self.handle_id)
 361        }
 362    }
 363}
 364
 365impl<T> From<Entity<T>> for AnyEntity {
 366    #[inline]
 367    fn from(entity: Entity<T>) -> Self {
 368        entity.any_entity
 369    }
 370}
 371
 372impl Hash for AnyEntity {
 373    #[inline]
 374    fn hash<H: Hasher>(&self, state: &mut H) {
 375        self.entity_id.hash(state);
 376    }
 377}
 378
 379impl PartialEq for AnyEntity {
 380    #[inline]
 381    fn eq(&self, other: &Self) -> bool {
 382        self.entity_id == other.entity_id
 383    }
 384}
 385
 386impl Eq for AnyEntity {}
 387
 388impl Ord for AnyEntity {
 389    #[inline]
 390    fn cmp(&self, other: &Self) -> Ordering {
 391        self.entity_id.cmp(&other.entity_id)
 392    }
 393}
 394
 395impl PartialOrd for AnyEntity {
 396    #[inline]
 397    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 398        Some(self.cmp(other))
 399    }
 400}
 401
 402impl std::fmt::Debug for AnyEntity {
 403    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 404        f.debug_struct("AnyEntity")
 405            .field("entity_id", &self.entity_id.as_u64())
 406            .finish()
 407    }
 408}
 409
 410/// A strong, well-typed reference to a struct which is managed
 411/// by GPUI
 412#[derive(Deref, DerefMut)]
 413pub struct Entity<T> {
 414    #[deref]
 415    #[deref_mut]
 416    pub(crate) any_entity: AnyEntity,
 417    pub(crate) entity_type: PhantomData<fn(T) -> T>,
 418}
 419
 420impl<T> Sealed for Entity<T> {}
 421
 422impl<T: 'static> Entity<T> {
 423    #[inline]
 424    fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self
 425    where
 426        T: 'static,
 427    {
 428        Self {
 429            any_entity: AnyEntity::new(
 430                id,
 431                TypeId::of::<T>(),
 432                entity_map,
 433                #[cfg(any(test, feature = "leak-detection"))]
 434                std::any::type_name::<T>(),
 435            ),
 436            entity_type: PhantomData,
 437        }
 438    }
 439
 440    /// Get the entity ID associated with this entity
 441    #[inline]
 442    pub fn entity_id(&self) -> EntityId {
 443        self.any_entity.entity_id
 444    }
 445
 446    /// Downgrade this entity pointer to a non-retaining weak pointer
 447    #[inline]
 448    pub fn downgrade(&self) -> WeakEntity<T> {
 449        WeakEntity {
 450            any_entity: self.any_entity.downgrade(),
 451            entity_type: self.entity_type,
 452        }
 453    }
 454
 455    /// Convert this into a dynamically typed entity.
 456    #[inline]
 457    pub fn into_any(self) -> AnyEntity {
 458        self.any_entity
 459    }
 460
 461    /// Grab a reference to this entity from the context.
 462    #[inline]
 463    pub fn read<'a>(&self, cx: &'a App) -> &'a T {
 464        cx.entities.read(self)
 465    }
 466
 467    /// Read the entity referenced by this handle with the given function.
 468    #[inline]
 469    pub fn read_with<R, C: AppContext>(&self, cx: &C, f: impl FnOnce(&T, &App) -> R) -> R {
 470        cx.read_entity(self, f)
 471    }
 472
 473    /// Updates the entity referenced by this handle with the given function.
 474    #[inline]
 475    pub fn update<R, C: AppContext>(
 476        &self,
 477        cx: &mut C,
 478        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
 479    ) -> R {
 480        cx.update_entity(self, update)
 481    }
 482
 483    /// Updates the entity referenced by this handle with the given function.
 484    #[inline]
 485    pub fn as_mut<'a, C: AppContext>(&self, cx: &'a mut C) -> GpuiBorrow<'a, T> {
 486        cx.as_mut(self)
 487    }
 488
 489    /// Updates the entity referenced by this handle with the given function.
 490    pub fn write<C: AppContext>(&self, cx: &mut C, value: T) {
 491        self.update(cx, |entity, cx| {
 492            *entity = value;
 493            cx.notify();
 494        })
 495    }
 496
 497    /// Updates the entity referenced by this handle with the given function if
 498    /// the referenced entity still exists, within a visual context that has a window.
 499    /// Returns an error if the window has been closed.
 500    #[inline]
 501    pub fn update_in<R, C: VisualContext>(
 502        &self,
 503        cx: &mut C,
 504        update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
 505    ) -> C::Result<R> {
 506        cx.update_window_entity(self, update)
 507    }
 508}
 509
 510impl<T> Clone for Entity<T> {
 511    #[inline]
 512    fn clone(&self) -> Self {
 513        Self {
 514            any_entity: self.any_entity.clone(),
 515            entity_type: self.entity_type,
 516        }
 517    }
 518}
 519
 520impl<T> std::fmt::Debug for Entity<T> {
 521    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 522        f.debug_struct("Entity")
 523            .field("entity_id", &self.any_entity.entity_id)
 524            .field("entity_type", &type_name::<T>())
 525            .finish()
 526    }
 527}
 528
 529impl<T> Hash for Entity<T> {
 530    #[inline]
 531    fn hash<H: Hasher>(&self, state: &mut H) {
 532        self.any_entity.hash(state);
 533    }
 534}
 535
 536impl<T> PartialEq for Entity<T> {
 537    #[inline]
 538    fn eq(&self, other: &Self) -> bool {
 539        self.any_entity == other.any_entity
 540    }
 541}
 542
 543impl<T> Eq for Entity<T> {}
 544
 545impl<T> PartialEq<WeakEntity<T>> for Entity<T> {
 546    #[inline]
 547    fn eq(&self, other: &WeakEntity<T>) -> bool {
 548        self.any_entity.entity_id() == other.entity_id()
 549    }
 550}
 551
 552impl<T: 'static> Ord for Entity<T> {
 553    #[inline]
 554    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 555        self.entity_id().cmp(&other.entity_id())
 556    }
 557}
 558
 559impl<T: 'static> PartialOrd for Entity<T> {
 560    #[inline]
 561    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
 562        Some(self.cmp(other))
 563    }
 564}
 565
 566/// A type erased, weak reference to a entity.
 567#[derive(Clone)]
 568pub struct AnyWeakEntity {
 569    pub(crate) entity_id: EntityId,
 570    entity_type: TypeId,
 571    entity_ref_counts: Weak<RwLock<EntityRefCounts>>,
 572}
 573
 574impl AnyWeakEntity {
 575    /// Get the entity ID associated with this weak reference.
 576    #[inline]
 577    pub fn entity_id(&self) -> EntityId {
 578        self.entity_id
 579    }
 580
 581    /// Check if this weak handle can be upgraded, or if the entity has already been dropped
 582    pub fn is_upgradable(&self) -> bool {
 583        let ref_count = self
 584            .entity_ref_counts
 585            .upgrade()
 586            .and_then(|ref_counts| Some(ref_counts.read().counts.get(self.entity_id)?.load(SeqCst)))
 587            .unwrap_or(0);
 588        ref_count > 0
 589    }
 590
 591    /// Upgrade this weak entity reference to a strong reference.
 592    pub fn upgrade(&self) -> Option<AnyEntity> {
 593        let ref_counts = &self.entity_ref_counts.upgrade()?;
 594        let ref_counts = ref_counts.read();
 595        let ref_count = ref_counts.counts.get(self.entity_id)?;
 596
 597        if atomic_incr_if_not_zero(ref_count) == 0 {
 598            // entity_id is in dropped_entity_ids
 599            return None;
 600        }
 601        drop(ref_counts);
 602
 603        Some(AnyEntity {
 604            entity_id: self.entity_id,
 605            entity_type: self.entity_type,
 606            entity_map: self.entity_ref_counts.clone(),
 607            #[cfg(any(test, feature = "leak-detection"))]
 608            handle_id: self
 609                .entity_ref_counts
 610                .upgrade()
 611                .unwrap()
 612                .write()
 613                .leak_detector
 614                .handle_created(self.entity_id, None),
 615        })
 616    }
 617
 618    /// Asserts that the entity referenced by this weak handle has been fully released.
 619    ///
 620    /// # Example
 621    ///
 622    /// ```ignore
 623    /// let entity = cx.new(|_| MyEntity::new());
 624    /// let weak = entity.downgrade();
 625    /// drop(entity);
 626    ///
 627    /// // Verify the entity was released
 628    /// weak.assert_released();
 629    /// ```
 630    ///
 631    /// # Debugging Leaks
 632    ///
 633    /// If this method panics due to leaked handles, set the `LEAK_BACKTRACE` environment
 634    /// variable to see where the leaked handles were allocated:
 635    ///
 636    /// ```bash
 637    /// LEAK_BACKTRACE=1 cargo test my_test
 638    /// ```
 639    ///
 640    /// # Panics
 641    ///
 642    /// - Panics if any strong handles to the entity are still alive.
 643    /// - Panics if the entity was recently dropped but cleanup hasn't completed yet
 644    ///   (resources are retained until the end of the effect cycle).
 645    #[cfg(any(test, feature = "leak-detection"))]
 646    pub fn assert_released(&self) {
 647        self.entity_ref_counts
 648            .upgrade()
 649            .unwrap()
 650            .write()
 651            .leak_detector
 652            .assert_released(self.entity_id);
 653
 654        if self
 655            .entity_ref_counts
 656            .upgrade()
 657            .and_then(|ref_counts| Some(ref_counts.read().counts.get(self.entity_id)?.load(SeqCst)))
 658            .is_some()
 659        {
 660            panic!(
 661                "entity was recently dropped but resources are retained until the end of the effect cycle."
 662            )
 663        }
 664    }
 665
 666    /// Creates a weak entity that can never be upgraded.
 667    pub fn new_invalid() -> Self {
 668        /// To hold the invariant that all ids are unique, and considering that slotmap
 669        /// increases their IDs from `0`, we can decrease ours from `u64::MAX` so these
 670        /// two will never conflict (u64 is way too large).
 671        static UNIQUE_NON_CONFLICTING_ID_GENERATOR: AtomicU64 = AtomicU64::new(u64::MAX);
 672        let entity_id = UNIQUE_NON_CONFLICTING_ID_GENERATOR.fetch_sub(1, SeqCst);
 673
 674        Self {
 675            // Safety:
 676            //   Docs say this is safe but can be unspecified if slotmap changes the representation
 677            //   after `1.0.7`, that said, providing a valid entity_id here is not necessary as long
 678            //   as we guarantee that `entity_id` is never used if `entity_ref_counts` equals
 679            //   to `Weak::new()` (that is, it's unable to upgrade), that is the invariant that
 680            //   actually needs to be hold true.
 681            //
 682            //   And there is no sane reason to read an entity slot if `entity_ref_counts` can't be
 683            //   read in the first place, so we're good!
 684            entity_id: entity_id.into(),
 685            entity_type: TypeId::of::<()>(),
 686            entity_ref_counts: Weak::new(),
 687        }
 688    }
 689}
 690
 691impl std::fmt::Debug for AnyWeakEntity {
 692    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 693        f.debug_struct(type_name::<Self>())
 694            .field("entity_id", &self.entity_id)
 695            .field("entity_type", &self.entity_type)
 696            .finish()
 697    }
 698}
 699
 700impl<T> From<WeakEntity<T>> for AnyWeakEntity {
 701    #[inline]
 702    fn from(entity: WeakEntity<T>) -> Self {
 703        entity.any_entity
 704    }
 705}
 706
 707impl Hash for AnyWeakEntity {
 708    #[inline]
 709    fn hash<H: Hasher>(&self, state: &mut H) {
 710        self.entity_id.hash(state);
 711    }
 712}
 713
 714impl PartialEq for AnyWeakEntity {
 715    #[inline]
 716    fn eq(&self, other: &Self) -> bool {
 717        self.entity_id == other.entity_id
 718    }
 719}
 720
 721impl Eq for AnyWeakEntity {}
 722
 723impl Ord for AnyWeakEntity {
 724    #[inline]
 725    fn cmp(&self, other: &Self) -> Ordering {
 726        self.entity_id.cmp(&other.entity_id)
 727    }
 728}
 729
 730impl PartialOrd for AnyWeakEntity {
 731    #[inline]
 732    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 733        Some(self.cmp(other))
 734    }
 735}
 736
 737/// A weak reference to a entity of the given type.
 738#[derive(Deref, DerefMut)]
 739pub struct WeakEntity<T> {
 740    #[deref]
 741    #[deref_mut]
 742    any_entity: AnyWeakEntity,
 743    entity_type: PhantomData<fn(T) -> T>,
 744}
 745
 746impl<T> std::fmt::Debug for WeakEntity<T> {
 747    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 748        f.debug_struct(type_name::<Self>())
 749            .field("entity_id", &self.any_entity.entity_id)
 750            .field("entity_type", &type_name::<T>())
 751            .finish()
 752    }
 753}
 754
 755impl<T> Clone for WeakEntity<T> {
 756    fn clone(&self) -> Self {
 757        Self {
 758            any_entity: self.any_entity.clone(),
 759            entity_type: self.entity_type,
 760        }
 761    }
 762}
 763
 764impl<T: 'static> WeakEntity<T> {
 765    /// Upgrade this weak entity reference into a strong entity reference
 766    pub fn upgrade(&self) -> Option<Entity<T>> {
 767        Some(Entity {
 768            any_entity: self.any_entity.upgrade()?,
 769            entity_type: self.entity_type,
 770        })
 771    }
 772
 773    /// Updates the entity referenced by this handle with the given function if
 774    /// the referenced entity still exists. Returns an error if the entity has
 775    /// been released.
 776    pub fn update<C, R>(
 777        &self,
 778        cx: &mut C,
 779        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
 780    ) -> Result<R>
 781    where
 782        C: AppContext,
 783    {
 784        let entity = self.upgrade().context("entity released")?;
 785        Ok(cx.update_entity(&entity, update))
 786    }
 787
 788    /// Updates the entity referenced by this handle with the given function if
 789    /// the referenced entity still exists, within a visual context that has a window.
 790    /// Returns an error if the entity has been released.
 791    pub fn update_in<C, R>(
 792        &self,
 793        cx: &mut C,
 794        update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
 795    ) -> Result<R>
 796    where
 797        C: VisualContext,
 798    {
 799        let window = cx.window_handle();
 800        let entity = self.upgrade().context("entity released")?;
 801
 802        window.update(cx, |_, window, cx| {
 803            entity.update(cx, |entity, cx| update(entity, window, cx))
 804        })
 805    }
 806
 807    /// Reads the entity referenced by this handle with the given function if
 808    /// the referenced entity still exists. Returns an error if the entity has
 809    /// been released.
 810    pub fn read_with<C, R>(&self, cx: &C, read: impl FnOnce(&T, &App) -> R) -> Result<R>
 811    where
 812        C: AppContext,
 813    {
 814        let entity = self.upgrade().context("entity released")?;
 815        Ok(cx.read_entity(&entity, read))
 816    }
 817
 818    /// Create a new weak entity that can never be upgraded.
 819    #[inline]
 820    pub fn new_invalid() -> Self {
 821        Self {
 822            any_entity: AnyWeakEntity::new_invalid(),
 823            entity_type: PhantomData,
 824        }
 825    }
 826}
 827
 828impl<T> Hash for WeakEntity<T> {
 829    #[inline]
 830    fn hash<H: Hasher>(&self, state: &mut H) {
 831        self.any_entity.hash(state);
 832    }
 833}
 834
 835impl<T> PartialEq for WeakEntity<T> {
 836    #[inline]
 837    fn eq(&self, other: &Self) -> bool {
 838        self.any_entity == other.any_entity
 839    }
 840}
 841
 842impl<T> Eq for WeakEntity<T> {}
 843
 844impl<T> PartialEq<Entity<T>> for WeakEntity<T> {
 845    #[inline]
 846    fn eq(&self, other: &Entity<T>) -> bool {
 847        self.entity_id() == other.any_entity.entity_id()
 848    }
 849}
 850
 851impl<T: 'static> Ord for WeakEntity<T> {
 852    #[inline]
 853    fn cmp(&self, other: &Self) -> Ordering {
 854        self.entity_id().cmp(&other.entity_id())
 855    }
 856}
 857
 858impl<T: 'static> PartialOrd for WeakEntity<T> {
 859    #[inline]
 860    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 861        Some(self.cmp(other))
 862    }
 863}
 864
 865/// Controls whether backtraces are captured when entity handles are created.
 866///
 867/// Set the `LEAK_BACKTRACE` environment variable to any non-empty value to enable
 868/// backtrace capture. This helps identify where leaked handles were allocated.
 869#[cfg(any(test, feature = "leak-detection"))]
 870static LEAK_BACKTRACE: std::sync::LazyLock<bool> =
 871    std::sync::LazyLock::new(|| std::env::var("LEAK_BACKTRACE").is_ok_and(|b| !b.is_empty()));
 872
 873/// Unique identifier for a specific entity handle instance.
 874///
 875/// This is distinct from `EntityId` - while multiple handles can point to the same
 876/// entity (same `EntityId`), each handle has its own unique `HandleId`.
 877#[cfg(any(test, feature = "leak-detection"))]
 878#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
 879pub(crate) struct HandleId {
 880    id: u64,
 881}
 882
 883/// Tracks entity handle allocations to detect leaks.
 884///
 885/// The leak detector is enabled in tests and when the `leak-detection` feature is active.
 886/// It tracks every `Entity<T>` and `AnyEntity` handle that is created and released,
 887/// allowing you to verify that all handles to an entity have been properly dropped.
 888///
 889/// # How do leaks happen?
 890///
 891/// Entities are reference-counted structures that can own other entities
 892/// allowing to form cycles. If such a strong-reference counted cycle is
 893/// created, all participating strong entities in this cycle will effectively
 894/// leak as they cannot be released anymore.
 895///
 896/// # Usage
 897///
 898/// You can use `WeakEntity::assert_released` or `AnyWeakEntity::assert_released`
 899/// to verify that an entity has been fully released:
 900///
 901/// ```ignore
 902/// let entity = cx.new(|_| MyEntity::new());
 903/// let weak = entity.downgrade();
 904/// drop(entity);
 905///
 906/// // This will panic if any handles to the entity are still alive
 907/// weak.assert_released();
 908/// ```
 909///
 910/// # Debugging Leaks
 911///
 912/// When a leak is detected, the detector will panic with information about the leaked
 913/// handles. To see where the leaked handles were allocated, set the `LEAK_BACKTRACE`
 914/// environment variable:
 915///
 916/// ```bash
 917/// LEAK_BACKTRACE=1 cargo test my_test
 918/// ```
 919///
 920/// This will capture and display backtraces for each leaked handle, helping you
 921/// identify where handles were created but not released.
 922///
 923/// # How It Works
 924///
 925/// - When an entity handle is created (via `Entity::new`, `Entity::clone`, or
 926///   `WeakEntity::upgrade`), `handle_created` is called to register the handle.
 927/// - When a handle is dropped, `handle_released` removes it from tracking.
 928/// - `assert_released` verifies that no handles remain for a given entity.
 929#[cfg(any(test, feature = "leak-detection"))]
 930pub(crate) struct LeakDetector {
 931    next_handle_id: u64,
 932    entity_handles: HashMap<EntityId, EntityLeakData>,
 933}
 934
 935/// A snapshot of the set of alive entities at a point in time.
 936///
 937/// Created by [`LeakDetector::snapshot`]. Can later be passed to
 938/// [`LeakDetector::assert_no_new_leaks`] to verify that no new entity
 939/// handles remain between the snapshot and the current state.
 940#[cfg(any(test, feature = "leak-detection"))]
 941pub struct LeakDetectorSnapshot {
 942    entity_ids: collections::HashSet<EntityId>,
 943}
 944
 945#[cfg(any(test, feature = "leak-detection"))]
 946struct EntityLeakData {
 947    handles: HashMap<HandleId, Option<backtrace::Backtrace>>,
 948    type_name: &'static str,
 949}
 950
 951#[cfg(any(test, feature = "leak-detection"))]
 952impl LeakDetector {
 953    /// Records that a new handle has been created for the given entity.
 954    ///
 955    /// Returns a unique `HandleId` that must be passed to `handle_released` when
 956    /// the handle is dropped. If `LEAK_BACKTRACE` is set, captures a backtrace
 957    /// at the allocation site.
 958    #[track_caller]
 959    pub fn handle_created(
 960        &mut self,
 961        entity_id: EntityId,
 962        type_name: Option<&'static str>,
 963    ) -> HandleId {
 964        let id = gpui_util::post_inc(&mut self.next_handle_id);
 965        let handle_id = HandleId { id };
 966        let handles = self
 967            .entity_handles
 968            .entry(entity_id)
 969            .or_insert_with(|| EntityLeakData {
 970                handles: HashMap::default(),
 971                type_name: type_name.unwrap_or("<unknown>"),
 972            });
 973        handles.handles.insert(
 974            handle_id,
 975            LEAK_BACKTRACE.then(backtrace::Backtrace::new_unresolved),
 976        );
 977        handle_id
 978    }
 979
 980    /// Records that a handle has been released (dropped).
 981    ///
 982    /// This removes the handle from tracking. The `handle_id` should be the same
 983    /// one returned by `handle_created` when the handle was allocated.
 984    pub fn handle_released(&mut self, entity_id: EntityId, handle_id: HandleId) {
 985        if let std::collections::hash_map::Entry::Occupied(mut data) =
 986            self.entity_handles.entry(entity_id)
 987        {
 988            data.get_mut().handles.remove(&handle_id);
 989            if data.get().handles.is_empty() {
 990                data.remove();
 991            }
 992        }
 993    }
 994
 995    /// Asserts that all handles to the given entity have been released.
 996    ///
 997    /// # Panics
 998    ///
 999    /// Panics if any handles to the entity are still alive. The panic message
1000    /// includes backtraces for each leaked handle if `LEAK_BACKTRACE` is set,
1001    /// otherwise it suggests setting the environment variable to get more info.
1002    pub fn assert_released(&mut self, entity_id: EntityId) {
1003        use std::fmt::Write as _;
1004        if let Some(data) = self.entity_handles.remove(&entity_id) {
1005            let mut out = String::new();
1006            for (_, backtrace) in data.handles {
1007                if let Some(mut backtrace) = backtrace {
1008                    backtrace.resolve();
1009                    writeln!(out, "Leaked handle:\n{:?}", backtrace).unwrap();
1010                } else {
1011                    writeln!(
1012                        out,
1013                        "Leaked handle: (export LEAK_BACKTRACE to find allocation site)"
1014                    )
1015                    .unwrap();
1016                }
1017            }
1018            panic!("{out}");
1019        }
1020    }
1021
1022    /// Captures a snapshot of all entity IDs that currently have alive handles.
1023    ///
1024    /// The returned [`LeakDetectorSnapshot`] can later be passed to
1025    /// [`assert_no_new_leaks`](Self::assert_no_new_leaks) to verify that no
1026    /// entities created after the snapshot are still alive.
1027    pub fn snapshot(&self) -> LeakDetectorSnapshot {
1028        LeakDetectorSnapshot {
1029            entity_ids: self.entity_handles.keys().copied().collect(),
1030        }
1031    }
1032
1033    /// Asserts that no entities created after `snapshot` still have alive handles.
1034    ///
1035    /// Entities that were already tracked at the time of the snapshot are ignored,
1036    /// even if they still have handles. Only *new* entities (those whose
1037    /// `EntityId` was not present in the snapshot) are considered leaks.
1038    ///
1039    /// # Panics
1040    ///
1041    /// Panics if any new entity handles exist. The panic message lists every
1042    /// leaked entity with its type name, and includes allocation-site backtraces
1043    /// when `LEAK_BACKTRACE` is set.
1044    pub fn assert_no_new_leaks(&self, snapshot: &LeakDetectorSnapshot) {
1045        use std::fmt::Write as _;
1046
1047        let mut out = String::new();
1048        for (entity_id, data) in &self.entity_handles {
1049            if snapshot.entity_ids.contains(entity_id) {
1050                continue;
1051            }
1052            for (_, backtrace) in &data.handles {
1053                if let Some(backtrace) = backtrace {
1054                    let mut backtrace = backtrace.clone();
1055                    backtrace.resolve();
1056                    writeln!(
1057                        out,
1058                        "Leaked handle for entity {} ({entity_id:?}):\n{:?}",
1059                        data.type_name, backtrace
1060                    )
1061                    .unwrap();
1062                } else {
1063                    writeln!(
1064                        out,
1065                        "Leaked handle for entity {} ({entity_id:?}): (export LEAK_BACKTRACE to find allocation site)",
1066                        data.type_name
1067                    )
1068                    .unwrap();
1069                }
1070            }
1071        }
1072
1073        if !out.is_empty() {
1074            panic!("New entity leaks detected since snapshot:\n{out}");
1075        }
1076    }
1077}
1078
1079#[cfg(any(test, feature = "leak-detection"))]
1080impl Drop for LeakDetector {
1081    fn drop(&mut self) {
1082        use std::fmt::Write;
1083
1084        if self.entity_handles.is_empty() || std::thread::panicking() {
1085            return;
1086        }
1087
1088        let mut out = String::new();
1089        for (entity_id, data) in self.entity_handles.drain() {
1090            for (_handle, backtrace) in data.handles {
1091                if let Some(mut backtrace) = backtrace {
1092                    backtrace.resolve();
1093                    writeln!(
1094                        out,
1095                        "Leaked handle for entity {} ({entity_id:?}):\n{:?}",
1096                        data.type_name, backtrace
1097                    )
1098                    .unwrap();
1099                } else {
1100                    writeln!(
1101                        out,
1102                        "Leaked handle for entity {} ({entity_id:?}): (export LEAK_BACKTRACE to find allocation site)",
1103                        data.type_name
1104                    )
1105                    .unwrap();
1106                }
1107            }
1108        }
1109        panic!("Exited with leaked handles:\n{out}");
1110    }
1111}
1112
1113#[cfg(test)]
1114mod test {
1115    use crate::EntityMap;
1116
1117    struct TestEntity {
1118        pub i: i32,
1119    }
1120
1121    #[test]
1122    fn test_entity_map_slot_assignment_before_cleanup() {
1123        // Tests that slots are not re-used before take_dropped.
1124        let mut entity_map = EntityMap::new();
1125
1126        let slot = entity_map.reserve::<TestEntity>();
1127        entity_map.insert(slot, TestEntity { i: 1 });
1128
1129        let slot = entity_map.reserve::<TestEntity>();
1130        entity_map.insert(slot, TestEntity { i: 2 });
1131
1132        let dropped = entity_map.take_dropped();
1133        assert_eq!(dropped.len(), 2);
1134
1135        assert_eq!(
1136            dropped
1137                .into_iter()
1138                .map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
1139                .collect::<Vec<i32>>(),
1140            vec![1, 2],
1141        );
1142    }
1143
1144    #[test]
1145    fn test_entity_map_weak_upgrade_before_cleanup() {
1146        // Tests that weak handles are not upgraded before take_dropped
1147        let mut entity_map = EntityMap::new();
1148
1149        let slot = entity_map.reserve::<TestEntity>();
1150        let handle = entity_map.insert(slot, TestEntity { i: 1 });
1151        let weak = handle.downgrade();
1152        drop(handle);
1153
1154        let strong = weak.upgrade();
1155        assert_eq!(strong, None);
1156
1157        let dropped = entity_map.take_dropped();
1158        assert_eq!(dropped.len(), 1);
1159
1160        assert_eq!(
1161            dropped
1162                .into_iter()
1163                .map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
1164                .collect::<Vec<i32>>(),
1165            vec![1],
1166        );
1167    }
1168
1169    #[test]
1170    fn test_leak_detector_snapshot_no_leaks() {
1171        let mut entity_map = EntityMap::new();
1172
1173        let slot = entity_map.reserve::<TestEntity>();
1174        let pre_existing = entity_map.insert(slot, TestEntity { i: 1 });
1175
1176        let snapshot = entity_map.leak_detector_snapshot();
1177
1178        let slot = entity_map.reserve::<TestEntity>();
1179        let temporary = entity_map.insert(slot, TestEntity { i: 2 });
1180        drop(temporary);
1181
1182        entity_map.assert_no_new_leaks(&snapshot);
1183
1184        drop(pre_existing);
1185    }
1186
1187    #[test]
1188    #[should_panic(expected = "New entity leaks detected since snapshot")]
1189    fn test_leak_detector_snapshot_detects_new_leak() {
1190        let mut entity_map = EntityMap::new();
1191
1192        let slot = entity_map.reserve::<TestEntity>();
1193        let pre_existing = entity_map.insert(slot, TestEntity { i: 1 });
1194
1195        let snapshot = entity_map.leak_detector_snapshot();
1196
1197        let slot = entity_map.reserve::<TestEntity>();
1198        let leaked = entity_map.insert(slot, TestEntity { i: 2 });
1199
1200        // `leaked` is still alive, so this should panic.
1201        entity_map.assert_no_new_leaks(&snapshot);
1202
1203        drop(pre_existing);
1204        drop(leaked);
1205    }
1206}