winit_runtime/executor/
mod.rs

1/*
2 * Created on Mon Aug 07 2023
3 *
4 * Copyright (c) storycraft. Licensed under the MIT Licence.
5 */
6
7//! Implementation of winit Executor
8
9pub mod event;
10pub mod handle;
11
12use std::sync::OnceLock;
13
14use async_task::Task;
15use event_source::emit;
16use futures_lite::Future;
17use instant::Duration;
18use scoped_tls_hkt::scoped_thread_local;
19use winit::{
20    error::EventLoopError,
21    event::Event,
22    event_loop::{ControlFlow, EventLoopBuilder, EventLoopWindowTarget},
23};
24
25use crate::{device, resumed, suspended, timer::UpdateState, window};
26
27use self::{event::ExecutorEvent, handle::ExecutorHandle};
28
29pub type EventLoopTarget = EventLoopWindowTarget<ExecutorEvent>;
30
31static HANDLE: OnceLock<ExecutorHandle> = OnceLock::new();
32
33/// Get current [`ExecutorHandle`]
34///
35/// There can be only one [`ExecutorHandle`] and will panic if executor did not start.
36pub fn executor_handle() -> &'static ExecutorHandle {
37    HANDLE.get().expect("Executor is not started")
38}
39
40scoped_thread_local!(static EL_TARGET: EventLoopTarget);
41
42/// Run closure using current [`EventLoopTarget`]
43///
44/// Will panic if it called on outside of runtime thread
45pub fn with_eventloop_target<R>(func: impl FnOnce(&EventLoopTarget) -> R) -> R {
46    EL_TARGET.with(func)
47}
48
49#[derive(Debug)]
50struct Executor {
51    _main: Task<()>,
52    handle: &'static ExecutorHandle,
53}
54
55impl Executor {
56    fn on_event(&mut self, event: Event<ExecutorEvent>, target: &EventLoopTarget) {
57        EL_TARGET.set(target, move || match event {
58            Event::UserEvent(ExecutorEvent::Wake) => {}
59
60            Event::UserEvent(ExecutorEvent::PollTask(runnable)) => {
61                runnable.run();
62            }
63
64            Event::UserEvent(ExecutorEvent::Exit) => target.exit(),
65
66            Event::DeviceEvent { device_id, event } => {
67                emit!(device(), (device_id, &event));
68            }
69
70            Event::WindowEvent {
71                window_id,
72                mut event,
73            } => {
74                emit!(window(), (window_id, &mut event));
75            }
76
77            Event::Resumed => {
78                emit!(resumed(), ());
79            }
80
81            Event::Suspended => {
82                emit!(suspended(), ());
83            }
84
85            Event::AboutToWait => {
86                if let UpdateState::WaitTimeout(next_delay) = self.handle.timer.update_next() {
87                    target.set_control_flow(ControlFlow::wait_duration(Duration::from_millis(
88                        next_delay.get(),
89                    )));
90                } else if target.control_flow() == ControlFlow::Poll {
91                    target.set_control_flow(ControlFlow::Wait);
92                }
93            }
94
95            _ => {}
96        });
97    }
98}
99
100/// Entrypoint for runtime
101pub fn run(main: impl Future<Output = ()>) -> Result<(), EventLoopError> {
102    let event_loop = EventLoopBuilder::with_user_event().build()?;
103
104    let handle = {
105        if HANDLE.set(ExecutorHandle::new(&event_loop)).is_err() {
106            panic!("This cannot be happen");
107        }
108
109        HANDLE.get().unwrap()
110    };
111
112    let (runnable, task) = {
113        let proxy = event_loop.create_proxy();
114
115        let main = async move {
116            main.await;
117            let _ = proxy.send_event(ExecutorEvent::Exit);
118        };
119
120        // SAFETY: EventLoop created on same function, closure does not need to be Send and task and references to Future outlive event loop
121        unsafe { handle.spawn_raw_unchecked(main) }
122    };
123
124    let mut executor = Executor {
125        _main: task,
126        handle,
127    };
128
129    EL_TARGET.set(&event_loop, move || runnable.run());
130
131    event_loop.run(move |event, target| executor.on_event(event, target))
132}