2023-09-20 16:17:29 +00:00
|
|
|
use crate::{
|
2023-09-25 17:47:37 +00:00
|
|
|
current_platform, AnyWindowHandle, Context, LayoutId, MainThreadOnly, Platform, Reference,
|
|
|
|
RootView, TextSystem, Window, WindowContext, WindowHandle, WindowId,
|
2023-09-20 16:17:29 +00:00
|
|
|
};
|
2023-09-19 19:19:22 +00:00
|
|
|
use anyhow::{anyhow, Result};
|
2023-09-25 17:47:37 +00:00
|
|
|
use collections::{HashMap, VecDeque};
|
2023-09-23 18:21:52 +00:00
|
|
|
use futures::{future, Future};
|
2023-09-22 18:44:37 +00:00
|
|
|
use parking_lot::Mutex;
|
2023-09-19 19:19:22 +00:00
|
|
|
use slotmap::SlotMap;
|
2023-09-25 17:47:37 +00:00
|
|
|
use smallvec::SmallVec;
|
2023-09-22 14:33:51 +00:00
|
|
|
use std::{
|
|
|
|
any::Any,
|
|
|
|
marker::PhantomData,
|
|
|
|
sync::{Arc, Weak},
|
|
|
|
};
|
2023-09-27 21:35:46 +00:00
|
|
|
use util::ResultExt;
|
2023-09-19 19:19:22 +00:00
|
|
|
|
2023-09-20 16:17:29 +00:00
|
|
|
#[derive(Clone)]
|
2023-09-22 18:44:37 +00:00
|
|
|
pub struct App(Arc<Mutex<AppContext>>);
|
2023-09-19 19:19:22 +00:00
|
|
|
|
2023-09-20 16:17:29 +00:00
|
|
|
impl App {
|
2023-09-22 16:02:11 +00:00
|
|
|
pub fn production() -> Self {
|
|
|
|
Self::new(current_platform())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(test, feature = "test"))]
|
|
|
|
pub fn test() -> Self {
|
|
|
|
Self::new(Arc::new(super::TestPlatform::new()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn new(platform: Arc<dyn Platform>) -> Self {
|
2023-09-22 18:44:37 +00:00
|
|
|
let dispatcher = platform.dispatcher();
|
2023-09-22 16:02:11 +00:00
|
|
|
let text_system = Arc::new(TextSystem::new(platform.text_system()));
|
|
|
|
let mut entities = SlotMap::with_key();
|
2023-09-26 17:29:44 +00:00
|
|
|
let unit_entity = Handle::new(entities.insert(Some(Box::new(()) as Box<dyn Any + Send>)));
|
2023-09-22 16:02:11 +00:00
|
|
|
Self(Arc::new_cyclic(|this| {
|
2023-09-22 18:44:37 +00:00
|
|
|
Mutex::new(AppContext {
|
2023-09-22 16:02:11 +00:00
|
|
|
this: this.clone(),
|
2023-09-22 18:44:37 +00:00
|
|
|
platform: MainThreadOnly::new(platform, dispatcher),
|
2023-09-22 16:02:11 +00:00
|
|
|
text_system,
|
2023-09-26 17:29:44 +00:00
|
|
|
unit_entity,
|
2023-09-22 16:02:11 +00:00
|
|
|
entities,
|
|
|
|
windows: SlotMap::with_key(),
|
2023-09-25 17:47:37 +00:00
|
|
|
pending_updates: 0,
|
|
|
|
pending_effects: Default::default(),
|
|
|
|
observers: Default::default(),
|
2023-09-22 16:02:11 +00:00
|
|
|
layout_id_buffer: Default::default(),
|
|
|
|
})
|
|
|
|
}))
|
2023-09-20 18:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run<F>(self, on_finish_launching: F)
|
|
|
|
where
|
2023-09-22 18:44:37 +00:00
|
|
|
F: 'static + FnOnce(&mut AppContext),
|
2023-09-20 18:03:37 +00:00
|
|
|
{
|
2023-09-22 18:52:52 +00:00
|
|
|
let this = self.clone();
|
2023-09-22 18:44:37 +00:00
|
|
|
let platform = self.0.lock().platform.clone();
|
|
|
|
platform.borrow_on_main_thread().run(Box::new(move || {
|
2023-09-22 18:52:52 +00:00
|
|
|
let cx = &mut *this.0.lock();
|
2023-09-22 16:02:11 +00:00
|
|
|
on_finish_launching(cx);
|
2023-09-20 18:03:37 +00:00
|
|
|
}));
|
2023-09-20 16:17:29 +00:00
|
|
|
}
|
|
|
|
}
|
2023-09-19 19:19:22 +00:00
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
|
|
|
|
|
2023-09-22 18:44:37 +00:00
|
|
|
pub struct AppContext {
|
|
|
|
this: Weak<Mutex<AppContext>>,
|
|
|
|
platform: MainThreadOnly<dyn Platform>,
|
2023-09-20 18:03:37 +00:00
|
|
|
text_system: Arc<TextSystem>,
|
2023-09-26 17:29:44 +00:00
|
|
|
pub(crate) unit_entity: Handle<()>,
|
2023-09-22 18:44:37 +00:00
|
|
|
pub(crate) entities: SlotMap<EntityId, Option<Box<dyn Any + Send>>>,
|
2023-09-19 19:19:22 +00:00
|
|
|
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
|
2023-09-25 17:47:37 +00:00
|
|
|
pending_updates: usize,
|
|
|
|
pub(crate) pending_effects: VecDeque<Effect>,
|
|
|
|
pub(crate) observers: HashMap<EntityId, Handlers>,
|
2023-09-19 19:19:22 +00:00
|
|
|
// We recycle this memory across layout requests.
|
|
|
|
pub(crate) layout_id_buffer: Vec<LayoutId>,
|
|
|
|
}
|
|
|
|
|
2023-09-22 18:44:37 +00:00
|
|
|
impl AppContext {
|
2023-09-20 18:03:37 +00:00
|
|
|
pub fn text_system(&self) -> &Arc<TextSystem> {
|
|
|
|
&self.text_system
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
|
2023-09-26 17:29:44 +00:00
|
|
|
pub fn to_async(&self) -> AsyncContext {
|
|
|
|
AsyncContext(self.this.clone())
|
|
|
|
}
|
|
|
|
|
2023-09-22 20:40:39 +00:00
|
|
|
pub fn spawn_on_main<F, R>(
|
2023-09-26 17:29:44 +00:00
|
|
|
&self,
|
2023-09-22 20:40:39 +00:00
|
|
|
f: impl FnOnce(&dyn Platform, &mut Self) -> F + Send + 'static,
|
|
|
|
) -> impl Future<Output = R>
|
|
|
|
where
|
2023-09-23 18:21:52 +00:00
|
|
|
F: Future<Output = R> + 'static,
|
2023-09-22 20:40:39 +00:00
|
|
|
R: Send + 'static,
|
|
|
|
{
|
2023-09-22 18:44:37 +00:00
|
|
|
let this = self.this.upgrade().unwrap();
|
|
|
|
self.platform.read(move |platform| {
|
|
|
|
let cx = &mut *this.lock();
|
2023-09-26 17:34:41 +00:00
|
|
|
cx.update(|cx| f(platform, cx))
|
2023-09-22 18:44:37 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-09-26 17:29:44 +00:00
|
|
|
pub fn open_window<S: 'static + Send + Sync>(
|
2023-09-19 19:19:22 +00:00
|
|
|
&mut self,
|
|
|
|
options: crate::WindowOptions,
|
2023-09-22 18:44:37 +00:00
|
|
|
build_root_view: impl FnOnce(&mut WindowContext) -> RootView<S> + Send + 'static,
|
|
|
|
) -> impl Future<Output = WindowHandle<S>> {
|
2023-09-22 20:40:39 +00:00
|
|
|
let id = self.windows.insert(None);
|
|
|
|
let handle = WindowHandle::new(id);
|
2023-09-23 18:21:52 +00:00
|
|
|
self.spawn_on_main(move |platform, cx| {
|
2023-09-26 17:29:44 +00:00
|
|
|
let mut window = Window::new(handle.into(), options, platform, cx);
|
2023-09-22 18:44:37 +00:00
|
|
|
let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window));
|
2023-09-26 17:29:44 +00:00
|
|
|
window.root_view.replace(root_view.into_any());
|
2023-09-22 18:44:37 +00:00
|
|
|
cx.windows.get_mut(id).unwrap().replace(window);
|
2023-09-23 18:21:52 +00:00
|
|
|
future::ready(handle)
|
|
|
|
})
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn update_window<R>(
|
|
|
|
&mut self,
|
2023-09-25 17:55:05 +00:00
|
|
|
id: WindowId,
|
2023-09-22 18:44:37 +00:00
|
|
|
update: impl FnOnce(&mut WindowContext) -> R,
|
2023-09-19 19:19:22 +00:00
|
|
|
) -> Result<R> {
|
2023-09-26 17:34:41 +00:00
|
|
|
self.update(|cx| {
|
|
|
|
let mut window = cx
|
|
|
|
.windows
|
|
|
|
.get_mut(id)
|
|
|
|
.ok_or_else(|| anyhow!("window not found"))?
|
|
|
|
.take()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let result = update(&mut WindowContext::mutable(cx, &mut window));
|
|
|
|
window.dirty = true;
|
|
|
|
|
|
|
|
cx.windows
|
|
|
|
.get_mut(id)
|
|
|
|
.ok_or_else(|| anyhow!("window not found"))?
|
|
|
|
.replace(window);
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
})
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
2023-09-25 17:47:37 +00:00
|
|
|
|
|
|
|
fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
|
|
|
|
self.pending_updates += 1;
|
|
|
|
let result = update(self);
|
|
|
|
self.pending_updates -= 1;
|
|
|
|
if self.pending_updates == 0 {
|
|
|
|
self.flush_effects();
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flush_effects(&mut self) {
|
|
|
|
while let Some(effect) = self.pending_effects.pop_front() {
|
|
|
|
match effect {
|
|
|
|
Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
|
|
|
|
}
|
|
|
|
}
|
2023-09-25 17:55:05 +00:00
|
|
|
|
|
|
|
let dirty_window_ids = self
|
|
|
|
.windows
|
|
|
|
.iter()
|
|
|
|
.filter_map(|(window_id, window)| {
|
|
|
|
let window = window.as_ref().unwrap();
|
|
|
|
if window.dirty {
|
|
|
|
Some(window_id)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for dirty_window_id in dirty_window_ids {
|
2023-09-27 21:35:46 +00:00
|
|
|
self.update_window(dirty_window_id, |cx| cx.draw())
|
|
|
|
.unwrap() // We know we have the window.
|
|
|
|
.log_err();
|
2023-09-25 17:55:05 +00:00
|
|
|
}
|
2023-09-25 17:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn apply_notify_effect(&mut self, updated_entity: EntityId) {
|
|
|
|
if let Some(mut handlers) = self.observers.remove(&updated_entity) {
|
|
|
|
handlers.retain(|handler| handler(self));
|
|
|
|
if let Some(new_handlers) = self.observers.remove(&updated_entity) {
|
|
|
|
handlers.extend(new_handlers);
|
|
|
|
}
|
|
|
|
self.observers.insert(updated_entity, handlers);
|
|
|
|
}
|
|
|
|
}
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
|
2023-09-22 18:44:37 +00:00
|
|
|
impl Context for AppContext {
|
2023-09-25 17:47:37 +00:00
|
|
|
type EntityContext<'a, 'w, T: Send + Sync + 'static> = ModelContext<'a, T>;
|
2023-09-26 17:29:44 +00:00
|
|
|
type Result<T> = T;
|
2023-09-19 19:19:22 +00:00
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
fn entity<T: Send + Sync + 'static>(
|
2023-09-19 19:19:22 +00:00
|
|
|
&mut self,
|
|
|
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
|
|
|
) -> Handle<T> {
|
|
|
|
let id = self.entities.insert(None);
|
|
|
|
let entity = Box::new(build_entity(&mut ModelContext::mutable(self, id)));
|
|
|
|
self.entities.get_mut(id).unwrap().replace(entity);
|
|
|
|
|
|
|
|
Handle::new(id)
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
fn update_entity<T: Send + Sync + 'static, R>(
|
2023-09-19 19:19:22 +00:00
|
|
|
&mut self,
|
|
|
|
handle: &Handle<T>,
|
|
|
|
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
|
|
|
) -> R {
|
|
|
|
let mut entity = self
|
|
|
|
.entities
|
|
|
|
.get_mut(handle.id)
|
|
|
|
.unwrap()
|
|
|
|
.take()
|
|
|
|
.unwrap()
|
|
|
|
.downcast::<T>()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let result = update(&mut *entity, &mut ModelContext::mutable(self, handle.id));
|
|
|
|
self.entities.get_mut(handle.id).unwrap().replace(entity);
|
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-26 17:29:44 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct AsyncContext(Weak<Mutex<AppContext>>);
|
|
|
|
|
|
|
|
impl Context for AsyncContext {
|
|
|
|
type EntityContext<'a, 'b, T: Send + Sync + 'static> = ModelContext<'a, T>;
|
|
|
|
type Result<T> = Result<T>;
|
|
|
|
|
|
|
|
fn entity<T: Send + Sync + 'static>(
|
|
|
|
&mut self,
|
|
|
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
|
|
|
) -> Result<Handle<T>> {
|
|
|
|
let app = self
|
|
|
|
.0
|
|
|
|
.upgrade()
|
|
|
|
.ok_or_else(|| anyhow!("app was released"))?;
|
|
|
|
let mut lock = app.lock();
|
|
|
|
Ok(lock.entity(build_entity))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_entity<T: Send + Sync + 'static, R>(
|
|
|
|
&mut self,
|
|
|
|
handle: &Handle<T>,
|
|
|
|
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
|
|
|
) -> Result<R> {
|
|
|
|
let app = self
|
|
|
|
.0
|
|
|
|
.upgrade()
|
|
|
|
.ok_or_else(|| anyhow!("app was released"))?;
|
|
|
|
let mut lock = app.lock();
|
|
|
|
Ok(lock.update_entity(handle, update))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsyncContext {
|
|
|
|
pub fn update_window<T>(
|
|
|
|
&self,
|
|
|
|
handle: AnyWindowHandle,
|
|
|
|
update: impl FnOnce(&mut WindowContext) -> T + Send + Sync,
|
|
|
|
) -> Result<T> {
|
|
|
|
let app = self
|
|
|
|
.0
|
|
|
|
.upgrade()
|
|
|
|
.ok_or_else(|| anyhow!("app was released"))?;
|
|
|
|
let mut app_context = app.lock();
|
|
|
|
app_context.update_window(handle.id, update)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-22 18:44:37 +00:00
|
|
|
pub struct ModelContext<'a, T> {
|
|
|
|
app: Reference<'a, AppContext>,
|
2023-09-19 19:19:22 +00:00
|
|
|
entity_type: PhantomData<T>,
|
|
|
|
entity_id: EntityId,
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
|
2023-09-22 18:44:37 +00:00
|
|
|
pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
|
2023-09-19 19:19:22 +00:00
|
|
|
Self {
|
|
|
|
app: Reference::Mutable(app),
|
|
|
|
entity_type: PhantomData,
|
|
|
|
entity_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-27 23:25:04 +00:00
|
|
|
// todo!
|
|
|
|
// fn update<R>(&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::<T>().unwrap(), self);
|
|
|
|
// self.app
|
|
|
|
// .entities
|
|
|
|
// .get_mut(self.entity_id)
|
|
|
|
// .unwrap()
|
|
|
|
// .replace(entity);
|
|
|
|
// result
|
|
|
|
// }
|
2023-09-25 17:47:37 +00:00
|
|
|
|
|
|
|
pub fn handle(&self) -> WeakHandle<T> {
|
|
|
|
WeakHandle {
|
|
|
|
id: self.entity_id,
|
|
|
|
entity_type: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn observe<E: Send + Sync + 'static>(
|
|
|
|
&mut self,
|
|
|
|
handle: &Handle<E>,
|
|
|
|
on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
|
|
|
|
) {
|
|
|
|
let this = self.handle();
|
|
|
|
let handle = handle.downgrade();
|
|
|
|
self.app
|
|
|
|
.observers
|
|
|
|
.entry(handle.id)
|
|
|
|
.or_default()
|
|
|
|
.push(Arc::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 notify(&mut self) {
|
|
|
|
self.app
|
|
|
|
.pending_effects
|
|
|
|
.push_back(Effect::Notify(self.entity_id));
|
|
|
|
}
|
2023-09-19 19:19:22 +00:00
|
|
|
}
|
|
|
|
|
2023-09-22 18:44:37 +00:00
|
|
|
impl<'a, T: 'static> Context for ModelContext<'a, T> {
|
2023-09-25 17:47:37 +00:00
|
|
|
type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
|
2023-09-26 17:29:44 +00:00
|
|
|
type Result<U> = U;
|
2023-09-22 18:44:37 +00:00
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
fn entity<U: Send + Sync + 'static>(
|
2023-09-19 19:19:22 +00:00
|
|
|
&mut self,
|
|
|
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
|
|
|
|
) -> Handle<U> {
|
|
|
|
self.app.entity(build_entity)
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
fn update_entity<U: Send + Sync + 'static, R>(
|
2023-09-19 19:19:22 +00:00
|
|
|
&mut self,
|
|
|
|
handle: &Handle<U>,
|
|
|
|
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
|
|
|
|
) -> R {
|
|
|
|
self.app.update_entity(handle, update)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
slotmap::new_key_type! { pub struct EntityId; }
|
|
|
|
|
2023-09-19 19:19:22 +00:00
|
|
|
pub struct Handle<T> {
|
|
|
|
pub(crate) id: EntityId,
|
|
|
|
pub(crate) entity_type: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
impl<T: Send + Sync + 'static> Handle<T> {
|
2023-09-19 19:19:22 +00:00
|
|
|
fn new(id: EntityId) -> Self {
|
|
|
|
Self {
|
|
|
|
id,
|
|
|
|
entity_type: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
pub fn downgrade(&self) -> WeakHandle<T> {
|
|
|
|
WeakHandle {
|
|
|
|
id: self.id,
|
|
|
|
entity_type: self.entity_type,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-19 19:19:22 +00:00
|
|
|
/// Update the entity referenced by this handle with the given function.
|
|
|
|
///
|
|
|
|
/// The update function receives a context appropriate for its environment.
|
|
|
|
/// When updating in an `AppContext`, it receives a `ModelContext`.
|
|
|
|
/// When updating an a `WindowContext`, it receives a `ViewContext`.
|
|
|
|
pub fn update<C: Context, R>(
|
|
|
|
&self,
|
|
|
|
cx: &mut C,
|
|
|
|
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
|
2023-09-26 17:29:44 +00:00
|
|
|
) -> C::Result<R> {
|
2023-09-19 19:19:22 +00:00
|
|
|
cx.update_entity(self, update)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Clone for Handle<T> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self {
|
|
|
|
id: self.id,
|
|
|
|
entity_type: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-22 18:44:37 +00:00
|
|
|
|
2023-09-25 17:47:37 +00:00
|
|
|
pub struct WeakHandle<T> {
|
|
|
|
pub(crate) id: EntityId,
|
|
|
|
pub(crate) entity_type: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Send + Sync + 'static> WeakHandle<T> {
|
2023-09-27 23:25:04 +00:00
|
|
|
pub fn upgrade(&self, _: &impl Context) -> Option<Handle<T>> {
|
2023-09-25 17:47:37 +00:00
|
|
|
// todo!("Actually upgrade")
|
|
|
|
Some(Handle {
|
|
|
|
id: self.id,
|
|
|
|
entity_type: self.entity_type,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Update the entity referenced by this handle with the given function if
|
|
|
|
/// the referenced entity still exists. Returns an error if the entity has
|
|
|
|
/// been released.
|
|
|
|
///
|
|
|
|
/// The update function receives a context appropriate for its environment.
|
|
|
|
/// When updating in an `AppContext`, it receives a `ModelContext`.
|
|
|
|
/// When updating an a `WindowContext`, it receives a `ViewContext`.
|
|
|
|
pub fn update<C: Context, R>(
|
|
|
|
&self,
|
|
|
|
cx: &mut C,
|
|
|
|
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
|
2023-09-26 17:29:44 +00:00
|
|
|
) -> Result<R>
|
|
|
|
where
|
|
|
|
Result<C::Result<R>>: crate::Flatten<R>,
|
|
|
|
{
|
|
|
|
crate::Flatten::flatten(
|
|
|
|
self.upgrade(cx)
|
|
|
|
.ok_or_else(|| anyhow!("entity release"))
|
|
|
|
.map(|this| cx.update_entity(&this, update)),
|
|
|
|
)
|
2023-09-25 17:47:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) enum Effect {
|
|
|
|
Notify(EntityId),
|
|
|
|
}
|
|
|
|
|
2023-09-22 18:44:37 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::AppContext;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_app_context_send_sync() {
|
|
|
|
// This will not compile if `AppContext` does not implement `Send`
|
|
|
|
fn assert_send<T: Send>() {}
|
|
|
|
assert_send::<AppContext>();
|
|
|
|
}
|
|
|
|
}
|