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
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Utilities for compating between futures 0.1 and futures 0.3 tasks.

#![doc(html_root_url = "https://docs.rs/task-compat/0.1.0")]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]

use futures01::{
    executor::{Notify, NotifyHandle, UnsafeNotify},
    Async, Poll as Poll01,
};
use futures03::task::{ArcWake, WakerRef};
use std::{
    sync::Arc,
    task::{Context, Poll as Poll03, RawWaker, RawWakerVTable, Waker},
};

/// Map a `std::task::Context` into the proper context
/// for `futures 0.1`.
pub fn with_notify<F, R>(cx: &mut Context<'_>, f: F) -> R
where
    F: FnOnce() -> R,
{
    let mut spawn = futures01::task::spawn(());

    // TODO: We should find a way to take advantage of the
    // `&static Notify` convert.
    let notify = Arc::new(NotifyWaker(cx.waker().clone()));

    spawn.poll_fn_notify(&notify, 0, |_| f())
}

/// Map a `futures 0.1` notify to a `std::task::Context`.
pub fn with_context<F, R>(f: F) -> R
where
    F: FnOnce(&mut Context<'_>) -> R,
{
    let current = Current::new();
    let waker = current.as_waker();
    let mut cx = Context::from_waker(&waker);

    f(&mut cx)
}

/// Map `std::task::Poll` to a `futures 0.1` poll.
pub fn poll_03_to_01<T, E>(x: Poll03<Result<T, E>>) -> Poll01<T, E> {
    match x? {
        Poll03::Ready(t) => Ok(Async::Ready(t)),
        Poll03::Pending => Ok(Async::NotReady),
    }
}

/// Map `futures 0.1` poll to `std::task::Poll`.
pub fn poll_01_to_03<T, E>(x: Poll01<T, E>) -> Poll03<Result<T, E>> {
    match x {
        Ok(Async::Ready(v)) => Poll03::Ready(Ok(v)),
        Ok(Async::NotReady) => Poll03::Pending,
        Err(e) => Poll03::Ready(Err(e)),
    }
}

// Waker adapters ported from `futures-util/src/compat`

struct NotifyWaker(Waker);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a Waker);

impl From<WakerToHandle<'_>> for NotifyHandle {
    fn from(handle: WakerToHandle<'_>) -> NotifyHandle {
        let ptr = Box::new(NotifyWaker(handle.0.clone()));

        unsafe { NotifyHandle::new(Box::into_raw(ptr)) }
    }
}

impl Notify for NotifyWaker {
    fn notify(&self, _: usize) {
        self.0.wake_by_ref();
    }
}

unsafe impl UnsafeNotify for NotifyWaker {
    unsafe fn clone_raw(&self) -> NotifyHandle {
        WakerToHandle(&self.0).into()
    }

    unsafe fn drop_raw(&self) {
        let ptr: *const dyn UnsafeNotify = self;
        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify));
    }
}

#[derive(Clone)]
struct Current(futures01::task::Task);

impl Current {
    fn new() -> Current {
        Current(futures01::task::current())
    }

    fn as_waker(&self) -> WakerRef<'_> {
        unsafe fn ptr_to_current<'a>(ptr: *const ()) -> &'a Current {
            &*(ptr as *const Current)
        }
        fn current_to_ptr(current: &Current) -> *const () {
            current as *const Current as *const ()
        }

        unsafe fn clone(ptr: *const ()) -> RawWaker {
            // Lazily create the `Arc` only when the waker is actually cloned.
            // FIXME: remove `transmute` when a `Waker` -> `RawWaker` conversion
            // function is landed in `core`.
            std::mem::transmute::<Waker, RawWaker>(futures03::task::waker(Arc::new(
                ptr_to_current(ptr).clone(),
            )))
        }
        unsafe fn drop(_: *const ()) {}
        unsafe fn wake(ptr: *const ()) {
            ptr_to_current(ptr).0.notify()
        }

        let ptr = current_to_ptr(self);
        let vtable = &RawWakerVTable::new(clone, wake, wake, drop);
        futures03::task::WakerRef::new_unowned(std::mem::ManuallyDrop::new(unsafe {
            futures03::task::Waker::from_raw(RawWaker::new(ptr, vtable))
        }))
    }
}

impl ArcWake for Current {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        arc_self.0.notify();
    }
}