Skip to main content

tokio_immediate_egui/
lib.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3//! [`egui`] integration for [`tokio_immediate`].
4//!
5//! [`EguiAsync`] manages [`AsyncViewport`]s automatically using an
6//! [`egui::Plugin`], so you only need to create it once, register the plugin,
7//! and then call its factory methods to obtain [`AsyncCall`] instances,
8//! [`AsyncWaker`]s, or [`trigger::AsyncTrigger`]s.
9//!
10//! Most factory methods come in three viewport-targeting variants:
11//!
12//! | Suffix | Target viewport |
13//! |---|---|
14//! | `*_for_root()` | [`ViewportId::ROOT`] |
15//! | `*()` (no suffix) | The current viewport (`ctx.viewport_id()`) |
16//! | `*_for(viewport_id)` | An explicit [`ViewportId`] |
17//!
18//! ## Feature flags
19#![cfg_attr(docsrs, feature(doc_cfg))]
20#![cfg_attr(
21    feature = "document-features",
22    cfg_attr(doc, doc = ::document_features::document_features!())
23)]
24//
25// Clippy lints.
26#![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/// Manages [`AsyncViewport`]s for all egui viewports via a [`Plugin`].
59///
60/// Create one at application startup, register its [`plugin()`](Self::plugin)
61/// on the [`egui::Context`], and then use the factory methods to create
62/// [`AsyncCall`] instances, [`AsyncWaker`]s, or
63/// [`trigger::AsyncTrigger`]s bound to the appropriate viewport.
64///
65/// # Viewport lifetime
66///
67/// The plugin automatically drops [`AsyncViewport`]s for viewports that
68/// are no longer present in the egui output (i.e. closed windows). Any
69/// [`AsyncCall`] or [`AsyncWaker`] that was bound to a dropped viewport
70/// will silently stop requesting UI repaints — tasks still run to
71/// completion, but the UI will not be notified. Because of this, creating
72/// [`AsyncCall`] instances for non-root viewports ahead of time is
73/// pointless; create them only once the viewport is actually open.
74///
75/// # Panics
76///
77/// Factory methods that create viewport-bound objects (`new_call*`,
78/// `new_serial_runner*`, `new_parallel_runner*`, `new_waker*`, and
79/// `new_trigger*`) require the plugin returned by [`plugin()`](Self::plugin)
80/// to be registered and initialized via [`Context::add_plugin()`]. Calling
81/// them before plugin setup panics.
82///
83/// `new_serial_runner*` methods may additionally panic if runtime access
84/// preconditions are not met by the selected runtime (for example,
85/// [`AsyncCurrentRuntime`] requires a Tokio runtime context on the current
86/// thread).
87#[derive(Default, Clone)]
88pub struct EguiAsync {
89    inner: Arc<RwLock<EguiAsyncPluginInner>>,
90}
91
92// TODO: Make weak context ptr available on `egui` side and remove this.
93/// The [`Plugin`] half of [`EguiAsync`].
94///
95/// This is a separate type that holds a [`Weak`] reference back to the
96/// shared state in order to break a reference cycle:
97/// `EguiAsync` → `AsyncViewport` → wake-up callback → `egui::Context`
98/// → plugins → back to `EguiAsync`. The [`EguiAsync`] value must be kept
99/// alive for the plugin to function.
100///
101/// Also exposes the same factory methods as [`EguiAsync`] for convenience.
102///
103/// # Panics
104///
105/// All forwarding factory methods panic if this plugin outlives its owning
106/// [`EguiAsync`] value.
107///
108/// They also inherit the panic conditions documented on the corresponding
109/// [`EguiAsync`] methods.
110#[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    /// Returns the [`Plugin`] that must be registered on the
126    /// [`egui::Context`] (via [`Context::add_plugin()`]).
127    #[must_use]
128    pub fn plugin(&self) -> EguiAsyncPlugin {
129        EguiAsyncPlugin {
130            inner: Arc::downgrade(&self.inner),
131        }
132    }
133
134    /// Creates an [`AsyncCall`] bound to the root viewport, using
135    /// `A::default()` as the runtime.
136    #[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    /// Creates an [`AsyncCall`] bound to the root viewport with an explicit
146    /// runtime.
147    #[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    /// Creates an [`AsyncCall`] bound to the current viewport, using
157    /// `A::default()` as the runtime.
158    #[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    /// Creates an [`AsyncCall`] bound to the current viewport with an
168    /// explicit runtime.
169    #[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    /// Creates an [`AsyncCall`] bound to `viewport_id`, using
179    /// `A::default()` as the runtime.
180    #[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    /// Creates an [`AsyncCall`] bound to `viewport_id` with an explicit
190    /// runtime.
191    #[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    /// Creates an [`AsyncSerialRunner`] bound to the root viewport, using
205    /// `A::default()` as the runtime.
206    #[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    /// Creates an [`AsyncSerialRunner`] bound to the root viewport with an
218    /// explicit runtime.
219    #[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    /// Creates an [`AsyncSerialRunner`] bound to the current viewport, using
234    /// `A::default()` as the runtime.
235    #[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    /// Creates an [`AsyncSerialRunner`] bound to the current viewport with an
247    /// explicit runtime.
248    #[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    /// Creates an [`AsyncSerialRunner`] bound to `viewport_id`, using
260    /// `A::default()` as the runtime.
261    #[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    /// Creates an [`AsyncSerialRunner`] bound to `viewport_id` with an
273    /// explicit runtime.
274    #[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    /// Creates an [`AsyncParallelRunner`] bound to the root viewport, using
290    /// `A::default()` as the runtime.
291    #[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    /// Creates an [`AsyncParallelRunner`] bound to the root viewport with an
301    /// explicit runtime.
302    #[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    /// Creates an [`AsyncParallelRunner`] bound to the current viewport, using
315    /// `A::default()` as the runtime.
316    #[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    /// Creates an [`AsyncParallelRunner`] bound to the current viewport with
326    /// an explicit runtime.
327    #[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    /// Creates an [`AsyncParallelRunner`] bound to `viewport_id`, using
337    /// `A::default()` as the runtime.
338    #[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    /// Creates an [`AsyncParallelRunner`] bound to `viewport_id` with an
351    /// explicit runtime.
352    #[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    /// Creates an [`AsyncWaker`] for the root viewport.
366    #[must_use]
367    pub fn new_waker_for_root(&self) -> AsyncWaker {
368        self.new_waker_for(ViewportId::ROOT)
369    }
370
371    /// Creates an [`AsyncWaker`] for the current viewport.
372    #[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    /// Creates an [`AsyncWaker`] for `viewport_id`.
380    #[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    /// Shared implementation behind the `new_waker*` family.
386    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    /// Creates an [`AsyncTrigger`](trigger::AsyncTrigger) for the
404    /// root viewport.
405    #[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    /// Creates an [`AsyncTrigger`](trigger::AsyncTrigger) for the
413    /// current viewport.
414    #[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    /// Creates an [`AsyncTrigger`](trigger::AsyncTrigger) for
424    /// `viewport_id`.
425    #[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        // Remove closed viewports.
499        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    /// See [`EguiAsync::new_call_for_root()`].
512    #[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    /// See [`EguiAsync::new_call_with_runtime_for_root()`].
522    #[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    /// See [`EguiAsync::new_call()`].
532    #[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    /// See [`EguiAsync::new_call_with_runtime()`].
542    #[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    /// See [`EguiAsync::new_call_for()`].
552    #[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    /// See [`EguiAsync::new_call_with_runtime_for()`].
562    #[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    /// See [`EguiAsync::new_serial_runner_for_root()`].
577    #[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    /// See [`EguiAsync::new_serial_runner_with_runtime_for_root()`].
589    #[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    /// See [`EguiAsync::new_serial_runner()`].
605    #[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    /// See [`EguiAsync::new_serial_runner_with_runtime()`].
617    #[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    /// See [`EguiAsync::new_serial_runner_for()`].
629    #[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    /// See [`EguiAsync::new_serial_runner_with_runtime_for()`].
641    #[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    /// See [`EguiAsync::new_parallel_runner_for_root()`].
658    #[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    /// See [`EguiAsync::new_parallel_runner_with_runtime_for_root()`].
668    #[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    /// See [`EguiAsync::new_parallel_runner()`].
682    #[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    /// See [`EguiAsync::new_parallel_runner_with_runtime()`].
692    #[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    /// See [`EguiAsync::new_parallel_runner_for()`].
702    #[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    /// See [`EguiAsync::new_parallel_runner_with_runtime_for()`].
715    #[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    /// See [`EguiAsync::new_waker_for_root()`].
730    #[must_use]
731    pub fn new_waker_for_root(&self) -> AsyncWaker {
732        self.upgrade().new_waker_for_root()
733    }
734
735    /// See [`EguiAsync::new_waker()`].
736    #[must_use]
737    pub fn new_waker(&self) -> AsyncWaker {
738        self.upgrade().new_waker()
739    }
740
741    /// See [`EguiAsync::new_waker_for()`].
742    #[must_use]
743    pub fn new_waker_for(&self, viewport_id: ViewportId) -> AsyncWaker {
744        self.upgrade().new_waker_for(viewport_id)
745    }
746
747    /// See [`EguiAsync::new_trigger_for_root()`].
748    #[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    /// See [`EguiAsync::new_trigger()`].
756    #[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    /// See [`EguiAsync::new_trigger_for()`].
764    #[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}