1use crate::{
2 current_platform, AnyWindowHandle, Context, LayoutId, MainThreadOnly, Platform, Reference,
3 RootView, TextSystem, Window, WindowContext, WindowHandle, WindowId,
4};
5use anyhow::{anyhow, Result};
6use collections::{HashMap, VecDeque};
7use futures::{future, Future};
8use parking_lot::Mutex;
9use slotmap::SlotMap;
10use smallvec::SmallVec;
11use std::{
12 any::Any,
13 marker::PhantomData,
14 sync::{Arc, Weak},
15};
16use util::ResultExt;
17
18#[derive(Clone)]
19pub struct App(Arc<Mutex<AppContext>>);
20
21impl App {
22 pub fn production() -> Self {
23 Self::new(current_platform())
24 }
25
26 #[cfg(any(test, feature = "test"))]
27 pub fn test() -> Self {
28 Self::new(Arc::new(super::TestPlatform::new()))
29 }
30
31 fn new(platform: Arc<dyn Platform>) -> Self {
32 let dispatcher = platform.dispatcher();
33 let text_system = Arc::new(TextSystem::new(platform.text_system()));
34 let mut entities = SlotMap::with_key();
35 let unit_entity = Handle::new(entities.insert(Some(Box::new(()) as Box<dyn Any + Send>)));
36 Self(Arc::new_cyclic(|this| {
37 Mutex::new(AppContext {
38 this: this.clone(),
39 platform: MainThreadOnly::new(platform, dispatcher),
40 text_system,
41 unit_entity,
42 entities,
43 windows: SlotMap::with_key(),
44 pending_updates: 0,
45 pending_effects: Default::default(),
46 observers: Default::default(),
47 layout_id_buffer: Default::default(),
48 })
49 }))
50 }
51
52 pub fn run<F>(self, on_finish_launching: F)
53 where
54 F: 'static + FnOnce(&mut AppContext),
55 {
56 let this = self.clone();
57 let platform = self.0.lock().platform.clone();
58 platform.borrow_on_main_thread().run(Box::new(move || {
59 let cx = &mut *this.0.lock();
60 on_finish_launching(cx);
61 }));
62 }
63}
64
65type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
66
67pub struct AppContext {
68 this: Weak<Mutex<AppContext>>,
69 platform: MainThreadOnly<dyn Platform>,
70 text_system: Arc<TextSystem>,
71 pub(crate) unit_entity: Handle<()>,
72 pub(crate) entities: SlotMap<EntityId, Option<Box<dyn Any + Send>>>,
73 pub(crate) windows: SlotMap<WindowId, Option<Window>>,
74 pending_updates: usize,
75 pub(crate) pending_effects: VecDeque<Effect>,
76 pub(crate) observers: HashMap<EntityId, Handlers>,
77 // We recycle this memory across layout requests.
78 pub(crate) layout_id_buffer: Vec<LayoutId>,
79}
80
81impl AppContext {
82 pub fn text_system(&self) -> &Arc<TextSystem> {
83 &self.text_system
84 }
85
86 pub fn to_async(&self) -> AsyncContext {
87 AsyncContext(self.this.clone())
88 }
89
90 pub fn spawn_on_main<F, R>(
91 &self,
92 f: impl FnOnce(&dyn Platform, &mut Self) -> F + Send + 'static,
93 ) -> impl Future<Output = R>
94 where
95 F: Future<Output = R> + 'static,
96 R: Send + 'static,
97 {
98 let this = self.this.upgrade().unwrap();
99 self.platform.read(move |platform| {
100 let cx = &mut *this.lock();
101 cx.update(|cx| f(platform, cx))
102 })
103 }
104
105 pub fn open_window<S: 'static + Send + Sync>(
106 &mut self,
107 options: crate::WindowOptions,
108 build_root_view: impl FnOnce(&mut WindowContext) -> RootView<S> + Send + 'static,
109 ) -> impl Future<Output = WindowHandle<S>> {
110 let id = self.windows.insert(None);
111 let handle = WindowHandle::new(id);
112 self.spawn_on_main(move |platform, cx| {
113 let mut window = Window::new(handle.into(), options, platform, cx);
114 let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window));
115 window.root_view.replace(root_view.into_any());
116 cx.windows.get_mut(id).unwrap().replace(window);
117 future::ready(handle)
118 })
119 }
120
121 pub(crate) fn update_window<R>(
122 &mut self,
123 id: WindowId,
124 update: impl FnOnce(&mut WindowContext) -> R,
125 ) -> Result<R> {
126 self.update(|cx| {
127 let mut window = cx
128 .windows
129 .get_mut(id)
130 .ok_or_else(|| anyhow!("window not found"))?
131 .take()
132 .unwrap();
133
134 let result = update(&mut WindowContext::mutable(cx, &mut window));
135 window.dirty = true;
136
137 cx.windows
138 .get_mut(id)
139 .ok_or_else(|| anyhow!("window not found"))?
140 .replace(window);
141
142 Ok(result)
143 })
144 }
145
146 fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
147 self.pending_updates += 1;
148 let result = update(self);
149 self.pending_updates -= 1;
150 if self.pending_updates == 0 {
151 self.flush_effects();
152 }
153 result
154 }
155
156 fn flush_effects(&mut self) {
157 while let Some(effect) = self.pending_effects.pop_front() {
158 match effect {
159 Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
160 }
161 }
162
163 let dirty_window_ids = self
164 .windows
165 .iter()
166 .filter_map(|(window_id, window)| {
167 let window = window.as_ref().unwrap();
168 if window.dirty {
169 Some(window_id)
170 } else {
171 None
172 }
173 })
174 .collect::<Vec<_>>();
175
176 for dirty_window_id in dirty_window_ids {
177 self.update_window(dirty_window_id, |cx| cx.draw())
178 .unwrap() // We know we have the window.
179 .log_err();
180 }
181 }
182
183 fn apply_notify_effect(&mut self, updated_entity: EntityId) {
184 if let Some(mut handlers) = self.observers.remove(&updated_entity) {
185 handlers.retain(|handler| handler(self));
186 if let Some(new_handlers) = self.observers.remove(&updated_entity) {
187 handlers.extend(new_handlers);
188 }
189 self.observers.insert(updated_entity, handlers);
190 }
191 }
192}
193
194impl Context for AppContext {
195 type EntityContext<'a, 'w, T: Send + Sync + 'static> = ModelContext<'a, T>;
196 type Result<T> = T;
197
198 fn entity<T: Send + Sync + 'static>(
199 &mut self,
200 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
201 ) -> Handle<T> {
202 let id = self.entities.insert(None);
203 let entity = Box::new(build_entity(&mut ModelContext::mutable(self, id)));
204 self.entities.get_mut(id).unwrap().replace(entity);
205
206 Handle::new(id)
207 }
208
209 fn update_entity<T: Send + Sync + 'static, R>(
210 &mut self,
211 handle: &Handle<T>,
212 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
213 ) -> R {
214 let mut entity = self
215 .entities
216 .get_mut(handle.id)
217 .unwrap()
218 .take()
219 .unwrap()
220 .downcast::<T>()
221 .unwrap();
222
223 let result = update(&mut *entity, &mut ModelContext::mutable(self, handle.id));
224 self.entities.get_mut(handle.id).unwrap().replace(entity);
225 result
226 }
227}
228
229#[derive(Clone)]
230pub struct AsyncContext(Weak<Mutex<AppContext>>);
231
232impl Context for AsyncContext {
233 type EntityContext<'a, 'b, T: Send + Sync + 'static> = ModelContext<'a, T>;
234 type Result<T> = Result<T>;
235
236 fn entity<T: Send + Sync + 'static>(
237 &mut self,
238 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
239 ) -> Result<Handle<T>> {
240 let app = self
241 .0
242 .upgrade()
243 .ok_or_else(|| anyhow!("app was released"))?;
244 let mut lock = app.lock();
245 Ok(lock.entity(build_entity))
246 }
247
248 fn update_entity<T: Send + Sync + 'static, R>(
249 &mut self,
250 handle: &Handle<T>,
251 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
252 ) -> Result<R> {
253 let app = self
254 .0
255 .upgrade()
256 .ok_or_else(|| anyhow!("app was released"))?;
257 let mut lock = app.lock();
258 Ok(lock.update_entity(handle, update))
259 }
260}
261
262impl AsyncContext {
263 pub fn update_window<T>(
264 &self,
265 handle: AnyWindowHandle,
266 update: impl FnOnce(&mut WindowContext) -> T + Send + Sync,
267 ) -> Result<T> {
268 let app = self
269 .0
270 .upgrade()
271 .ok_or_else(|| anyhow!("app was released"))?;
272 let mut app_context = app.lock();
273 app_context.update_window(handle.id, update)
274 }
275}
276
277pub struct ModelContext<'a, T> {
278 app: Reference<'a, AppContext>,
279 entity_type: PhantomData<T>,
280 entity_id: EntityId,
281}
282
283impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
284 pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
285 Self {
286 app: Reference::Mutable(app),
287 entity_type: PhantomData,
288 entity_id,
289 }
290 }
291
292 // todo!
293 // fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
294 // let mut entity = self
295 // .app
296 // .entities
297 // .get_mut(self.entity_id)
298 // .unwrap()
299 // .take()
300 // .unwrap();
301 // let result = update(entity.downcast_mut::<T>().unwrap(), self);
302 // self.app
303 // .entities
304 // .get_mut(self.entity_id)
305 // .unwrap()
306 // .replace(entity);
307 // result
308 // }
309
310 pub fn handle(&self) -> WeakHandle<T> {
311 WeakHandle {
312 id: self.entity_id,
313 entity_type: PhantomData,
314 }
315 }
316
317 pub fn observe<E: Send + Sync + 'static>(
318 &mut self,
319 handle: &Handle<E>,
320 on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
321 ) {
322 let this = self.handle();
323 let handle = handle.downgrade();
324 self.app
325 .observers
326 .entry(handle.id)
327 .or_default()
328 .push(Arc::new(move |cx| {
329 if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
330 this.update(cx, |this, cx| on_notify(this, handle, cx));
331 true
332 } else {
333 false
334 }
335 }));
336 }
337
338 pub fn notify(&mut self) {
339 self.app
340 .pending_effects
341 .push_back(Effect::Notify(self.entity_id));
342 }
343}
344
345impl<'a, T: 'static> Context for ModelContext<'a, T> {
346 type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
347 type Result<U> = U;
348
349 fn entity<U: Send + Sync + 'static>(
350 &mut self,
351 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
352 ) -> Handle<U> {
353 self.app.entity(build_entity)
354 }
355
356 fn update_entity<U: Send + Sync + 'static, R>(
357 &mut self,
358 handle: &Handle<U>,
359 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
360 ) -> R {
361 self.app.update_entity(handle, update)
362 }
363}
364
365slotmap::new_key_type! { pub struct EntityId; }
366
367pub struct Handle<T> {
368 pub(crate) id: EntityId,
369 pub(crate) entity_type: PhantomData<T>,
370}
371
372impl<T: Send + Sync + 'static> Handle<T> {
373 fn new(id: EntityId) -> Self {
374 Self {
375 id,
376 entity_type: PhantomData,
377 }
378 }
379
380 pub fn downgrade(&self) -> WeakHandle<T> {
381 WeakHandle {
382 id: self.id,
383 entity_type: self.entity_type,
384 }
385 }
386
387 /// Update the entity referenced by this handle with the given function.
388 ///
389 /// The update function receives a context appropriate for its environment.
390 /// When updating in an `AppContext`, it receives a `ModelContext`.
391 /// When updating an a `WindowContext`, it receives a `ViewContext`.
392 pub fn update<C: Context, R>(
393 &self,
394 cx: &mut C,
395 update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
396 ) -> C::Result<R> {
397 cx.update_entity(self, update)
398 }
399}
400
401impl<T> Clone for Handle<T> {
402 fn clone(&self) -> Self {
403 Self {
404 id: self.id,
405 entity_type: PhantomData,
406 }
407 }
408}
409
410pub struct WeakHandle<T> {
411 pub(crate) id: EntityId,
412 pub(crate) entity_type: PhantomData<T>,
413}
414
415impl<T: Send + Sync + 'static> WeakHandle<T> {
416 pub fn upgrade(&self, _: &impl Context) -> Option<Handle<T>> {
417 // todo!("Actually upgrade")
418 Some(Handle {
419 id: self.id,
420 entity_type: self.entity_type,
421 })
422 }
423
424 /// Update the entity referenced by this handle with the given function if
425 /// the referenced entity still exists. Returns an error if the entity has
426 /// been released.
427 ///
428 /// The update function receives a context appropriate for its environment.
429 /// When updating in an `AppContext`, it receives a `ModelContext`.
430 /// When updating an a `WindowContext`, it receives a `ViewContext`.
431 pub fn update<C: Context, R>(
432 &self,
433 cx: &mut C,
434 update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
435 ) -> Result<R>
436 where
437 Result<C::Result<R>>: crate::Flatten<R>,
438 {
439 crate::Flatten::flatten(
440 self.upgrade(cx)
441 .ok_or_else(|| anyhow!("entity release"))
442 .map(|this| cx.update_entity(&this, update)),
443 )
444 }
445}
446
447pub(crate) enum Effect {
448 Notify(EntityId),
449}
450
451#[cfg(test)]
452mod tests {
453 use super::AppContext;
454
455 #[test]
456 fn test_app_context_send_sync() {
457 // This will not compile if `AppContext` does not implement `Send`
458 fn assert_send<T: Send>() {}
459 assert_send::<AppContext>();
460 }
461}