geng_async_state/
lib.rs

1use futures::prelude::*;
2
3scoped_tls::scoped_thread_local! { static mut WITH_FRAMEBUFFER: for<'a> &'a mut (dyn 'a + FnMut(&mut dyn FnMut(&mut ugli::Framebuffer))) }
4
5pub fn with_current_framebuffer<T>(
6    window: &geng_window::Window,
7    f: impl FnOnce(&mut ugli::Framebuffer<'_>) -> T,
8) -> T {
9    if WITH_FRAMEBUFFER.is_set() {
10        let mut value = None::<T>;
11        let mut f = Some(f);
12        WITH_FRAMEBUFFER.with(|with_framebuffer| {
13            with_framebuffer(&mut |framebuffer| value = Some(f.take().unwrap()(framebuffer)))
14        });
15        value.expect("LUL")
16    } else {
17        window.with_framebuffer(f)
18    }
19}
20
21pub trait ActiveState {
22    fn draw(&mut self, framebuffer: &mut ugli::Framebuffer);
23}
24
25impl<'a, T: ActiveState + ?Sized> ActiveState for &'a mut T {
26    fn draw(&mut self, framebuffer: &mut ugli::Framebuffer) {
27        (**self).draw(framebuffer)
28    }
29}
30
31impl<T: ActiveState + ?Sized> ActiveState for Box<T> {
32    fn draw(&mut self, framebuffer: &mut ugli::Framebuffer) {
33        (**self).draw(framebuffer)
34    }
35}
36
37pub trait Transition {
38    fn finished(&self) -> bool;
39    fn draw(
40        &mut self,
41        from: &mut dyn FnMut(&mut ugli::Framebuffer),
42        to: &mut dyn FnMut(&mut ugli::Framebuffer),
43        framebuffer: &mut ugli::Framebuffer,
44    );
45}
46
47pub struct StateResult<'a, T> {
48    pub value: T,
49    pub active_state: Box<dyn ActiveState + 'a>,
50}
51
52pub async fn transition<T>(
53    window: &geng_window::Window,
54    from: &mut dyn ActiveState,
55    transition: &mut dyn Transition,
56    into: impl Future<Output = T>,
57) -> T {
58    let mut into = std::pin::pin!(into);
59    std::future::poll_fn(|cx| {
60        if transition.finished() {
61            into.as_mut().poll(cx)
62        } else {
63            with_current_framebuffer(window, |actual_framebuffer| {
64                WITH_FRAMEBUFFER.set(
65                    &mut |with_framebuffer: &mut dyn FnMut(&mut ugli::Framebuffer)| {
66                        transition.draw(
67                            &mut |f| from.draw(f),
68                            with_framebuffer,
69                            actual_framebuffer,
70                        );
71                    },
72                    || into.as_mut().poll(cx),
73                )
74            })
75        }
76    })
77    .await
78}