1mod async_context;
2mod entity_map;
3mod model_context;
4
5pub use async_context::*;
6pub use entity_map::*;
7pub use model_context::*;
8use refineable::Refineable;
9
10use crate::{
11 current_platform, run_on_main, spawn_on_main, Context, LayoutId, MainThread, MainThreadOnly,
12 Platform, PlatformDispatcher, RootView, TextStyle, TextStyleRefinement, TextSystem, Window,
13 WindowContext, WindowHandle, WindowId,
14};
15use anyhow::{anyhow, Result};
16use collections::{HashMap, VecDeque};
17use futures::{future, Future};
18use parking_lot::Mutex;
19use slotmap::SlotMap;
20use smallvec::SmallVec;
21use std::{
22 any::{type_name, Any, TypeId},
23 marker::PhantomData,
24 ops::{Deref, DerefMut},
25 sync::{Arc, Weak},
26};
27use util::ResultExt;
28
29#[derive(Clone)]
30pub struct App(Arc<Mutex<AppContext<MainThread>>>);
31
32impl App {
33 pub fn production() -> Self {
34 Self::new(current_platform())
35 }
36
37 #[cfg(any(test, feature = "test"))]
38 pub fn test() -> Self {
39 Self::new(Arc::new(super::TestPlatform::new()))
40 }
41
42 fn new(platform: Arc<dyn Platform>) -> Self {
43 let dispatcher = platform.dispatcher();
44 let text_system = Arc::new(TextSystem::new(platform.text_system()));
45 let entities = EntityMap::new();
46 let unit_entity = entities.redeem(entities.reserve(), ());
47 Self(Arc::new_cyclic(|this| {
48 Mutex::new(AppContext {
49 thread: PhantomData,
50 this: this.clone(),
51 platform: MainThreadOnly::new(platform, dispatcher.clone()),
52 dispatcher,
53 text_system,
54 pending_updates: 0,
55 text_style_stack: Vec::new(),
56 state_stacks_by_type: HashMap::default(),
57 unit_entity,
58 entities,
59 windows: SlotMap::with_key(),
60 pending_effects: Default::default(),
61 observers: Default::default(),
62 layout_id_buffer: Default::default(),
63 })
64 }))
65 }
66
67 pub fn run<F>(self, on_finish_launching: F)
68 where
69 F: 'static + FnOnce(&mut AppContext<MainThread>),
70 {
71 let this = self.clone();
72 let platform = self.0.lock().platform.clone();
73 platform.borrow_on_main_thread().run(Box::new(move || {
74 let cx = &mut *this.0.lock();
75 on_finish_launching(cx);
76 }));
77 }
78}
79
80type Handlers<Thread> =
81 SmallVec<[Arc<dyn Fn(&mut AppContext<Thread>) -> bool + Send + Sync + 'static>; 2]>;
82
83pub struct AppContext<Thread = ()> {
84 thread: PhantomData<Thread>,
85 this: Weak<Mutex<AppContext<Thread>>>,
86 platform: MainThreadOnly<dyn Platform>,
87 dispatcher: Arc<dyn PlatformDispatcher>,
88 text_system: Arc<TextSystem>,
89 pending_updates: usize,
90 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
91 pub(crate) state_stacks_by_type: HashMap<TypeId, Vec<Box<dyn Any + Send + Sync>>>,
92 pub(crate) unit_entity: Handle<()>,
93 pub(crate) entities: EntityMap,
94 pub(crate) windows: SlotMap<WindowId, Option<Window>>,
95 pub(crate) pending_effects: VecDeque<Effect>,
96 pub(crate) observers: HashMap<EntityId, Handlers<Thread>>,
97 pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
98}
99
100impl<Thread: 'static + Send + Sync> AppContext<Thread> {
101 // TODO: Better names for these?
102 #[inline]
103 pub fn downcast(&self) -> &AppContext<()> {
104 // Any `Thread` can become `()`.
105 //
106 // Can't do this in a blanket `Deref` impl, as it infinitely recurses.
107 unsafe { std::mem::transmute::<&AppContext<Thread>, &AppContext<()>>(self) }
108 }
109
110 #[inline]
111 pub fn downcast_mut(&mut self) -> &mut AppContext<()> {
112 // Any `Thread` can become `()`.
113 //
114 // Can't do this in a blanket `DerefMut` impl, as it infinitely recurses.
115 unsafe { std::mem::transmute::<&mut AppContext<Thread>, &mut AppContext<()>>(self) }
116 }
117
118 pub fn text_system(&self) -> &Arc<TextSystem> {
119 &self.text_system
120 }
121
122 pub fn to_async(&self) -> AsyncContext<Thread> {
123 AsyncContext(self.this.clone())
124 }
125
126 pub fn run_on_main<R>(
127 &self,
128 f: impl FnOnce(&mut AppContext<MainThread>) -> R + Send + 'static,
129 ) -> impl Future<Output = R>
130 where
131 R: Send + 'static,
132 {
133 let this = self.this.upgrade().unwrap();
134 run_on_main(self.dispatcher.clone(), move || {
135 let cx = &mut *this.lock();
136 let main_thread_cx = unsafe {
137 std::mem::transmute::<&mut AppContext<Thread>, &mut AppContext<MainThread>>(cx)
138 };
139 main_thread_cx.update(|cx| f(cx))
140 })
141 }
142
143 pub fn spawn_on_main<F, R>(
144 &self,
145 f: impl FnOnce(&mut AppContext<MainThread>) -> F + Send + 'static,
146 ) -> impl Future<Output = R>
147 where
148 F: Future<Output = R> + 'static,
149 R: Send + 'static,
150 {
151 let this = self.this.upgrade().unwrap();
152 spawn_on_main(self.dispatcher.clone(), move || {
153 let cx = &mut *this.lock();
154 let main_thread_cx = unsafe {
155 std::mem::transmute::<&mut AppContext<Thread>, &mut AppContext<MainThread>>(cx)
156 };
157 main_thread_cx.update(|cx| f(cx))
158 })
159 }
160
161 pub fn text_style(&self) -> TextStyle {
162 let mut style = TextStyle::default();
163 for refinement in &self.text_style_stack {
164 style.refine(refinement);
165 }
166 style
167 }
168
169 pub fn state<S: 'static>(&self) -> &S {
170 self.state_stacks_by_type
171 .get(&TypeId::of::<S>())
172 .and_then(|stack| stack.last())
173 .and_then(|any_state| any_state.downcast_ref::<S>())
174 .ok_or_else(|| anyhow!("no state of type {} exists", type_name::<S>()))
175 .unwrap()
176 }
177
178 pub fn state_mut<S: 'static>(&mut self) -> &mut S {
179 self.state_stacks_by_type
180 .get_mut(&TypeId::of::<S>())
181 .and_then(|stack| stack.last_mut())
182 .and_then(|any_state| any_state.downcast_mut::<S>())
183 .ok_or_else(|| anyhow!("no state of type {} exists", type_name::<S>()))
184 .unwrap()
185 }
186
187 pub(crate) fn push_text_style(&mut self, text_style: TextStyleRefinement) {
188 self.text_style_stack.push(text_style);
189 }
190
191 pub(crate) fn pop_text_style(&mut self) {
192 self.text_style_stack.pop();
193 }
194
195 pub(crate) fn push_state<T: Send + Sync + 'static>(&mut self, state: T) {
196 self.state_stacks_by_type
197 .entry(TypeId::of::<T>())
198 .or_default()
199 .push(Box::new(state));
200 }
201
202 pub(crate) fn pop_state<T: 'static>(&mut self) {
203 self.state_stacks_by_type
204 .get_mut(&TypeId::of::<T>())
205 .and_then(|stack| stack.pop())
206 .expect("state stack underflow");
207 }
208
209 pub(crate) fn update_window<R>(
210 &mut self,
211 id: WindowId,
212 update: impl FnOnce(&mut WindowContext) -> R,
213 ) -> Result<R> {
214 self.update(|cx| {
215 let mut window = cx
216 .windows
217 .get_mut(id)
218 .ok_or_else(|| anyhow!("window not found"))?
219 .take()
220 .unwrap();
221
222 let result = update(&mut WindowContext::mutable(cx.downcast_mut(), &mut window));
223 window.dirty = true;
224
225 cx.windows
226 .get_mut(id)
227 .ok_or_else(|| anyhow!("window not found"))?
228 .replace(window);
229
230 Ok(result)
231 })
232 }
233
234 fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
235 dbg!("update");
236 self.pending_updates += 1;
237 let result = update(self);
238 self.pending_updates -= 1;
239 if self.pending_updates == 0 {
240 self.flush_effects();
241 }
242 result
243 }
244
245 fn flush_effects(&mut self) {
246 dbg!("Flush effects");
247
248 while let Some(effect) = self.pending_effects.pop_front() {
249 match effect {
250 Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
251 }
252 }
253
254 let dirty_window_ids = self
255 .windows
256 .iter()
257 .filter_map(|(window_id, window)| {
258 let window = window.as_ref().unwrap();
259 if window.dirty {
260 Some(window_id)
261 } else {
262 None
263 }
264 })
265 .collect::<Vec<_>>();
266
267 for dirty_window_id in dirty_window_ids {
268 self.update_window(dirty_window_id, |cx| cx.draw())
269 .unwrap() // We know we have the window.
270 .log_err();
271 }
272 }
273
274 fn apply_notify_effect(&mut self, updated_entity: EntityId) {
275 if let Some(mut handlers) = self.observers.remove(&updated_entity) {
276 handlers.retain(|handler| handler(self));
277 if let Some(new_handlers) = self.observers.remove(&updated_entity) {
278 handlers.extend(new_handlers);
279 }
280 self.observers.insert(updated_entity, handlers);
281 }
282 }
283}
284
285impl Context for AppContext {
286 type EntityContext<'a, 'w, T: Send + Sync + 'static> = ModelContext<'a, T>;
287 type Result<T> = T;
288
289 fn entity<T: Send + Sync + 'static>(
290 &mut self,
291 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
292 ) -> Handle<T> {
293 let slot = self.entities.reserve();
294 let entity = build_entity(&mut ModelContext::mutable(self, slot.id));
295 self.entities.redeem(slot, entity)
296 }
297
298 fn update_entity<T: Send + Sync + 'static, R>(
299 &mut self,
300 handle: &Handle<T>,
301 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
302 ) -> R {
303 let mut entity = self.entities.lease(handle);
304 let result = update(&mut *entity, &mut ModelContext::mutable(self, handle.id));
305 self.entities.end_lease(entity);
306 result
307 }
308}
309
310impl AppContext<MainThread> {
311 pub(crate) fn platform(&self) -> &dyn Platform {
312 self.platform.borrow_on_main_thread()
313 }
314
315 pub fn activate(&mut self, ignoring_other_apps: bool) {
316 self.platform().activate(ignoring_other_apps);
317 }
318
319 pub fn open_window<S: 'static + Send + Sync>(
320 &mut self,
321 options: crate::WindowOptions,
322 build_root_view: impl FnOnce(&mut WindowContext) -> RootView<S> + Send + 'static,
323 ) -> WindowHandle<S> {
324 let id = self.windows.insert(None);
325 let handle = WindowHandle::new(id);
326 let mut window = Window::new(handle.into(), options, self);
327 let root_view = build_root_view(&mut WindowContext::mutable(
328 self.downcast_mut(),
329 &mut window,
330 ));
331 window.root_view.replace(root_view.into_any());
332 self.windows.get_mut(id).unwrap().replace(window);
333 handle
334 }
335}
336
337pub(crate) enum Effect {
338 Notify(EntityId),
339}
340
341#[cfg(test)]
342mod tests {
343 use super::AppContext;
344
345 #[test]
346 fn test_app_context_send_sync() {
347 // This will not compile if `AppContext` does not implement `Send`
348 fn assert_send<T: Send>() {}
349 assert_send::<AppContext>();
350 }
351}