Skip to main content

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