1#![cfg_attr(docsrs, feature(doc_cfg))]
20#![cfg_attr(
21 feature = "document-features",
22 cfg_attr(doc, doc = ::document_features::document_features!())
23)]
24#![warn(clippy::pedantic)]
27#![warn(clippy::cargo)]
28#![warn(clippy::undocumented_unsafe_blocks)]
29
30use ::std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak};
31
32use ::egui::{Context, FullOutput, OrderedViewportIdMap, Plugin, RawInput, ViewportId};
33
34pub use ::tokio_immediate::tokio;
35
36#[cfg(feature = "sync")]
37#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
38pub use ::tokio_immediate::sync;
39#[cfg(feature = "sync")]
40#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
41pub use ::tokio_immediate::trigger;
42
43pub use ::tokio_immediate::parallel;
44#[cfg(feature = "sync")]
45#[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
46pub use ::tokio_immediate::serial;
47pub use ::tokio_immediate::single;
48pub use ::tokio_immediate::{
49 AsyncCurrentRuntime, AsyncRuntime, AsyncViewport, AsyncWakeUp, AsyncWakeUpCallback,
50 AsyncWakeUpGuard, AsyncWaker, AsyncWakerList,
51};
52
53use ::tokio_immediate::parallel::AsyncParallelRunner;
54#[cfg(feature = "sync")]
55use ::tokio_immediate::serial::AsyncSerialRunner;
56use ::tokio_immediate::single::AsyncCall;
57
58#[derive(Default, Clone)]
88pub struct EguiAsync {
89 inner: Arc<RwLock<EguiAsyncPluginInner>>,
90}
91
92#[derive(Clone)]
111pub struct EguiAsyncPlugin {
112 inner: Weak<RwLock<EguiAsyncPluginInner>>,
113}
114
115#[derive(Default)]
116struct EguiAsyncPluginInner {
117 context: Option<Context>,
118 viewports: OrderedViewportIdMap<AsyncViewport>,
119
120 #[cfg(feature = "sync")]
121 triggers: OrderedViewportIdMap<trigger::AsyncTriggerHandle>,
122}
123
124impl EguiAsync {
125 #[must_use]
128 pub fn plugin(&self) -> EguiAsyncPlugin {
129 EguiAsyncPlugin {
130 inner: Arc::downgrade(&self.inner),
131 }
132 }
133
134 #[must_use]
137 pub fn new_call_for_root<T, A>(&self) -> AsyncCall<T, A>
138 where
139 T: 'static + Send,
140 A: Default + AsyncRuntime,
141 {
142 AsyncCall::new(self.new_waker_for_root())
143 }
144
145 #[must_use]
148 pub fn new_call_with_runtime_for_root<T, A>(&self, runtime: A) -> AsyncCall<T, A>
149 where
150 T: 'static + Send,
151 A: AsyncRuntime,
152 {
153 AsyncCall::new_with_runtime(self.new_waker_for_root(), runtime)
154 }
155
156 #[must_use]
159 pub fn new_call<T, A>(&self) -> AsyncCall<T, A>
160 where
161 T: 'static + Send,
162 A: Default + AsyncRuntime,
163 {
164 AsyncCall::new(self.new_waker())
165 }
166
167 #[must_use]
170 pub fn new_call_with_runtime<T, A>(&self, runtime: A) -> AsyncCall<T, A>
171 where
172 T: 'static + Send,
173 A: AsyncRuntime,
174 {
175 AsyncCall::new_with_runtime(self.new_waker(), runtime)
176 }
177
178 #[must_use]
181 pub fn new_call_for<T, A>(&self, viewport_id: ViewportId) -> AsyncCall<T, A>
182 where
183 T: 'static + Send,
184 A: Default + AsyncRuntime,
185 {
186 AsyncCall::new(self.new_waker_for(viewport_id))
187 }
188
189 #[must_use]
192 pub fn new_call_with_runtime_for<T, A>(
193 &self,
194 runtime: A,
195 viewport_id: ViewportId,
196 ) -> AsyncCall<T, A>
197 where
198 T: 'static + Send,
199 A: AsyncRuntime,
200 {
201 AsyncCall::new_with_runtime(self.new_waker_for(viewport_id), runtime)
202 }
203
204 #[must_use]
207 #[cfg(feature = "sync")]
208 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
209 pub fn new_serial_runner_for_root<T, A>(&self) -> AsyncSerialRunner<T, A>
210 where
211 T: 'static + Send,
212 A: Default + AsyncRuntime,
213 {
214 AsyncSerialRunner::new(self.new_waker_for_root())
215 }
216
217 #[must_use]
220 #[cfg(feature = "sync")]
221 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
222 pub fn new_serial_runner_with_runtime_for_root<T, A>(
223 &self,
224 runtime: A,
225 ) -> AsyncSerialRunner<T, A>
226 where
227 T: 'static + Send,
228 A: AsyncRuntime,
229 {
230 AsyncSerialRunner::new_with_runtime(self.new_waker_for_root(), runtime)
231 }
232
233 #[must_use]
236 #[cfg(feature = "sync")]
237 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
238 pub fn new_serial_runner<T, A>(&self) -> AsyncSerialRunner<T, A>
239 where
240 T: 'static + Send,
241 A: Default + AsyncRuntime,
242 {
243 AsyncSerialRunner::new(self.new_waker())
244 }
245
246 #[must_use]
249 #[cfg(feature = "sync")]
250 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
251 pub fn new_serial_runner_with_runtime<T, A>(&self, runtime: A) -> AsyncSerialRunner<T, A>
252 where
253 T: 'static + Send,
254 A: AsyncRuntime,
255 {
256 AsyncSerialRunner::new_with_runtime(self.new_waker(), runtime)
257 }
258
259 #[must_use]
262 #[cfg(feature = "sync")]
263 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
264 pub fn new_serial_runner_for<T, A>(&self, viewport_id: ViewportId) -> AsyncSerialRunner<T, A>
265 where
266 T: 'static + Send,
267 A: Default + AsyncRuntime,
268 {
269 AsyncSerialRunner::new(self.new_waker_for(viewport_id))
270 }
271
272 #[must_use]
275 #[cfg(feature = "sync")]
276 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
277 pub fn new_serial_runner_with_runtime_for<T, A>(
278 &self,
279 runtime: A,
280 viewport_id: ViewportId,
281 ) -> AsyncSerialRunner<T, A>
282 where
283 T: 'static + Send,
284 A: AsyncRuntime,
285 {
286 AsyncSerialRunner::new_with_runtime(self.new_waker_for(viewport_id), runtime)
287 }
288
289 #[must_use]
292 pub fn new_parallel_runner_for_root<T, A>(&self) -> AsyncParallelRunner<T, A>
293 where
294 T: 'static + Send,
295 A: Default + AsyncRuntime,
296 {
297 AsyncParallelRunner::new(self.new_waker_for_root())
298 }
299
300 #[must_use]
303 pub fn new_parallel_runner_with_runtime_for_root<T, A>(
304 &self,
305 runtime: A,
306 ) -> AsyncParallelRunner<T, A>
307 where
308 T: 'static + Send,
309 A: AsyncRuntime,
310 {
311 AsyncParallelRunner::new_with_runtime(self.new_waker_for_root(), runtime)
312 }
313
314 #[must_use]
317 pub fn new_parallel_runner<T, A>(&self) -> AsyncParallelRunner<T, A>
318 where
319 T: 'static + Send,
320 A: Default + AsyncRuntime,
321 {
322 AsyncParallelRunner::new(self.new_waker())
323 }
324
325 #[must_use]
328 pub fn new_parallel_runner_with_runtime<T, A>(&self, runtime: A) -> AsyncParallelRunner<T, A>
329 where
330 T: 'static + Send,
331 A: AsyncRuntime,
332 {
333 AsyncParallelRunner::new_with_runtime(self.new_waker(), runtime)
334 }
335
336 #[must_use]
339 pub fn new_parallel_runner_for<T, A>(
340 &self,
341 viewport_id: ViewportId,
342 ) -> AsyncParallelRunner<T, A>
343 where
344 T: 'static + Send,
345 A: Default + AsyncRuntime,
346 {
347 AsyncParallelRunner::new(self.new_waker_for(viewport_id))
348 }
349
350 #[must_use]
353 pub fn new_parallel_runner_with_runtime_for<T, A>(
354 &self,
355 runtime: A,
356 viewport_id: ViewportId,
357 ) -> AsyncParallelRunner<T, A>
358 where
359 T: 'static + Send,
360 A: AsyncRuntime,
361 {
362 AsyncParallelRunner::new_with_runtime(self.new_waker_for(viewport_id), runtime)
363 }
364
365 #[must_use]
367 pub fn new_waker_for_root(&self) -> AsyncWaker {
368 self.new_waker_for(ViewportId::ROOT)
369 }
370
371 #[must_use]
373 pub fn new_waker(&self) -> AsyncWaker {
374 let inner = self.inner_mut();
375 let viewport_id = Self::context(&inner).viewport_id();
376 Self::new_waker_for_inner(inner, viewport_id)
377 }
378
379 #[must_use]
381 pub fn new_waker_for(&self, viewport_id: ViewportId) -> AsyncWaker {
382 Self::new_waker_for_inner(self.inner_mut(), viewport_id)
383 }
384
385 fn new_waker_for_inner(
387 mut inner: RwLockWriteGuard<'_, EguiAsyncPluginInner>,
388 viewport_id: ViewportId,
389 ) -> AsyncWaker {
390 if let Some(viewport) = inner.viewports.get(&viewport_id) {
391 viewport.new_waker()
392 } else {
393 let ctx = Self::context(&inner).clone();
394 let viewport = AsyncViewport::new_with_wake_up(Arc::new(move || {
395 ctx.request_repaint_of(viewport_id);
396 }));
397 let waker = viewport.new_waker();
398 inner.viewports.insert(viewport_id, viewport);
399 waker
400 }
401 }
402
403 #[must_use]
406 #[cfg(feature = "sync")]
407 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
408 pub fn new_trigger_for_root(&self) -> trigger::AsyncTrigger {
409 self.new_trigger_for(ViewportId::ROOT)
410 }
411
412 #[must_use]
415 #[cfg(feature = "sync")]
416 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
417 pub fn new_trigger(&self) -> trigger::AsyncTrigger {
418 let inner = self.inner_mut();
419 let viewport_id = Self::context(&inner).viewport_id();
420 Self::new_trigger_for_inner(inner, viewport_id)
421 }
422
423 #[must_use]
426 #[cfg(feature = "sync")]
427 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
428 pub fn new_trigger_for(&self, viewport_id: ViewportId) -> trigger::AsyncTrigger {
429 Self::new_trigger_for_inner(self.inner_mut(), viewport_id)
430 }
431
432 #[cfg(feature = "sync")]
433 fn new_trigger_for_inner(
434 mut inner: RwLockWriteGuard<'_, EguiAsyncPluginInner>,
435 viewport_id: ViewportId,
436 ) -> trigger::AsyncTrigger {
437 if let Some(trigger) = inner.triggers.get(&viewport_id) {
438 trigger.subscribe()
439 } else {
440 let handle = trigger::AsyncTriggerHandle::default();
441 let trigger = handle.subscribe();
442 inner.triggers.insert(viewport_id, handle);
443 trigger
444 }
445 }
446
447 fn context<'a>(inner: &'a RwLockWriteGuard<'_, EguiAsyncPluginInner>) -> &'a Context {
448 inner
449 .context
450 .as_ref()
451 .expect("No egui context: EguiAsyncPlugin is not initialized yet")
452 }
453
454 fn inner_mut(&self) -> RwLockWriteGuard<'_, EguiAsyncPluginInner> {
455 self.inner
456 .write()
457 .expect("Failed to access EguiAsync: poisoned by panic in another thread")
458 }
459}
460
461impl Plugin for EguiAsyncPlugin {
462 fn debug_name(&self) -> &'static str {
463 "EguiAsyncPlugin"
464 }
465
466 fn setup(&mut self, ctx: &Context) {
467 let egui_async = self.upgrade();
468 let mut inner = Self::inner_mut(&egui_async.inner);
469
470 inner.context = Some(ctx.clone());
471 }
472
473 #[cfg(feature = "sync")]
474 fn on_end_pass(&mut self, ctx: &Context) {
475 let egui_async = self.upgrade();
476 let inner = Self::inner(&egui_async.inner);
477
478 if !ctx.will_discard()
479 && let Some(trigger) = inner.triggers.get(&ctx.viewport_id())
480 {
481 trigger.trigger();
482 }
483 }
484
485 fn input_hook(&mut self, input: &mut RawInput) {
486 let egui_async = self.upgrade();
487 let inner = Self::inner(&egui_async.inner);
488
489 if let Some(viewport) = inner.viewports.get(&input.viewport_id) {
490 viewport.woke_up();
491 }
492 }
493
494 fn output_hook(&mut self, output: &mut FullOutput) {
495 let egui_async = self.upgrade();
496 let mut inner = Self::inner_mut(&egui_async.inner);
497
498 inner
500 .viewports
501 .retain(|vid, _| output.viewport_output.contains_key(vid));
502
503 #[cfg(feature = "sync")]
504 inner
505 .triggers
506 .retain(|vid, _| output.viewport_output.contains_key(vid));
507 }
508}
509
510impl EguiAsyncPlugin {
511 #[must_use]
513 pub fn new_call_for_root<T, A>(&self) -> AsyncCall<T, A>
514 where
515 T: 'static + Send,
516 A: Default + AsyncRuntime,
517 {
518 self.upgrade().new_call_for_root()
519 }
520
521 #[must_use]
523 pub fn new_call_with_runtime_for_root<T, A>(&self, runtime: A) -> AsyncCall<T, A>
524 where
525 T: 'static + Send,
526 A: AsyncRuntime,
527 {
528 self.upgrade().new_call_with_runtime_for_root(runtime)
529 }
530
531 #[must_use]
533 pub fn new_call<T, A>(&self) -> AsyncCall<T, A>
534 where
535 T: 'static + Send,
536 A: Default + AsyncRuntime,
537 {
538 self.upgrade().new_call()
539 }
540
541 #[must_use]
543 pub fn new_call_with_runtime<T, A>(&self, runtime: A) -> AsyncCall<T, A>
544 where
545 T: 'static + Send,
546 A: AsyncRuntime,
547 {
548 self.upgrade().new_call_with_runtime(runtime)
549 }
550
551 #[must_use]
553 pub fn new_call_for<T, A>(&self, viewport_id: ViewportId) -> AsyncCall<T, A>
554 where
555 T: 'static + Send,
556 A: Default + AsyncRuntime,
557 {
558 self.upgrade().new_call_for(viewport_id)
559 }
560
561 #[must_use]
563 pub fn new_call_with_runtime_for<T, A>(
564 &self,
565 runtime: A,
566 viewport_id: ViewportId,
567 ) -> AsyncCall<T, A>
568 where
569 T: 'static + Send,
570 A: AsyncRuntime,
571 {
572 self.upgrade()
573 .new_call_with_runtime_for(runtime, viewport_id)
574 }
575
576 #[must_use]
578 #[cfg(feature = "sync")]
579 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
580 pub fn new_serial_runner_for_root<T, A>(&self) -> AsyncSerialRunner<T, A>
581 where
582 T: 'static + Send,
583 A: Default + AsyncRuntime,
584 {
585 self.upgrade().new_serial_runner_for_root()
586 }
587
588 #[must_use]
590 #[cfg(feature = "sync")]
591 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
592 pub fn new_serial_runner_with_runtime_for_root<T, A>(
593 &self,
594 runtime: A,
595 ) -> AsyncSerialRunner<T, A>
596 where
597 T: 'static + Send,
598 A: AsyncRuntime,
599 {
600 self.upgrade()
601 .new_serial_runner_with_runtime_for_root(runtime)
602 }
603
604 #[must_use]
606 #[cfg(feature = "sync")]
607 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
608 pub fn new_serial_runner<T, A>(&self) -> AsyncSerialRunner<T, A>
609 where
610 T: 'static + Send,
611 A: Default + AsyncRuntime,
612 {
613 self.upgrade().new_serial_runner()
614 }
615
616 #[must_use]
618 #[cfg(feature = "sync")]
619 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
620 pub fn new_serial_runner_with_runtime<T, A>(&self, runtime: A) -> AsyncSerialRunner<T, A>
621 where
622 T: 'static + Send,
623 A: AsyncRuntime,
624 {
625 self.upgrade().new_serial_runner_with_runtime(runtime)
626 }
627
628 #[must_use]
630 #[cfg(feature = "sync")]
631 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
632 pub fn new_serial_runner_for<T, A>(&self, viewport_id: ViewportId) -> AsyncSerialRunner<T, A>
633 where
634 T: 'static + Send,
635 A: Default + AsyncRuntime,
636 {
637 self.upgrade().new_serial_runner_for(viewport_id)
638 }
639
640 #[must_use]
642 #[cfg(feature = "sync")]
643 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
644 pub fn new_serial_runner_with_runtime_for<T, A>(
645 &self,
646 runtime: A,
647 viewport_id: ViewportId,
648 ) -> AsyncSerialRunner<T, A>
649 where
650 T: 'static + Send,
651 A: AsyncRuntime,
652 {
653 self.upgrade()
654 .new_serial_runner_with_runtime_for(runtime, viewport_id)
655 }
656
657 #[must_use]
659 pub fn new_parallel_runner_for_root<T, A>(&self) -> AsyncParallelRunner<T, A>
660 where
661 T: 'static + Send,
662 A: Default + AsyncRuntime,
663 {
664 self.upgrade().new_parallel_runner_for_root()
665 }
666
667 #[must_use]
669 pub fn new_parallel_runner_with_runtime_for_root<T, A>(
670 &self,
671 runtime: A,
672 ) -> AsyncParallelRunner<T, A>
673 where
674 T: 'static + Send,
675 A: AsyncRuntime,
676 {
677 self.upgrade()
678 .new_parallel_runner_with_runtime_for_root(runtime)
679 }
680
681 #[must_use]
683 pub fn new_parallel_runner<T, A>(&self) -> AsyncParallelRunner<T, A>
684 where
685 T: 'static + Send,
686 A: Default + AsyncRuntime,
687 {
688 self.upgrade().new_parallel_runner()
689 }
690
691 #[must_use]
693 pub fn new_parallel_runner_with_runtime<T, A>(&self, runtime: A) -> AsyncParallelRunner<T, A>
694 where
695 T: 'static + Send,
696 A: AsyncRuntime,
697 {
698 self.upgrade().new_parallel_runner_with_runtime(runtime)
699 }
700
701 #[must_use]
703 pub fn new_parallel_runner_for<T, A>(
704 &self,
705 viewport_id: ViewportId,
706 ) -> AsyncParallelRunner<T, A>
707 where
708 T: 'static + Send,
709 A: Default + AsyncRuntime,
710 {
711 self.upgrade().new_parallel_runner_for(viewport_id)
712 }
713
714 #[must_use]
716 pub fn new_parallel_runner_with_runtime_for<T, A>(
717 &self,
718 runtime: A,
719 viewport_id: ViewportId,
720 ) -> AsyncParallelRunner<T, A>
721 where
722 T: 'static + Send,
723 A: AsyncRuntime,
724 {
725 self.upgrade()
726 .new_parallel_runner_with_runtime_for(runtime, viewport_id)
727 }
728
729 #[must_use]
731 pub fn new_waker_for_root(&self) -> AsyncWaker {
732 self.upgrade().new_waker_for_root()
733 }
734
735 #[must_use]
737 pub fn new_waker(&self) -> AsyncWaker {
738 self.upgrade().new_waker()
739 }
740
741 #[must_use]
743 pub fn new_waker_for(&self, viewport_id: ViewportId) -> AsyncWaker {
744 self.upgrade().new_waker_for(viewport_id)
745 }
746
747 #[must_use]
749 #[cfg(feature = "sync")]
750 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
751 pub fn new_trigger_for_root(&self) -> trigger::AsyncTrigger {
752 self.upgrade().new_trigger_for_root()
753 }
754
755 #[must_use]
757 #[cfg(feature = "sync")]
758 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
759 pub fn new_trigger(&self) -> trigger::AsyncTrigger {
760 self.upgrade().new_trigger()
761 }
762
763 #[must_use]
765 #[cfg(feature = "sync")]
766 #[cfg_attr(docsrs, doc(cfg(feature = "sync")))]
767 pub fn new_trigger_for(&self, viewport_id: ViewportId) -> trigger::AsyncTrigger {
768 self.upgrade().new_trigger_for(viewport_id)
769 }
770
771 fn inner(
772 inner: &Arc<RwLock<EguiAsyncPluginInner>>,
773 ) -> RwLockReadGuard<'_, EguiAsyncPluginInner> {
774 inner
775 .read()
776 .expect("Failed to read-lock EguiAsyncPlugin: poisoned by panic in another thread")
777 }
778
779 fn inner_mut(
780 inner: &Arc<RwLock<EguiAsyncPluginInner>>,
781 ) -> RwLockWriteGuard<'_, EguiAsyncPluginInner> {
782 inner
783 .write()
784 .expect("Failed to write-lock EguiAsyncPlugin: poisoned by panic in another thread")
785 }
786
787 fn upgrade(&self) -> EguiAsync {
788 EguiAsync {
789 inner: self
790 .inner
791 .upgrade()
792 .expect("EguiAsyncPlugin outlived its EguiAsync owner"),
793 }
794 }
795}