| #![feature(generator_trait)] |
| #![no_std] |
| |
| pub use core::*; |
| |
| pub mod future { |
| pub use core::future::Future; |
| use core::ops::Generator; |
| use core::pin::Pin; |
| use core::task::Poll; |
| |
| pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output> |
| where |
| F: Future, |
| { |
| crate::executor::poll(f) |
| } |
| |
| pub fn from_generator<G: Generator<Yield = ()>>( |
| generator: G, |
| ) -> impl Future<Output = G::Return> { |
| crate::executor::from_generator(generator) |
| } |
| } |
| |
| pub mod executor { |
| use core::future::Future; |
| use core::ops::Generator; |
| use core::ops::GeneratorState; |
| use core::pin::Pin; |
| use core::ptr; |
| use core::task::Context; |
| use core::task::Poll; |
| use core::task::RawWaker; |
| use core::task::RawWakerVTable; |
| use core::task::Waker; |
| |
| extern "Rust" { |
| #[link_name = "libtock::syscalls::raw::yieldk"] |
| fn yieldk(); |
| } |
| |
| /// # Safety |
| /// |
| /// [[block_on]] yields whenever a future cannot make any progress at present. Yielding is considered unsafe. |
| pub unsafe fn block_on<T>(mut future: impl Future<Output = T>) -> T { |
| // Contract described in the Rustdoc: "A value, once pinned, must remain pinned forever (...).". |
| // IOW calling Pin::new_unchecked is safe as long as no &mut future is leaked after pinning. |
| let mut pinned_future = Pin::new_unchecked(&mut future); |
| |
| loop { |
| match poll(pinned_future.as_mut()) { |
| Poll::Pending => yieldk(), |
| Poll::Ready(value) => { |
| return value; |
| } |
| } |
| } |
| } |
| |
| pub(crate) fn poll<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> { |
| let waker = unsafe { Waker::from_raw(get_dummy_waker()) }; |
| let mut context = Context::from_waker(&waker); |
| pinned_future.poll(&mut context) |
| } |
| |
| // Since Tock OS comes with waking-up functionality built-in, we use dummy wakers that do nothing at all. |
| fn get_dummy_waker() -> RawWaker { |
| fn clone(_x: *const ()) -> RawWaker { |
| get_dummy_waker() |
| } |
| |
| fn do_nothing(_x: *const ()) {} |
| |
| // This vtable implements the methods required for managing the lifecycle of the wakers. |
| // Our wakers are dummies, so those functions don't do anything. |
| static DUMMY_WAKER_VTABLE: RawWakerVTable = |
| RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing); |
| |
| // The wakers don't have any implementation, so the instance can simply be null. |
| RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE) |
| } |
| |
| pub(crate) fn from_generator<G: Generator<Yield = ()>>( |
| generator: G, |
| ) -> impl Future<Output = G::Return> { |
| GeneratorFuture { generator } |
| } |
| |
| struct GeneratorFuture<G> { |
| generator: G, |
| } |
| |
| impl<G: Generator<Yield = ()>> Future for GeneratorFuture<G> { |
| type Output = G::Return; |
| |
| fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { |
| // Pin::map_unchecked_mut is safe as long as the move and drop guarantees are propagated through the mapping. |
| // This is trivially satisfied since our future is only a newtype decorator of the generator. |
| let pinned_generator = |
| unsafe { self.map_unchecked_mut(|future| &mut future.generator) }; |
| |
| match pinned_generator.resume() { |
| GeneratorState::Yielded(()) => Poll::Pending, |
| GeneratorState::Complete(out) => Poll::Ready(out), |
| } |
| } |
| } |
| } |