logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Asynchronous support

// #![feature(async_await)]
pub mod future;

use std::{
    cell::RefCell,
    future::Future,
    ptr,
    rc::Rc,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
    time::Instant,
};
use winit::{
    event::{DeviceEvent, DeviceId, Event, WindowEvent},
    event_loop::{ControlFlow, EventLoop},
    window::WindowId,
};

pub struct EventLoopRunnerAsync<E: 'static> {
    shared_state: Rc<RefCell<SharedState<E>>>,
}

pub struct SharedState<E: 'static> {
    next_event: Option<Event<'static, E>>,
    control_flow: Option<ptr::NonNull<ControlFlow>>,
}

#[must_use]
pub enum WaitCanceledCause {
    ResumeTimeReached,
    EventsReceived,
}

#[derive(Clone, Debug, PartialEq)]
pub enum EventAsync<E: 'static> {
    WindowEvent {
        window_id: WindowId,
        event: WindowEvent<'static>,
    },
    DeviceEvent {
        device_id: DeviceId,
        event: DeviceEvent,
    },
    UserEvent(E),
    Suspended,
    Resumed,
}

/// Defines the behavior for running an application in asynchronous mode.
pub trait EventLoopAsync {
    type Event: 'static;
    fn run_async<Fn, Fu>(self, event_handler: Fn) -> !
    where
        Fn: 'static + FnOnce(EventLoopRunnerAsync<Self::Event>) -> Fu,
        Fu: Future<Output = ()>;
}

impl<E: 'static + std::fmt::Debug> EventLoopAsync for EventLoop<E> {
    type Event = E;

    fn run_async<Fn, Fu>(self, event_handler: Fn) -> !
    where
        Fn: 'static + FnOnce(EventLoopRunnerAsync<E>) -> Fu,
        Fu: Future<Output = ()>,
    {
        let shared_state = Rc::new(RefCell::new(SharedState {
            next_event: None,
            control_flow: None,
        }));
        let shared_state_clone = shared_state.clone();
        let mut future = Box::pin(async move {
            let runner = EventLoopRunnerAsync {
                shared_state: shared_state_clone,
            };
            event_handler(runner).await
        });
        let waker = unsafe { Waker::from_raw(null_waker()) };

        self.run(move |event, _, control_flow| {
            let control_flow_ptr = control_flow as *mut ControlFlow;
            drop(control_flow);
            {
                let mut shared_state = shared_state.borrow_mut();
                shared_state.control_flow = ptr::NonNull::new(control_flow_ptr);
                shared_state.next_event = event.to_static();
            }

            if unsafe { *control_flow_ptr } != ControlFlow::Exit {
                let mut context = Context::from_waker(&waker);
                match future.as_mut().poll(&mut context) {
                    Poll::Ready(()) => unsafe { *control_flow_ptr = ControlFlow::Exit },
                    Poll::Pending => (),
                }
            }

            shared_state.borrow_mut().control_flow = None;
        });
    }
}

impl<E> EventLoopRunnerAsync<E> {
    pub fn wait(&mut self) -> future::WaitFuture<'_, E> {
        future::WaitFuture {
            shared_state: &self.shared_state,
        }
    }

    pub fn wait_until(&mut self, timeout: Instant) -> future::WaitUntilFuture<'_, E> {
        future::WaitUntilFuture {
            timeout,
            shared_state: &self.shared_state,
        }
    }

    pub fn recv_events(&mut self) -> impl '_ + Future<Output = future::EventReceiver<'_, E>> {
        future::EventReceiverBuilder {
            shared_state: &self.shared_state,
        }
    }
}

fn null_waker() -> RawWaker {
    RawWaker::new(ptr::null(), VTABLE)
}

const VTABLE: &RawWakerVTable = &RawWakerVTable::new(null_waker_clone, null_fn, null_fn, null_fn);

unsafe fn null_waker_clone(_: *const ()) -> RawWaker {
    null_waker()
}

unsafe fn null_fn(_: *const ()) {}