# Entity API Reference Complete API documentation for GPUI's entity system. ## Entity Types ### Entity A strong reference to state of type `T`. **Methods:** - `entity_id()` → `EntityId` - Returns unique identifier - `downgrade()` → `WeakEntity` - Creates weak reference - `read(cx)` → `&T` - Immutable access to state - `read_with(cx, |state, cx| ...)` → `R` - Read with closure, returns closure result - `update(cx, |state, cx| ...)` → `R` - Mutable update with `Context`, returns closure result - `update_in(cx, |state, window, cx| ...)` → `R` - Update with `Window` access (requires `AsyncWindowContext` or `VisualTestContext`) **Important Notes:** - Trying to update an entity while it's already being updated will panic - Within closures, use the inner `cx` provided to avoid multiple borrow issues - With async contexts, return values are wrapped in `anyhow::Result` ### WeakEntity A weak reference to state of type `T`. **Methods:** - `upgrade()` → `Option>` - Convert to strong reference if still alive - `read_with(cx, |state, cx| ...)` → `Result` - Read if entity exists - `update(cx, |state, cx| ...)` → `Result` - Update if entity exists - `update_in(cx, |state, window, cx| ...)` → `Result` - Update with window if entity exists **Use Cases:** - Avoid circular dependencies between entities - Store references in closures/callbacks without preventing cleanup - Optional relationships between components **Important:** All operations return `Result` since the entity may no longer exist. ### AnyEntity Dynamically-typed entity handle for storing entities of different types. ### AnyWeakEntity Dynamically-typed weak entity handle. ## Entity Creation ### cx.new() Create new entity with initial state. ```rust let entity = cx.new(|cx| MyState { count: 0, name: "Default".to_string(), }); ``` **Parameters:** - `cx: &mut App` or other context type - Closure receiving `&mut Context` returning initial state `T` **Returns:** `Entity` ## Entity Operations ### Reading State #### read() Direct read-only access to state. ```rust let count = my_entity.read(cx).count; ``` **Use when:** Simple field access, no context operations needed. #### read_with() Read with context access in closure. ```rust let count = my_entity.read_with(cx, |state, cx| { // Can access both state and context state.count }); // Return multiple values let (count, theme) = my_entity.read_with(cx, |state, cx| { (state.count, cx.theme().clone()) }); ``` **Use when:** Need context operations, multiple return values, complex logic. ### Updating State #### update() Mutable update with `Context`. ```rust my_entity.update(cx, |state, cx| { state.count += 1; cx.notify(); // Trigger re-render }); ``` **Available Operations:** - `cx.notify()` - Trigger re-render - `cx.entity()` - Get current entity - `cx.emit(event)` - Emit event - `cx.spawn(task)` - Spawn async task - Other `Context` methods #### update_in() Update with both `Window` and `Context` access. ```rust my_entity.update_in(cx, |state, window, cx| { state.focused = window.is_window_focused(); cx.notify(); }); ``` **Requires:** `AsyncWindowContext` or `VisualTestContext` **Use when:** Need window-specific operations like focus state, window bounds, etc. ## Context Methods for Entities ### cx.entity() Get current entity being updated. ```rust impl MyComponent { fn some_method(&mut self, cx: &mut Context) { let current_entity = cx.entity(); // Entity let weak = current_entity.downgrade(); } } ``` ### cx.observe() Observe entity for changes. ```rust cx.observe(&entity, |this, observed_entity, cx| { // Called when observed_entity.update() calls cx.notify() println!("Entity changed"); }).detach(); ``` **Returns:** `Subscription` - Call `.detach()` to make permanent ### cx.subscribe() Subscribe to events from entity. ```rust cx.subscribe(&entity, |this, emitter, event: &SomeEvent, cx| { // Called when emitter emits SomeEvent match event { SomeEvent::DataChanged => { cx.notify(); } } }).detach(); ``` **Returns:** `Subscription` - Call `.detach()` to make permanent ### cx.observe_new_entities() Register callback for new entities of a type. ```rust cx.observe_new_entities::(|entity, cx| { println!("New entity created: {:?}", entity.entity_id()); }).detach(); ``` ## Async Operations ### cx.spawn() Spawn foreground task (UI thread). ```rust cx.spawn(async move |this, cx| { // `this`: WeakEntity // `cx`: &mut AsyncApp let result = some_async_work().await; // Update entity safely let _ = this.update(cx, |state, cx| { state.data = result; cx.notify(); }); }).detach(); ``` **Note:** Always use weak entity reference in spawned tasks to prevent retain cycles. ### cx.background_spawn() Spawn background task (background thread). ```rust cx.background_spawn(async move { // Long-running computation let result = heavy_computation().await; // Cannot directly update entities here // Use channels or spawn foreground task to update }).detach(); ``` ## Entity Lifecycle ### Creation Entities are created via `cx.new()` and immediately registered in the app. ### Reference Counting - `Entity` is a strong reference (increases reference count) - `WeakEntity` is a weak reference (does not increase reference count) - Cloning `Entity` increases reference count ### Disposal Entities are automatically disposed when all strong references are dropped. ```rust { let entity = cx.new(|cx| MyState::default()); // entity exists } // entity dropped here if no other strong references exist ``` **Memory Leak Prevention:** - Use `WeakEntity` in closures/callbacks - Use `WeakEntity` for parent-child relationships - Avoid circular strong references ## EntityId Every entity has a unique identifier. ```rust let id: EntityId = entity.entity_id(); // EntityIds can be compared if entity1.entity_id() == entity2.entity_id() { // Same entity } ``` **Use Cases:** - Debugging and logging - Entity comparison without borrowing - Hash maps keyed by entity ## Error Handling ### WeakEntity Operations All `WeakEntity` operations return `Result`: ```rust let weak = entity.downgrade(); // Handle potential failure match weak.read_with(cx, |state, cx| state.count) { Ok(count) => println!("Count: {}", count), Err(e) => eprintln!("Entity no longer exists: {}", e), } // Or use Result combinators let _ = weak.update(cx, |state, cx| { state.count += 1; cx.notify(); }).ok(); // Ignore errors ``` ### Update Panics Nested updates on the same entity will panic: ```rust // ❌ Will panic entity.update(cx, |state1, cx| { entity.update(cx, |state2, cx| { // Panic: entity already borrowed }); }); ``` **Solution:** Perform updates sequentially or use different entities. ## Type Conversions ### Entity → WeakEntity ```rust let entity: Entity = cx.new(|cx| T::default()); let weak: WeakEntity = entity.downgrade(); ``` ### WeakEntity → Entity ```rust let weak: WeakEntity = entity.downgrade(); let strong: Option> = weak.upgrade(); ``` ### AnyEntity ```rust let any: AnyEntity = entity.into(); let typed: Option> = any.downcast::(); ``` ## Best Practice Guidelines ### Always Use Inner cx ```rust // ✅ Good: Use inner cx entity.update(cx, |state, inner_cx| { inner_cx.notify(); // Use inner_cx, not outer cx }); // ❌ Bad: Use outer cx entity.update(cx, |state, inner_cx| { cx.notify(); // Wrong! Multiple borrow error }); ``` ### Weak References in Closures ```rust // ✅ Good: Weak reference let weak = cx.entity().downgrade(); callback(move || { let _ = weak.update(cx, |state, cx| { cx.notify(); }); }); // ❌ Bad: Strong reference (retain cycle) let strong = cx.entity(); callback(move || { strong.update(cx, |state, cx| { // May never be dropped cx.notify(); }); }); ``` ### Sequential Updates ```rust // ✅ Good: Sequential updates entity1.update(cx, |state, cx| { /* ... */ }); entity2.update(cx, |state, cx| { /* ... */ }); // ❌ Bad: Nested updates entity1.update(cx, |_, cx| { entity2.update(cx, |_, cx| { // May panic if entities are related }); }); ```