#![forbid(unsafe_code)]
mod run_return;
pub use run_return::*;
use std::convert::Infallible;
use std::future::Future;
use std::sync::{Arc, Mutex};
use std::task::{Context, Wake, Waker};
use winit::event::Event;
use winit::event_loop::{
ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget as Elwt,
};
pub mod prelude {
pub use super::{EventLoopBuilderExt, EventLoopExt};
}
pub trait EventLoopExt {
type User;
fn block_on<F, Fut>(self, handler: F, fut: Fut) -> !
where
F: FnMut(Event<'_, Self::User>, &Elwt<Signal<Self::User>>, &mut ControlFlow) + 'static,
Fut: Future<Output = Infallible> + 'static;
}
impl<T: Send + 'static> EventLoopExt for EventLoop<Signal<T>> {
type User = T;
fn block_on<F, Fut>(self, mut handler: F, fut: Fut) -> !
where
F: FnMut(Event<'_, Self::User>, &Elwt<Signal<Self::User>>, &mut ControlFlow) + 'static,
Fut: Future<Output = Infallible> + 'static,
{
let mut fut = Box::pin(fut);
let mut ready = true;
let waker = make_proxy_waker(&self);
self.run(move |event, target, control_flow| {
match event {
Event::UserEvent(Signal(Inner::Wakeup)) => {
ready = true;
}
Event::UserEvent(Signal(Inner::User(user))) => {
let event = Event::UserEvent(user);
handler(event, target, control_flow);
}
Event::RedrawEventsCleared => {
handler(Event::RedrawEventsCleared, target, control_flow);
if ready {
ready = false;
let _ = fut.as_mut().poll(&mut Context::from_waker(&waker));
}
}
event => {
let event: Event<T> =
event.map_nonuser_event().unwrap_or_else(|_| unreachable!());
handler(event, target, control_flow);
}
}
})
}
}
fn make_proxy_waker<T: Send + 'static>(evl: &EventLoop<Signal<T>>) -> Waker {
let proxy = evl.create_proxy();
Waker::from(Arc::new(ProxyWaker(Mutex::new(proxy))))
}
struct ProxyWaker<T: 'static>(Mutex<EventLoopProxy<Signal<T>>>);
impl<T> Wake for ProxyWaker<T> {
fn wake(self: Arc<Self>) {
self.0
.lock()
.unwrap()
.send_event(Signal(Inner::Wakeup))
.ok();
}
fn wake_by_ref(self: &Arc<Self>) {
self.0
.lock()
.unwrap()
.send_event(Signal(Inner::Wakeup))
.ok();
}
}
pub trait EventLoopBuilderExt {
fn new_block_on() -> Self;
}
impl<T> EventLoopBuilderExt for EventLoopBuilder<Signal<T>> {
fn new_block_on() -> Self {
Self::with_user_event()
}
}
pub struct Signal<T>(Inner<T>);
impl<T> From<T> for Signal<T> {
fn from(t: T) -> Self {
Self(Inner::User(t))
}
}
enum Inner<T> {
User(T),
Wakeup,
}