aboutsummaryrefslogtreecommitdiff
path: root/src/async_util.rs
blob: bd8882d8f4e02d07d5e87a16ad4504e27c98bb9f (plain) (blame)
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
//! Async support for RTIC

use core::{
    future::Future,
    mem,
    pin::Pin,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

//=============
// Waker

///
pub static WAKER_VTABLE: RawWakerVTable =
    RawWakerVTable::new(waker_clone, waker_wake, waker_wake, waker_drop);

unsafe fn waker_clone(p: *const ()) -> RawWaker {
    RawWaker::new(p, &WAKER_VTABLE)
}

unsafe fn waker_wake(p: *const ()) {
    let f: fn() = mem::transmute(p);
    f();
}

unsafe fn waker_drop(_: *const ()) {
    // nop
}

//============
// Task

///
pub enum Task<F: Future + 'static> {
    ///
    Idle,

    ///
    Running(F),

    ///
    Done(F::Output),
}

impl<F: Future + 'static> Task<F> {
    ///
    pub const fn new() -> Self {
        Self::Idle
    }

    ///
    pub fn spawn(&mut self, future: impl FnOnce() -> F) {
        *self = Task::Running(future());
    }

    ///
    pub unsafe fn poll(&mut self, wake: fn()) {
        match self {
            Task::Idle => {}
            Task::Running(future) => {
                let future = Pin::new_unchecked(future);
                let waker_data: *const () = mem::transmute(wake);
                let waker = Waker::from_raw(RawWaker::new(waker_data, &WAKER_VTABLE));
                let mut cx = Context::from_waker(&waker);

                match future.poll(&mut cx) {
                    Poll::Ready(r) => *self = Task::Done(r),
                    Poll::Pending => {}
                };
            }
            Task::Done(_) => {}
        }
    }
}