use crate::{ AppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, Subscription, WeakHandle, }; use std::marker::PhantomData; pub struct ModelContext<'a, T> { app: Reference<'a, AppContext>, entity_type: PhantomData, entity_id: EntityId, } impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self { Self { app: Reference::Mutable(app), entity_type: PhantomData, entity_id, } } // todo! // fn update(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R { // let mut entity = self // .app // .entities // .get_mut(self.entity_id) // .unwrap() // .take() // .unwrap(); // let result = update(entity.downcast_mut::().unwrap(), self); // self.app // .entities // .get_mut(self.entity_id) // .unwrap() // .replace(entity); // result // } pub fn handle(&self) -> WeakHandle { self.app.entities.weak_handle(self.entity_id) } pub fn observe( &mut self, handle: &Handle, on_notify: impl Fn(&mut T, Handle, &mut ModelContext<'_, T>) + Send + Sync + 'static, ) -> Subscription { let this = self.handle(); let handle = handle.downgrade(); self.app.observers.insert( handle.id, Box::new(move |cx| { if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) { this.update(cx, |this, cx| on_notify(this, handle, cx)); true } else { false } }), ) } pub fn subscribe( &mut self, handle: &Handle, on_event: impl Fn(&mut T, Handle, &E::Event, &mut ModelContext<'_, T>) + Send + Sync + 'static, ) -> Subscription { let this = self.handle(); let handle = handle.downgrade(); self.app.event_handlers.insert( handle.id, Box::new(move |event, cx| { let event = event.downcast_ref().expect("invalid event type"); if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) { this.update(cx, |this, cx| on_event(this, handle, event, cx)); true } else { false } }), ) } pub fn on_release( &mut self, on_release: impl Fn(&mut T, &mut AppContext) + Send + Sync + 'static, ) -> Subscription { self.app.release_handlers.insert( self.entity_id, Box::new(move |this, cx| { let this = this.downcast_mut().expect("invalid entity type"); on_release(this, cx); }), ) } pub fn observe_release( &mut self, handle: &Handle, on_release: impl Fn(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static, ) -> Subscription { let this = self.handle(); self.app.release_handlers.insert( handle.id, Box::new(move |entity, cx| { let entity = entity.downcast_mut().expect("invalid entity type"); if let Some(this) = this.upgrade(cx) { this.update(cx, |this, cx| on_release(this, entity, cx)); } }), ) } pub fn notify(&mut self) { self.app.push_effect(Effect::Notify { emitter: self.entity_id, }); } } impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> { pub fn emit(&mut self, event: T::Event) { self.app.push_effect(Effect::Emit { emitter: self.entity_id, event: Box::new(event), }); } } impl<'a, T: 'static> Context for ModelContext<'a, T> { type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>; type Result = U; fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U, ) -> Handle { self.app.entity(build_entity) } fn update_entity( &mut self, handle: &Handle, update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R, ) -> R { self.app.update_entity(handle, update) } }