macroquad/
exec.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::sync::{Arc, Mutex};
4use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
5
6use crate::Error;
7
8// Returns Pending as long as its inner bool is false.
9#[derive(Default)]
10pub struct FrameFuture {
11    done: bool,
12}
13
14impl Future for FrameFuture {
15    type Output = ();
16
17    fn poll(mut self: Pin<&mut Self>, _context: &mut Context) -> Poll<Self::Output> {
18        if self.done {
19            // We were told to step, meaning this future gets destroyed and we run
20            // the main future until we call next_frame again and end up in this poll
21            // function again.
22            Poll::Ready(())
23        } else {
24            self.done = true;
25            Poll::Pending
26        }
27    }
28}
29
30pub struct FileLoadingFuture {
31    pub contents: Arc<Mutex<Option<Result<Vec<u8>, Error>>>>,
32}
33
34impl Future for FileLoadingFuture {
35    type Output = Result<Vec<u8>, Error>;
36
37    fn poll(self: Pin<&mut Self>, _context: &mut Context) -> Poll<Self::Output> {
38        let mut contents = self.contents.lock().unwrap();
39        if let Some(contents) = contents.take() {
40            Poll::Ready(contents)
41        } else {
42            Poll::Pending
43        }
44    }
45}
46
47fn waker() -> Waker {
48    unsafe fn clone(data: *const ()) -> RawWaker {
49        RawWaker::new(data, &VTABLE)
50    }
51    unsafe fn wake(_data: *const ()) {
52        panic!(
53            "macroquad does not support waking futures, please use coroutines, \
54            otherwise your pending future will block until the next frame"
55        )
56    }
57    unsafe fn wake_by_ref(data: *const ()) {
58        wake(data);
59    }
60    unsafe fn drop(_data: *const ()) {
61        // Nothing to do
62    }
63    const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
64    let raw_waker = RawWaker::new(std::ptr::null(), &VTABLE);
65    unsafe { Waker::from_raw(raw_waker) }
66}
67
68/// returns Some(T) if future is done, None if it would block
69pub(crate) fn resume<T>(future: &mut Pin<Box<dyn Future<Output = T>>>) -> Option<T> {
70    let waker = waker();
71    let mut futures_context = std::task::Context::from_waker(&waker);
72    match future.as_mut().poll(&mut futures_context) {
73        Poll::Ready(v) => Some(v),
74        Poll::Pending => None,
75    }
76}