async_component_winit/executor/
mod.rs1pub mod signal;
4#[cfg(target_arch = "wasm32")]
5mod wasm;
6
7use std::{
8 sync::atomic::Ordering,
9 task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
10};
11
12use async_component_core::{context::ComponentStream, AsyncComponent};
13use futures::{Stream, StreamExt};
14use winit::{
15 event::Event,
16 event_loop::{ControlFlow, EventLoop},
17};
18
19use crate::WinitComponent;
20
21use ref_extended::ref_extended;
22
23use self::signal::WinitSignal;
24
25#[derive(Debug, Clone, Copy)]
27#[non_exhaustive]
28pub struct ExecutorPollEvent;
29
30#[derive(Debug)]
34pub struct WinitExecutor {
35 event_loop: Option<EventLoop<ExecutorPollEvent>>,
36
37 state_signal: WinitSignal,
38}
39
40impl WinitExecutor {
41 pub fn new(event_loop: EventLoop<ExecutorPollEvent>) -> Self {
43 let state_signal = WinitSignal::new(event_loop.create_proxy());
44
45 Self {
46 event_loop: Some(event_loop),
47
48 state_signal,
49 }
50 }
51
52 fn poll_stream(&'static self, mut stream: impl Stream + Unpin) -> Poll<()> {
53 if self
54 .state_signal
55 .scheduled
56 .compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire)
57 .is_ok()
58 {
59 if let Poll::Ready(Some(_)) =
60 stream.poll_next_unpin(&mut Context::from_waker(&unsafe {
61 Waker::from_raw(create_raw_waker(&self.state_signal))
62 }))
63 {
64 self.state_signal.scheduled.store(true, Ordering::Release);
65 }
66
67 Poll::Ready(())
68 } else {
69 Poll::Pending
70 }
71 }
72
73 pub fn run<C: AsyncComponent + WinitComponent + 'static>(
77 mut self,
78 func: impl FnOnce() -> C,
79 ) -> ! {
80 let event_loop = self.event_loop.take().unwrap();
81
82 let mut stream = ComponentStream::new(func);
83
84 let executor = self;
85 ref_extended!(|&executor| event_loop.run(move |event, _, control_flow| {
86 let mut stream = stream.enter();
87
88 match event {
89 Event::MainEventsCleared => {
90 stream
91 .component_mut()
92 .on_event(&mut Event::MainEventsCleared, control_flow);
93
94 if let ControlFlow::ExitWithCode(_) = control_flow {
95 return;
96 }
97
98 match executor.poll_stream(&mut stream) {
99 Poll::Ready(_) => {
100 control_flow.set_poll();
101 }
102
103 Poll::Pending => {
104 control_flow.set_wait();
105 }
106 }
107 }
108
109 Event::UserEvent(_) => {}
111
112 _ => {
113 stream
114 .component_mut()
115 .on_event(&mut event.map_nonuser_event().unwrap(), control_flow);
116 }
117 }
118 }))
119 }
120}
121
122fn create_raw_waker(signal: &'static WinitSignal) -> RawWaker {
123 unsafe fn waker_clone(this: *const ()) -> RawWaker {
124 create_raw_waker(&*(this as *const WinitSignal))
125 }
126
127 unsafe fn waker_wake(this: *const ()) {
128 let this = &*(this as *const WinitSignal);
129 this.wake_by_ref();
130 }
131
132 unsafe fn waker_wake_by_ref(this: *const ()) {
133 let this = &*(this as *const WinitSignal);
134 this.wake_by_ref();
135 }
136
137 unsafe fn waker_drop(_: *const ()) {}
138
139 RawWaker::new(
140 signal as *const _ as *const (),
141 &RawWakerVTable::new(waker_clone, waker_wake, waker_wake_by_ref, waker_drop),
142 )
143}