|  | 
|  | 1 | +//! Definition of the `PinnedFut` adapter combinator | 
|  | 2 | +
 | 
|  | 3 | +// TODO: import `Pinned` and use it to make `Borrowed` immovable. | 
|  | 4 | +use core::mem::PinMut; | 
|  | 5 | + | 
|  | 6 | +use futures_core::{Future, Poll}; | 
|  | 7 | +use futures_core::task; | 
|  | 8 | + | 
|  | 9 | +pub trait PinnedFnLt<'a, Data: 'a, Output> { | 
|  | 10 | +    type Future: Future<Output = Output> + 'a; | 
|  | 11 | +    fn apply(self, data: PinMut<'a, Data>) -> Self::Future; | 
|  | 12 | +} | 
|  | 13 | + | 
|  | 14 | +pub trait PinnedFn<Data, Output>: for<'a> PinnedFnLt<'a, Data, Output> {} | 
|  | 15 | +impl<Data, Output, T> PinnedFn<Data, Output> for T | 
|  | 16 | +    where T: for<'a> PinnedFnLt<'a, Data, Output> {} | 
|  | 17 | + | 
|  | 18 | +impl<'a, Data, Output, Fut, T> PinnedFnLt<'a, Data, Output> for T | 
|  | 19 | +where | 
|  | 20 | +    Data: 'a, | 
|  | 21 | +    T: FnOnce(PinMut<'a, Data>) -> Fut, | 
|  | 22 | +    Fut: Future<Output = Output> + 'a, | 
|  | 23 | +{ | 
|  | 24 | +    type Future = Fut; | 
|  | 25 | +    fn apply(self, data: PinMut<'a, Data>) -> Self::Future { | 
|  | 26 | +        (self)(data) | 
|  | 27 | +    } | 
|  | 28 | +} | 
|  | 29 | + | 
|  | 30 | +/// A future which borrows a value for an asynchronous lifetime. | 
|  | 31 | +/// | 
|  | 32 | +/// Created by the `borrowed` function. | 
|  | 33 | +#[must_use = "futures do nothing unless polled"] | 
|  | 34 | +#[allow(missing_debug_implementations)] | 
|  | 35 | +pub struct PinnedFut<'any, Data: 'any, Output, F: PinnedFn<Data, Output> + 'any> { | 
|  | 36 | +    fn_or_fut: FnOrFut<'any, Data, Output, F>, | 
|  | 37 | +    // TODO: | 
|  | 38 | +    // marker: Pinned, | 
|  | 39 | +    // Data, which may be borrowed by `fn_or_fut`, must be dropped last | 
|  | 40 | +    data: Data, | 
|  | 41 | +} | 
|  | 42 | + | 
|  | 43 | +enum FnOrFut<'any, Data: 'any, Output, F: PinnedFn<Data, Output> + 'any> { | 
|  | 44 | +    F(F), | 
|  | 45 | +    Fut(<F as PinnedFnLt<'any, Data, Output>>::Future), | 
|  | 46 | +    None, | 
|  | 47 | +} | 
|  | 48 | + | 
|  | 49 | +impl<'any, Data: 'any, Output, F: PinnedFn<Data, Output> + 'any> FnOrFut<'any, Data, Output, F> { | 
|  | 50 | +    fn is_fn(&self) -> bool { | 
|  | 51 | +        if let FnOrFut::F(_) = self { | 
|  | 52 | +            true | 
|  | 53 | +        } else { | 
|  | 54 | +            false | 
|  | 55 | +        } | 
|  | 56 | +    } | 
|  | 57 | +} | 
|  | 58 | + | 
|  | 59 | +/// Creates a new future which pins some data and borrows it for an | 
|  | 60 | +/// asynchronous lifetime. | 
|  | 61 | +pub fn pinned<'any, Data, Output, F>(data: Data, f: F) -> PinnedFut<'any, Data, Output, F> | 
|  | 62 | +    where F: PinnedFn<Data, Output> + 'any, | 
|  | 63 | +          Data: 'any, | 
|  | 64 | +{ | 
|  | 65 | +    PinnedFut { | 
|  | 66 | +        fn_or_fut: FnOrFut::F(f), | 
|  | 67 | +        data, | 
|  | 68 | +    } | 
|  | 69 | +} | 
|  | 70 | + | 
|  | 71 | +unsafe fn transmute_lt<'input, 'output, T>(x: &'input mut T) -> &'output mut T { | 
|  | 72 | +    ::std::mem::transmute(x) | 
|  | 73 | +} | 
|  | 74 | + | 
|  | 75 | +impl<'any, Data, Output, F> Future for PinnedFut<'any, Data, Output, F> | 
|  | 76 | +    where F: PinnedFn<Data, Output> + 'any, | 
|  | 77 | +          Data: 'any, | 
|  | 78 | +{ | 
|  | 79 | +    type Output = <<F as PinnedFnLt<'any, Data, Output>>::Future as Future>::Output; | 
|  | 80 | + | 
|  | 81 | +    fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> { | 
|  | 82 | +        unsafe { | 
|  | 83 | +            let this = PinMut::get_mut(self); | 
|  | 84 | +            if this.fn_or_fut.is_fn() { | 
|  | 85 | +                if let FnOrFut::F(f) = ::std::mem::replace(&mut this.fn_or_fut, FnOrFut::None) { | 
|  | 86 | +                    let fut = f.apply(PinMut::new_unchecked(transmute_lt(&mut this.data))); | 
|  | 87 | +                    this.fn_or_fut = FnOrFut::Fut(fut); | 
|  | 88 | +                } else { | 
|  | 89 | +                    unreachable!() | 
|  | 90 | +                } | 
|  | 91 | +            } | 
|  | 92 | + | 
|  | 93 | +            let res = if let FnOrFut::Fut(fut) = &mut this.fn_or_fut {  | 
|  | 94 | +                PinMut::new_unchecked(fut).poll(cx) | 
|  | 95 | +            } else { | 
|  | 96 | +                panic!("polled PinnedFut after completion") | 
|  | 97 | +            }; | 
|  | 98 | + | 
|  | 99 | +            if let Poll::Ready(_) = &res { | 
|  | 100 | +                this.fn_or_fut = FnOrFut::None; | 
|  | 101 | +            } | 
|  | 102 | + | 
|  | 103 | +            res | 
|  | 104 | +        } | 
|  | 105 | +    } | 
|  | 106 | +} | 
|  | 107 | + | 
|  | 108 | +#[allow(unused)] | 
|  | 109 | +fn does_compile() -> impl Future<Output = u8> { | 
|  | 110 | +    pinned(5, |x: PinMut<_>| { // This type annotation is *required* to compile | 
|  | 111 | +        ::future::lazy(move |_cx| { | 
|  | 112 | +            // we can use (copy from) the asynchronously borrowed data here | 
|  | 113 | +            *x | 
|  | 114 | +        }) | 
|  | 115 | +    }) | 
|  | 116 | +} | 
0 commit comments