task_compat/
lib.rs

1//! Utilities for compating between futures 0.1 and futures 0.3 tasks.
2
3#![doc(html_root_url = "https://docs.rs/task-compat/0.1.0")]
4#![warn(
5    missing_debug_implementations,
6    missing_docs,
7    rust_2018_idioms,
8    unreachable_pub
9)]
10
11use futures01::{
12    executor::{Notify, NotifyHandle, UnsafeNotify},
13    Async, Poll as Poll01,
14};
15use futures03::task::{ArcWake, WakerRef};
16use std::{
17    sync::Arc,
18    task::{Context, Poll as Poll03, RawWaker, RawWakerVTable, Waker},
19};
20
21/// Map a `std::task::Context` into the proper context
22/// for `futures 0.1`.
23pub fn with_notify<F, R>(cx: &mut Context<'_>, f: F) -> R
24where
25    F: FnOnce() -> R,
26{
27    let mut spawn = futures01::task::spawn(());
28
29    // TODO: We should find a way to take advantage of the
30    // `&static Notify` convert.
31    let notify = Arc::new(NotifyWaker(cx.waker().clone()));
32
33    spawn.poll_fn_notify(&notify, 0, |_| f())
34}
35
36/// Map a `futures 0.1` notify to a `std::task::Context`.
37pub fn with_context<F, R>(f: F) -> R
38where
39    F: FnOnce(&mut Context<'_>) -> R,
40{
41    let current = Current::new();
42    let waker = current.as_waker();
43    let mut cx = Context::from_waker(&waker);
44
45    f(&mut cx)
46}
47
48/// Map `std::task::Poll` to a `futures 0.1` poll.
49pub fn poll_03_to_01<T, E>(x: Poll03<Result<T, E>>) -> Poll01<T, E> {
50    match x? {
51        Poll03::Ready(t) => Ok(Async::Ready(t)),
52        Poll03::Pending => Ok(Async::NotReady),
53    }
54}
55
56/// Map `futures 0.1` poll to `std::task::Poll`.
57pub fn poll_01_to_03<T, E>(x: Poll01<T, E>) -> Poll03<Result<T, E>> {
58    match x {
59        Ok(Async::Ready(v)) => Poll03::Ready(Ok(v)),
60        Ok(Async::NotReady) => Poll03::Pending,
61        Err(e) => Poll03::Ready(Err(e)),
62    }
63}
64
65// Waker adapters ported from `futures-util/src/compat`
66
67struct NotifyWaker(Waker);
68
69#[derive(Clone)]
70struct WakerToHandle<'a>(&'a Waker);
71
72impl From<WakerToHandle<'_>> for NotifyHandle {
73    fn from(handle: WakerToHandle<'_>) -> NotifyHandle {
74        let ptr = Box::new(NotifyWaker(handle.0.clone()));
75
76        unsafe { NotifyHandle::new(Box::into_raw(ptr)) }
77    }
78}
79
80impl Notify for NotifyWaker {
81    fn notify(&self, _: usize) {
82        self.0.wake_by_ref();
83    }
84}
85
86unsafe impl UnsafeNotify for NotifyWaker {
87    unsafe fn clone_raw(&self) -> NotifyHandle {
88        WakerToHandle(&self.0).into()
89    }
90
91    unsafe fn drop_raw(&self) {
92        let ptr: *const dyn UnsafeNotify = self;
93        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify));
94    }
95}
96
97#[derive(Clone)]
98struct Current(futures01::task::Task);
99
100impl Current {
101    fn new() -> Current {
102        Current(futures01::task::current())
103    }
104
105    fn as_waker(&self) -> WakerRef<'_> {
106        unsafe fn ptr_to_current<'a>(ptr: *const ()) -> &'a Current {
107            &*(ptr as *const Current)
108        }
109        fn current_to_ptr(current: &Current) -> *const () {
110            current as *const Current as *const ()
111        }
112
113        unsafe fn clone(ptr: *const ()) -> RawWaker {
114            // Lazily create the `Arc` only when the waker is actually cloned.
115            // FIXME: remove `transmute` when a `Waker` -> `RawWaker` conversion
116            // function is landed in `core`.
117            std::mem::transmute::<Waker, RawWaker>(futures03::task::waker(Arc::new(
118                ptr_to_current(ptr).clone(),
119            )))
120        }
121        unsafe fn drop(_: *const ()) {}
122        unsafe fn wake(ptr: *const ()) {
123            ptr_to_current(ptr).0.notify()
124        }
125
126        let ptr = current_to_ptr(self);
127        let vtable = &RawWakerVTable::new(clone, wake, wake, drop);
128        futures03::task::WakerRef::new_unowned(std::mem::ManuallyDrop::new(unsafe {
129            futures03::task::Waker::from_raw(RawWaker::new(ptr, vtable))
130        }))
131    }
132}
133
134impl ArcWake for Current {
135    fn wake_by_ref(arc_self: &Arc<Self>) {
136        arc_self.0.notify();
137    }
138}