# Entity Patterns Common patterns and use cases for entity management in GPUI. ## Application Scenarios ### Model-View Separation Separate business logic (model) from UI (view) using entities. ```rust struct CounterModel { count: usize, listeners: Vec>, } struct CounterView { model: Entity, } impl CounterModel { fn increment(&mut self, cx: &mut Context) { self.count += 1; // Notify listeners for listener in &self.listeners { listener(self.count); } cx.notify(); } fn decrement(&mut self, cx: &mut Context) { if self.count > 0 { self.count -= 1; cx.notify(); } } } impl CounterView { fn new(cx: &mut App) -> Entity { let model = cx.new(|_cx| CounterModel { count: 0, listeners: Vec::new(), }); cx.new(|cx| Self { model }) } fn increment_count(&mut self, cx: &mut Context) { self.model.update(cx, |model, cx| { model.increment(cx); }); } } impl Render for CounterView { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let count = self.model.read(cx).count; div() .child(format!("Count: {}", count)) .child( Button::new("increment") .label("Increment") .on_click(cx.listener(|this, _, cx| { this.increment_count(cx); })) ) } } ``` ### Component State Management Managing complex component state with entities. ```rust struct TodoList { todos: Vec, filter: TodoFilter, next_id: usize, } struct Todo { id: usize, text: String, completed: bool, } enum TodoFilter { All, Active, Completed, } impl TodoList { fn new() -> Self { Self { todos: Vec::new(), filter: TodoFilter::All, next_id: 0, } } fn add_todo(&mut self, text: String, cx: &mut Context) { self.todos.push(Todo { id: self.next_id, text, completed: false, }); self.next_id += 1; cx.notify(); } fn toggle_todo(&mut self, id: usize, cx: &mut Context) { if let Some(todo) = self.todos.iter_mut().find(|t| t.id == id) { todo.completed = !todo.completed; cx.notify(); } } fn remove_todo(&mut self, id: usize, cx: &mut Context) { self.todos.retain(|t| t.id != id); cx.notify(); } fn set_filter(&mut self, filter: TodoFilter, cx: &mut Context) { self.filter = filter; cx.notify(); } fn visible_todos(&self) -> impl Iterator { self.todos.iter().filter(move |todo| match self.filter { TodoFilter::All => true, TodoFilter::Active => !todo.completed, TodoFilter::Completed => todo.completed, }) } } ``` ### Cross-Entity Communication Coordinating state between parent and child entities. ```rust struct ParentComponent { child_entities: Vec>, global_message: String, } struct ChildComponent { id: usize, message: String, parent: WeakEntity, } impl ParentComponent { fn new(cx: &mut App) -> Entity { cx.new(|cx| Self { child_entities: Vec::new(), global_message: String::new(), }) } fn add_child(&mut self, cx: &mut Context) { let parent_weak = cx.entity().downgrade(); let child_id = self.child_entities.len(); let child = cx.new(|cx| ChildComponent { id: child_id, message: String::new(), parent: parent_weak, }); self.child_entities.push(child); cx.notify(); } fn broadcast_message(&mut self, message: String, cx: &mut Context) { self.global_message = message.clone(); // Update all children for child in &self.child_entities { child.update(cx, |child_state, cx| { child_state.message = message.clone(); cx.notify(); }); } cx.notify(); } } impl ChildComponent { fn notify_parent(&mut self, message: String, cx: &mut Context) { if let Ok(_) = self.parent.update(cx, |parent_state, cx| { parent_state.global_message = format!("Child {}: {}", self.id, message); cx.notify(); }) { // Parent successfully notified } } } ``` ### Async Operations with Entities Managing async state updates. ```rust struct DataLoader { loading: bool, data: Option, error: Option, } impl DataLoader { fn new() -> Self { Self { loading: false, data: None, error: None, } } fn load_data(&mut self, cx: &mut Context) { // Set loading state self.loading = true; self.error = None; cx.notify(); // Get weak reference for async task let entity = cx.entity().downgrade(); cx.spawn(async move |cx| { // Simulate async operation tokio::time::sleep(Duration::from_secs(2)).await; let result = fetch_data().await; // Update entity with result let _ = entity.update(cx, |state, cx| { state.loading = false; match result { Ok(data) => state.data = Some(data), Err(e) => state.error = Some(e.to_string()), } cx.notify(); }); }).detach(); } } async fn fetch_data() -> Result { // Actual fetch implementation Ok("Fetched data".to_string()) } ``` ### Background Task Coordination Using background tasks with entity updates. ```rust struct ImageProcessor { images: Vec, processing: bool, } struct ProcessedImage { path: PathBuf, thumbnail: Option>, } impl ImageProcessor { fn process_images(&mut self, paths: Vec, cx: &mut Context) { self.processing = true; cx.notify(); let entity = cx.entity().downgrade(); cx.background_spawn({ let paths = paths.clone(); async move { let mut processed = Vec::new(); for path in paths { // Process image on background thread let thumbnail = generate_thumbnail(&path).await; processed.push((path, thumbnail)); } // Send results back to foreground processed } }) .then(cx.spawn(move |processed, cx| { // Update entity on foreground thread let _ = entity.update(cx, |state, cx| { for (path, thumbnail) in processed { state.images.push(ProcessedImage { path, thumbnail: Some(thumbnail), }); } state.processing = false; cx.notify(); }); })) .detach(); } } ``` ## Common Patterns ### 1. Stateful Components Use entities for components that maintain internal state. ```rust struct StatefulComponent { value: i32, history: Vec, } impl StatefulComponent { fn update_value(&mut self, new_value: i32, cx: &mut Context) { self.history.push(self.value); self.value = new_value; cx.notify(); } fn undo(&mut self, cx: &mut Context) { if let Some(prev_value) = self.history.pop() { self.value = prev_value; cx.notify(); } } } ``` ### 2. Shared State Share state between multiple components using entities. ```rust struct SharedState { theme: Theme, user: Option, } struct ComponentA { shared: Entity, } struct ComponentB { shared: Entity, } // Both components can read/update the same shared state impl ComponentA { fn update_theme(&mut self, theme: Theme, cx: &mut Context) { self.shared.update(cx, |state, cx| { state.theme = theme; cx.notify(); }); } } ``` ### 3. Event Coordination Use entities to coordinate events between components. ```rust struct EventCoordinator { listeners: Vec>, } trait EventListener { fn on_event(&mut self, event: &AppEvent, cx: &mut App); } impl EventCoordinator { fn emit_event(&mut self, event: AppEvent, cx: &mut Context) { // Notify all listeners self.listeners.retain(|weak_listener| { weak_listener.update(cx, |listener, cx| { listener.on_event(&event, cx); }).is_ok() }); cx.notify(); } } ``` ### 4. Async State Management Manage state that changes based on async operations. ```rust struct AsyncState { state: AsyncValue, } enum AsyncValue { Loading, Loaded(T), Error(String), } impl AsyncState { fn is_loading(&self) -> bool { matches!(self.state, AsyncValue::Loading) } fn value(&self) -> Option<&T> { match &self.state { AsyncValue::Loaded(v) => Some(v), _ => None, } } } ``` ### 5. Parent-Child Relationships Manage hierarchical relationships with weak references. ```rust struct Parent { children: Vec>, } struct Child { parent: WeakEntity, data: String, } impl Child { fn notify_parent_of_change(&mut self, cx: &mut Context) { if let Ok(_) = self.parent.update(cx, |parent, cx| { // Parent can react to child change cx.notify(); }) { // Successfully notified } } } ``` ### 6. Observer Pattern React to entity state changes using observers. ```rust struct Observable { value: i32, } struct Observer { observed: Entity, } impl Observer { fn new(observed: Entity, cx: &mut App) -> Entity { cx.new(|cx| { // Observe the entity cx.observe(&observed, |this, observed_entity, cx| { // React to changes let value = observed_entity.read(cx).value; println!("Value changed to: {}", value); }).detach(); Self { observed } }) } } ``` ### 7. Event Subscription Handle events emitted by other entities. ```rust #[derive(Clone)] enum DataEvent { Updated, Deleted, } struct DataSource { data: Vec, } impl DataSource { fn update_data(&mut self, cx: &mut Context) { // Update data cx.emit(DataEvent::Updated); cx.notify(); } } struct DataConsumer { source: Entity, } impl DataConsumer { fn new(source: Entity, cx: &mut App) -> Entity { cx.new(|cx| { // Subscribe to events cx.subscribe(&source, |this, source, event: &DataEvent, cx| { match event { DataEvent::Updated => { // Handle update cx.notify(); } DataEvent::Deleted => { // Handle deletion } } }).detach(); Self { source } }) } } ``` ### 8. Resource Management Manage external resources with proper cleanup. ```rust struct FileHandle { path: PathBuf, file: Option, } impl FileHandle { fn open(&mut self, cx: &mut Context) -> Result<()> { self.file = Some(File::open(&self.path)?); cx.notify(); Ok(()) } fn close(&mut self, cx: &mut Context) { self.file = None; cx.notify(); } } impl Drop for FileHandle { fn drop(&mut self) { // Cleanup when entity is dropped if let Some(file) = self.file.take() { drop(file); } } } ``` ## Pattern Selection Guide | Need | Pattern | Complexity | |------|---------|------------| | Component with internal state | Stateful Components | Low | | State shared by multiple components | Shared State | Low | | Coordinate events between components | Event Coordination | Medium | | Handle async data fetching | Async State Management | Medium | | Parent-child component hierarchy | Parent-Child Relationships | Medium | | React to state changes | Observer Pattern | Medium | | Handle custom events | Event Subscription | Medium-High | | Manage external resources | Resource Management | High | Choose the simplest pattern that meets your requirements. Combine patterns as needed for complex scenarios.