1use crate::{
2 AnyView, AnyWindowHandle, App, AppCell, AppContext, BackgroundExecutor, BorrowAppContext,
3 Entity, EventEmitter, Focusable, ForegroundExecutor, Global, PromptButton, PromptLevel, Render,
4 Reservation, Result, Subscription, Task, VisualContext, Window, WindowHandle,
5};
6use anyhow::{Context as _, anyhow};
7use derive_more::{Deref, DerefMut};
8use futures::channel::oneshot;
9use std::{future::Future, rc::Weak};
10
11use super::{Context, WeakEntity};
12
13#[derive(Clone)]
17pub struct AsyncApp {
18 pub(crate) app: Weak<AppCell>,
19 pub(crate) background_executor: BackgroundExecutor,
20 pub(crate) foreground_executor: ForegroundExecutor,
21}
22
23impl AppContext for AsyncApp {
24 type Result<T> = Result<T>;
25
26 fn new<T: 'static>(
27 &mut self,
28 build_entity: impl FnOnce(&mut Context<T>) -> T,
29 ) -> Self::Result<Entity<T>> {
30 let app = self.app.upgrade().context("app was released")?;
31 let mut app = app.borrow_mut();
32 Ok(app.new(build_entity))
33 }
34
35 fn reserve_entity<T: 'static>(&mut self) -> Result<Reservation<T>> {
36 let app = self.app.upgrade().context("app was released")?;
37 let mut app = app.borrow_mut();
38 Ok(app.reserve_entity())
39 }
40
41 fn insert_entity<T: 'static>(
42 &mut self,
43 reservation: Reservation<T>,
44 build_entity: impl FnOnce(&mut Context<T>) -> T,
45 ) -> Result<Entity<T>> {
46 let app = self.app.upgrade().context("app was released")?;
47 let mut app = app.borrow_mut();
48 Ok(app.insert_entity(reservation, build_entity))
49 }
50
51 fn update_entity<T: 'static, R>(
52 &mut self,
53 handle: &Entity<T>,
54 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
55 ) -> Self::Result<R> {
56 let app = self.app.upgrade().context("app was released")?;
57 let mut app = app.borrow_mut();
58 Ok(app.update_entity(handle, update))
59 }
60
61 fn as_mut<'a, T>(&'a mut self, _handle: &Entity<T>) -> Self::Result<super::GpuiBorrow<'a, T>>
62 where
63 T: 'static,
64 {
65 Err(anyhow!(
66 "Cannot as_mut with an async context. Try calling update() first"
67 ))
68 }
69
70 fn read_entity<T, R>(
71 &self,
72 handle: &Entity<T>,
73 callback: impl FnOnce(&T, &App) -> R,
74 ) -> Self::Result<R>
75 where
76 T: 'static,
77 {
78 let app = self.app.upgrade().context("app was released")?;
79 let lock = app.borrow();
80 Ok(lock.read_entity(handle, callback))
81 }
82
83 fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
84 where
85 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
86 {
87 let app = self.app.upgrade().context("app was released")?;
88 let mut lock = app.try_borrow_mut()?;
89 lock.update_window(window, f)
90 }
91
92 fn read_window<T, R>(
93 &self,
94 window: &WindowHandle<T>,
95 read: impl FnOnce(Entity<T>, &App) -> R,
96 ) -> Result<R>
97 where
98 T: 'static,
99 {
100 let app = self.app.upgrade().context("app was released")?;
101 let lock = app.borrow();
102 lock.read_window(window, read)
103 }
104
105 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
106 where
107 R: Send + 'static,
108 {
109 self.background_executor.spawn(future)
110 }
111
112 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
113 where
114 G: Global,
115 {
116 let app = self.app.upgrade().context("app was released")?;
117 let mut lock = app.borrow_mut();
118 Ok(lock.update(|this| this.read_global(callback)))
119 }
120}
121
122impl AsyncApp {
123 pub fn refresh(&self) -> Result<()> {
125 let app = self.app.upgrade().context("app was released")?;
126 let mut lock = app.borrow_mut();
127 lock.update(|cx| cx.refresh_windows());
130 Ok(())
131 }
132
133 pub fn background_executor(&self) -> &BackgroundExecutor {
135 &self.background_executor
136 }
137
138 pub fn is_test(&self) -> bool {
141 self.background_executor.is_test()
142 }
143
144 pub fn foreground_executor(&self) -> &ForegroundExecutor {
146 &self.foreground_executor
147 }
148
149 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> Result<R> {
151 let app = self.app.upgrade().context("app was released")?;
152 let mut lock = app.borrow_mut();
153 Ok(lock.update(f))
154 }
155
156 pub fn subscribe<T, Event>(
159 &mut self,
160 entity: &Entity<T>,
161 mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
162 ) -> Result<Subscription>
163 where
164 T: 'static + EventEmitter<Event>,
165 Event: 'static,
166 {
167 let app = self.app.upgrade().context("app was released")?;
168 let mut lock = app.borrow_mut();
169 let subscription = lock.subscribe(entity, on_event);
170 Ok(subscription)
171 }
172
173 pub fn open_window<V>(
175 &self,
176 options: crate::WindowOptions,
177 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
178 ) -> Result<WindowHandle<V>>
179 where
180 V: 'static + Render,
181 {
182 let app = self.app.upgrade().context("app was released")?;
183 let mut lock = app.borrow_mut();
184 lock.open_window(options, build_root_view)
185 }
186
187 #[track_caller]
189 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
190 where
191 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
192 R: 'static,
193 {
194 let mut cx = self.clone();
195 self.foreground_executor
196 .spawn(async move { f(&mut cx).await })
197 }
198
199 pub fn has_global<G: Global>(&self) -> Result<bool> {
202 let app = self.app.upgrade().context("app was released")?;
203 let app = app.borrow_mut();
204 Ok(app.has_global::<G>())
205 }
206
207 pub fn read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> Result<R> {
212 let app = self.app.upgrade().context("app was released")?;
213 let app = app.borrow_mut();
214 Ok(read(app.global(), &app))
215 }
216
217 pub fn try_read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> Option<R> {
224 let app = self.app.upgrade()?;
225 let app = app.borrow_mut();
226 Some(read(app.try_global()?, &app))
227 }
228
229 pub fn try_read_default_global<G: Global + Default, R>(
235 &self,
236 read: impl FnOnce(&G, &App) -> R,
237 ) -> Result<R> {
238 let app = self.app.upgrade().context("app was released")?;
239 let mut app = app.borrow_mut();
240 app.update(|cx| {
241 cx.default_global::<G>();
242 });
243 Ok(read(app.try_global().context("app was released")?, &app))
244 }
245
246 pub fn update_global<G: Global, R>(
249 &self,
250 update: impl FnOnce(&mut G, &mut App) -> R,
251 ) -> Result<R> {
252 let app = self.app.upgrade().context("app was released")?;
253 let mut app = app.borrow_mut();
254 Ok(app.update(|cx| cx.update_global(update)))
255 }
256
257 pub fn on_drop<T: 'static, Callback: FnOnce(&mut T, &mut Context<T>) + 'static>(
259 &self,
260 entity: &WeakEntity<T>,
261 f: Callback,
262 ) -> util::Deferred<impl FnOnce() + use<T, Callback>> {
263 let entity = entity.clone();
264 let mut cx = self.clone();
265 util::defer(move || {
266 entity.update(&mut cx, f).ok();
267 })
268 }
269}
270
271#[derive(Clone, Deref, DerefMut)]
274pub struct AsyncWindowContext {
275 #[deref]
276 #[deref_mut]
277 app: AsyncApp,
278 window: AnyWindowHandle,
279}
280
281impl AsyncWindowContext {
282 pub(crate) fn new_context(app: AsyncApp, window: AnyWindowHandle) -> Self {
283 Self { app, window }
284 }
285
286 pub fn window_handle(&self) -> AnyWindowHandle {
288 self.window
289 }
290
291 pub fn update<R>(&mut self, update: impl FnOnce(&mut Window, &mut App) -> R) -> Result<R> {
293 self.app
294 .update_window(self.window, |_, window, cx| update(window, cx))
295 }
296
297 pub fn update_root<R>(
299 &mut self,
300 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
301 ) -> Result<R> {
302 self.app.update_window(self.window, update)
303 }
304
305 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut Window, &mut App) + 'static) {
307 self.window
308 .update(self, |_, window, _| window.on_next_frame(f))
309 .ok();
310 }
311
312 pub fn read_global<G: Global, R>(
314 &mut self,
315 read: impl FnOnce(&G, &Window, &App) -> R,
316 ) -> Result<R> {
317 self.window
318 .update(self, |_, window, cx| read(cx.global(), window, cx))
319 }
320
321 pub fn update_global<G, R>(
324 &mut self,
325 update: impl FnOnce(&mut G, &mut Window, &mut App) -> R,
326 ) -> Result<R>
327 where
328 G: Global,
329 {
330 self.window.update(self, |_, window, cx| {
331 cx.update_global(|global, cx| update(global, window, cx))
332 })
333 }
334
335 #[track_caller]
338 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
339 where
340 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
341 R: 'static,
342 {
343 let mut cx = self.clone();
344 self.foreground_executor
345 .spawn(async move { f(&mut cx).await })
346 }
347
348 pub fn prompt<T>(
352 &mut self,
353 level: PromptLevel,
354 message: &str,
355 detail: Option<&str>,
356 answers: &[T],
357 ) -> oneshot::Receiver<usize>
358 where
359 T: Clone + Into<PromptButton>,
360 {
361 self.window
362 .update(self, |_, window, cx| {
363 window.prompt(level, message, detail, answers, cx)
364 })
365 .unwrap_or_else(|_| oneshot::channel().1)
366 }
367}
368
369impl AppContext for AsyncWindowContext {
370 type Result<T> = Result<T>;
371
372 fn new<T>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Result<Entity<T>>
373 where
374 T: 'static,
375 {
376 let mut build_entity = Some(build_entity);
377 match self.app.update_window(self.window, |_, _, cx| {
378 cx.new(
379 build_entity
380 .take()
381 .expect("build_entity is taken exactly once"),
382 )
383 }) {
384 Ok(entity) => Ok(entity),
385 Err(err) => {
386 let Some(build_entity) = build_entity.take() else {
387 return Err(err);
388 };
389 self.app.new(build_entity)
390 }
391 }
392 }
393
394 fn reserve_entity<T: 'static>(&mut self) -> Result<Reservation<T>> {
395 self.app.reserve_entity()
396 }
397
398 fn insert_entity<T: 'static>(
399 &mut self,
400 reservation: Reservation<T>,
401 build_entity: impl FnOnce(&mut Context<T>) -> T,
402 ) -> Self::Result<Entity<T>> {
403 let mut args = Some((reservation, build_entity));
404 match self.app.update_window(self.window, |_, _, cx| {
405 let (reservation, build_entity) = args.take().expect("args are taken exactly once");
406 cx.insert_entity(reservation, build_entity)
407 }) {
408 Ok(entity) => Ok(entity),
409 Err(err) => {
410 let Some((reservation, build_entity)) = args.take() else {
411 return Err(err);
412 };
413 self.app.insert_entity(reservation, build_entity)
414 }
415 }
416 }
417
418 fn update_entity<T: 'static, R>(
419 &mut self,
420 handle: &Entity<T>,
421 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
422 ) -> Result<R> {
423 self.window
424 .update(self, |_, _, cx| cx.update_entity(handle, update))
425 }
426
427 fn as_mut<'a, T>(&'a mut self, _: &Entity<T>) -> Self::Result<super::GpuiBorrow<'a, T>>
428 where
429 T: 'static,
430 {
431 Err(anyhow!(
432 "Cannot use as_mut() from an async context, call `update`"
433 ))
434 }
435
436 fn read_entity<T, R>(
437 &self,
438 handle: &Entity<T>,
439 read: impl FnOnce(&T, &App) -> R,
440 ) -> Self::Result<R>
441 where
442 T: 'static,
443 {
444 self.app.read_entity(handle, read)
445 }
446
447 fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
448 where
449 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
450 {
451 self.app.update_window(window, update)
452 }
453
454 fn read_window<T, R>(
455 &self,
456 window: &WindowHandle<T>,
457 read: impl FnOnce(Entity<T>, &App) -> R,
458 ) -> Result<R>
459 where
460 T: 'static,
461 {
462 self.app.read_window(window, read)
463 }
464
465 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
466 where
467 R: Send + 'static,
468 {
469 self.app.background_executor.spawn(future)
470 }
471
472 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Result<R>
473 where
474 G: Global,
475 {
476 self.app.read_global(callback)
477 }
478}
479
480impl VisualContext for AsyncWindowContext {
481 fn window_handle(&self) -> AnyWindowHandle {
482 self.window
483 }
484
485 fn new_window_entity<T: 'static>(
486 &mut self,
487 build_entity: impl FnOnce(&mut Window, &mut Context<T>) -> T,
488 ) -> Self::Result<Entity<T>> {
489 self.window
490 .update(self, |_, window, cx| cx.new(|cx| build_entity(window, cx)))
491 }
492
493 fn update_window_entity<T: 'static, R>(
494 &mut self,
495 view: &Entity<T>,
496 update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
497 ) -> Self::Result<R> {
498 self.window.update(self, |_, window, cx| {
499 view.update(cx, |entity, cx| update(entity, window, cx))
500 })
501 }
502
503 fn replace_root_view<V>(
504 &mut self,
505 build_view: impl FnOnce(&mut Window, &mut Context<V>) -> V,
506 ) -> Self::Result<Entity<V>>
507 where
508 V: 'static + Render,
509 {
510 self.window
511 .update(self, |_, window, cx| window.replace_root(cx, build_view))
512 }
513
514 fn focus<V>(&mut self, view: &Entity<V>) -> Self::Result<()>
515 where
516 V: Focusable,
517 {
518 self.window.update(self, |_, window, cx| {
519 view.read(cx).focus_handle(cx).focus(window);
520 })
521 }
522}
523
524#[cfg(test)]
525mod tests {
526 use super::*;
527 use crate::{Empty, TestAppContext};
528
529 struct TestEntity(usize);
530
531 #[test]
532 fn async_window_context_creates_entities_after_window_closes() {
533 let mut cx = TestAppContext::single();
534 let window = cx.add_window(|_, _| Empty);
535 let window: AnyWindowHandle = window.into();
536 let mut async_cx = cx
537 .update_window(window, |_, window, cx| window.to_async(cx))
538 .unwrap();
539
540 cx.update_window(window, |_, window, _| window.remove_window())
541 .unwrap();
542 assert!(cx.update_window(window, |_, _, _| ()).is_err());
543
544 let entity = async_cx.new(|_| TestEntity(1)).unwrap();
545 assert_eq!(
546 async_cx.read_entity(&entity, |entity, _| entity.0).unwrap(),
547 1
548 );
549
550 let reservation = async_cx.reserve_entity::<TestEntity>().unwrap();
551 let entity = async_cx
552 .insert_entity(reservation, |_| TestEntity(2))
553 .unwrap();
554 assert_eq!(
555 async_cx.read_entity(&entity, |entity, _| entity.0).unwrap(),
556 2
557 );
558 }
559}