about summary refs log tree commit diff
path: root/src/libcore/future
diff options
context:
space:
mode:
authorJosef Reinhard Brandl <mail@josefbrandl.de>2018-06-30 21:16:44 +0200
committerJosef Reinhard Brandl <mail@josefbrandl.de>2018-07-02 13:59:40 +0200
commitd8bf2223672973f9d86f6c173793bcfce7890cd8 (patch)
tree641557daeb359a6b32a1b2eca7af0bded0b80b96 /src/libcore/future
parent9f70e7fe3c4126bf8390a78e4740ade3261ac4df (diff)
Add lifetime to `FutureObj`
Diffstat (limited to 'src/libcore/future')
-rw-r--r--src/libcore/future/future.rs112
-rw-r--r--src/libcore/future/future_obj.rs149
-rw-r--r--src/libcore/future/mod.rs21
3 files changed, 282 insertions, 0 deletions
diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs
new file mode 100644
index 00000000000..10b4ca9b0b2
--- /dev/null
+++ b/src/libcore/future/future.rs
@@ -0,0 +1,112 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+use mem::PinMut;
+use marker::Unpin;
+use task::{self, Poll};
+
+/// A future represents an asychronous computation.
+///
+/// A future is a value that may not have finished computing yet. This kind of
+/// "asynchronous value" makes it possible for a thread to continue doing useful
+/// work while it waits for the value to become available.
+///
+/// # The `poll` method
+///
+/// The core method of future, `poll`, *attempts* to resolve the future into a
+/// final value. This method does not block if the value is not ready. Instead,
+/// the current task is scheduled to be woken up when it's possible to make
+/// further progress by `poll`ing again. The wake up is performed using
+/// `cx.waker()`, a handle for waking up the current task.
+///
+/// When using a future, you generally won't call `poll` directly, but instead
+/// `await!` the value.
+pub trait Future {
+    /// The result of the `Future`.
+    type Output;
+
+    /// Attempt to resolve the future to a final value, registering
+    /// the current task for wakeup if the value is not yet available.
+    ///
+    /// # Return value
+    ///
+    /// This function returns:
+    ///
+    /// - [`Poll::Pending`] if the future is not ready yet
+    /// - [`Poll::Ready(val)`] with the result `val` of this future if it
+    ///   finished successfully.
+    ///
+    /// Once a future has finished, clients should not `poll` it again.
+    ///
+    /// When a future is not ready yet, `poll` returns
+    /// `Poll::Pending`. The future will *also* register the
+    /// interest of the current task in the value being produced. For example,
+    /// if the future represents the availability of data on a socket, then the
+    /// task is recorded so that when data arrives, it is woken up (via
+    /// [`cx.waker()`]). Once a task has been woken up,
+    /// it should attempt to `poll` the future again, which may or may not
+    /// produce a final value.
+    ///
+    /// Note that if `Pending` is returned it only means that the *current* task
+    /// (represented by the argument `cx`) will receive a notification. Tasks
+    /// from previous calls to `poll` will *not* receive notifications.
+    ///
+    /// # Runtime characteristics
+    ///
+    /// Futures alone are *inert*; they must be *actively* `poll`ed to make
+    /// progress, meaning that each time the current task is woken up, it should
+    /// actively re-`poll` pending futures that it still has an interest in.
+    ///
+    /// The `poll` function is not called repeatedly in a tight loop for
+    /// futures, but only whenever the future itself is ready, as signaled via
+    /// the `Waker` inside `task::Context`. If you're familiar with the
+    /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
+    /// typically do *not* suffer the same problems of "all wakeups must poll
+    /// all events"; they are more like `epoll(4)`.
+    ///
+    /// An implementation of `poll` should strive to return quickly, and must
+    /// *never* block. Returning quickly prevents unnecessarily clogging up
+    /// threads or event loops. If it is known ahead of time that a call to
+    /// `poll` may end up taking awhile, the work should be offloaded to a
+    /// thread pool (or something similar) to ensure that `poll` can return
+    /// quickly.
+    ///
+    /// # Panics
+    ///
+    /// Once a future has completed (returned `Ready` from `poll`),
+    /// then any future calls to `poll` may panic, block forever, or otherwise
+    /// cause bad behavior. The `Future` trait itself provides no guarantees
+    /// about the behavior of `poll` after a future has completed.
+    ///
+    /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
+    /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
+    /// [`cx.waker()`]: ../task/struct.Context.html#method.waker
+    fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output>;
+}
+
+impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F {
+    type Output = F::Output;
+
+    fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
+        F::poll(PinMut::new(&mut **self), cx)
+    }
+}
+
+impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> {
+    type Output = F::Output;
+
+    fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
+        F::poll((*self).reborrow(), cx)
+    }
+}
diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs
new file mode 100644
index 00000000000..c60b8b97d34
--- /dev/null
+++ b/src/libcore/future/future_obj.rs
@@ -0,0 +1,149 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+use fmt;
+use future::Future;
+use marker::PhantomData;
+use mem::PinMut;
+use task::{Context, Poll};
+
+/// A custom trait object for polling futures, roughly akin to
+/// `Box<dyn Future<Output = T>>`.
+/// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound.
+pub struct LocalFutureObj<'a, T> {
+    ptr: *mut (),
+    poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<T>,
+    drop_fn: unsafe fn(*mut ()),
+    _marker1: PhantomData<T>,
+    _marker2: PhantomData<&'a ()>,
+}
+
+impl<'a, T> LocalFutureObj<'a, T> {
+    /// Create a `LocalFutureObj` from a custom trait object representation.
+    #[inline]
+    pub fn new<F: UnsafeFutureObj<'a, T> + 'a>(f: F) -> LocalFutureObj<'a, T> {
+        LocalFutureObj {
+            ptr: f.into_raw(),
+            poll_fn: F::poll,
+            drop_fn: F::drop,
+            _marker1: PhantomData,
+            _marker2: PhantomData,
+        }
+    }
+
+    /// Converts the `LocalFutureObj` into a `FutureObj`
+    /// To make this operation safe one has to ensure that the `UnsafeFutureObj`
+    /// instance from which this `LocalFutureObj` was created actually
+    /// implements `Send`.
+    #[inline]
+    pub unsafe fn as_future_obj(self) -> FutureObj<'a, T> {
+        FutureObj(self)
+    }
+}
+
+impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("LocalFutureObj")
+            .finish()
+    }
+}
+
+impl<'a, T> From<FutureObj<'a, T>> for LocalFutureObj<'a, T> {
+    #[inline]
+    fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> {
+        f.0
+    }
+}
+
+impl<'a, T> Future for LocalFutureObj<'a, T> {
+    type Output = T;
+
+    #[inline]
+    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
+        unsafe {
+            (self.poll_fn)(self.ptr, cx)
+        }
+    }
+}
+
+impl<'a, T> Drop for LocalFutureObj<'a, T> {
+    fn drop(&mut self) {
+        unsafe {
+            (self.drop_fn)(self.ptr)
+        }
+    }
+}
+
+/// A custom trait object for polling futures, roughly akin to
+/// `Box<dyn Future<Output = T>> + Send`.
+pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>);
+
+unsafe impl<'a, T> Send for FutureObj<'a, T> {}
+
+impl<'a, T> FutureObj<'a, T> {
+    /// Create a `FutureObj` from a custom trait object representation.
+    #[inline]
+    pub fn new<F: UnsafeFutureObj<'a, T> + Send>(f: F) -> FutureObj<'a, T> {
+        FutureObj(LocalFutureObj::new(f))
+    }
+}
+
+impl<'a, T> fmt::Debug for FutureObj<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("FutureObj")
+            .finish()
+    }
+}
+
+impl<'a, T> Future for FutureObj<'a, T> {
+    type Output = T;
+
+    #[inline]
+    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
+        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
+        pinned_field.poll(cx)
+    }
+}
+
+/// A custom implementation of a future trait object for `FutureObj`, providing
+/// a hand-rolled vtable.
+///
+/// This custom representation is typically used only in `no_std` contexts,
+/// where the default `Box`-based implementation is not available.
+///
+/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
+/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
+/// called.
+pub unsafe trait UnsafeFutureObj<'a, T>: 'a {
+    /// Convert a owned instance into a (conceptually owned) void pointer.
+    fn into_raw(self) -> *mut ();
+
+    /// Poll the future represented by the given void pointer.
+    ///
+    /// # Safety
+    ///
+    /// The trait implementor must guarantee that it is safe to repeatedly call
+    /// `poll` with the result of `into_raw` until `drop` is called; such calls
+    /// are not, however, allowed to race with each other or with calls to `drop`.
+    unsafe fn poll(future: *mut (), cx: &mut Context) -> Poll<T>;
+
+    /// Drops the future represented by the given void pointer.
+    ///
+    /// # Safety
+    ///
+    /// The trait implementor must guarantee that it is safe to call this
+    /// function once per `into_raw` invocation; that call cannot race with
+    /// other calls to `drop` or `poll`.
+    unsafe fn drop(future: *mut ());
+}
diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs
new file mode 100644
index 00000000000..f9361a0f4e7
--- /dev/null
+++ b/src/libcore/future/mod.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+//! Asynchronous values.
+
+mod future;
+pub use self::future::Future;
+
+mod future_obj;
+pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj};