about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/alloc/src/task.rs16
-rw-r--r--library/core/src/task/wake.rs99
2 files changed, 28 insertions, 87 deletions
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index 7dad2f3f822..357f7e0650a 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -173,14 +173,16 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
 ///
 /// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function
 /// is used to push new tasks onto the run queue, while the block on function will remove them
-/// and poll them. When a task is woken, it will put itself back on the run queue to be polled by the executor.
+/// and poll them. When a task is woken, it will put itself back on the run queue to be polled
+/// by the executor.
 ///
-/// **Note:** A real world example would interleave poll calls with calls to an io reactor to wait for events instead
-/// of spinning on a loop.
+/// **Note:** This example trades correctness for simplicity. A real world example would interleave
+/// poll calls with calls to an io reactor to wait for events instead of spinning on a loop.
 ///
 /// ```rust
 /// #![feature(local_waker)]
-/// use std::task::{LocalWake, ContextBuilder, LocalWaker};
+/// #![feature(noop_waker)]
+/// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker};
 /// use std::future::Future;
 /// use std::pin::Pin;
 /// use std::rc::Rc;
@@ -225,10 +227,12 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
 ///             // we exit, since there are no more tasks remaining on the queue
 ///             return;
 ///         };
+///         let waker = Waker::noop();
 ///         // cast the Rc<Task> into a `LocalWaker`
-///         let waker: LocalWaker = task.clone().into();
+///         let local_waker: LocalWaker = task.clone().into();
 ///         // Build the context using `ContextBuilder`
-///         let mut cx = ContextBuilder::from_local_waker(&waker)
+///         let mut cx = ContextBuilder::from_waker(&waker)
+///             .local_waker(&local_waker)
 ///             .build();
 ///
 ///         // Poll the task
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 6a5b5a3fb54..a746fe58f47 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -217,7 +217,7 @@ impl RawWakerVTable {
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[lang = "Context"]
 pub struct Context<'a> {
-    waker: Option<&'a Waker>,
+    waker: &'a Waker,
     local_waker: &'a LocalWaker,
     // Ensure we future-proof against variance changes by forcing
     // the lifetime to be invariant (argument-position lifetimes
@@ -245,9 +245,7 @@ impl<'a> Context<'a> {
     #[stable(feature = "futures_api", since = "1.36.0")]
     #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
     pub const fn waker(&self) -> &'a Waker {
-        &self
-            .waker
-            .expect("no waker was set on this context, consider calling `local_waker` instead.")
+        &self.waker
     }
     /// Returns a reference to the [`LocalWaker`] for the current task.
     #[inline]
@@ -256,14 +254,6 @@ impl<'a> Context<'a> {
     pub const fn local_waker(&self) -> &'a LocalWaker {
         &self.local_waker
     }
-    /// Returns a `Some(&Waker)` if a waker was defined on the `Context`,
-    /// otherwise it returns `None`.
-    #[inline]
-    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
-    #[unstable(feature = "local_waker", issue = "118959")]
-    pub const fn try_waker(&self) -> Option<&'a Waker> {
-        self.waker
-    }
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
@@ -286,8 +276,8 @@ impl fmt::Debug for Context<'_> {
 /// let local_waker = LocalWaker::noop();
 /// let waker = Waker::noop();
 ///
-/// let mut cx = ContextBuilder::from_local_waker(&local_waker)
-///     .waker(&waker)
+/// let mut cx = ContextBuilder::from_waker(&waker)
+///     .local_waker(&local_waker)
 ///     .build();
 ///
 /// let mut future = std::pin::pin!(async { 20 });
@@ -298,8 +288,16 @@ impl fmt::Debug for Context<'_> {
 #[unstable(feature = "local_waker", issue = "118959")]
 #[derive(Debug)]
 pub struct ContextBuilder<'a> {
-    waker: Option<&'a Waker>,
+    waker: &'a Waker,
     local_waker: &'a LocalWaker,
+    // Ensure we future-proof against variance changes by forcing
+    // the lifetime to be invariant (argument-position lifetimes
+    // are contravariant while return-position lifetimes are
+    // covariant).
+    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
+    // Ensure `Context` is `!Send` and `!Sync` in order to allow
+    // for future `!Send` and / or `!Sync` fields.
+    _marker2: PhantomData<*mut ()>,
 }
 
 impl<'a> ContextBuilder<'a> {
@@ -310,23 +308,7 @@ impl<'a> ContextBuilder<'a> {
     pub const fn from_waker(waker: &'a Waker) -> Self {
         // SAFETY: LocalWaker is just Waker without thread safety
         let local_waker = unsafe { transmute(waker) };
-        Self { waker: Some(waker), local_waker }
-    }
-
-    /// Create a ContextBuilder from a LocalWaker.
-    #[inline]
-    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
-    #[unstable(feature = "local_waker", issue = "118959")]
-    pub const fn from_local_waker(local_waker: &'a LocalWaker) -> Self {
-        Self { local_waker, waker: None }
-    }
-
-    /// This field is used to set the value of the waker on `Context`.
-    #[inline]
-    #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
-    #[unstable(feature = "local_waker", issue = "118959")]
-    pub const fn waker(self, waker: &'a Waker) -> Self {
-        Self { waker: Some(waker), ..self }
+        Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData }
     }
 
     /// This method is used to set the value for the local waker on `Context`.
@@ -342,52 +324,8 @@ impl<'a> ContextBuilder<'a> {
     #[unstable(feature = "local_waker", issue = "118959")]
     #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
     pub const fn build(self) -> Context<'a> {
-        let ContextBuilder { waker, local_waker } = self;
-        Context { waker, local_waker, _marker: PhantomData, _marker2: PhantomData }
-    }
-}
-
-/// Construct a [`ContextBuilder`] from a [`Context`]. This is useful for
-/// overriding values from a context.
-///
-/// # Examples
-/// An example of a future that allows to set a [`Waker`] on Context if none was defined.
-/// This can be used to await futures that require a [`Waker`] even if the runtime does not
-/// support [`Waker`].
-/// ```rust
-/// #![feature(noop_waker, local_waker)]
-/// use std::task::{Waker, ContextBuilder};
-/// use std::future::{poll_fn, Future};
-/// use std::pin::pin;
-///
-/// async fn with_waker<F>(f: F, waker: &Waker) -> F::Output
-/// where
-///     F: Future
-/// {
-///     let mut f = pin!(f);
-///     poll_fn(move |cx| {
-///         let has_waker = cx.try_waker().is_some();
-///         if has_waker {
-///             return f.as_mut().poll(cx);
-///         }
-///
-///         let mut cx = ContextBuilder::from(cx)
-///             .waker(&waker)
-///             .build();
-///         f.as_mut().poll(&mut cx)
-///     }).await
-/// }
-///
-/// # async fn __() {
-/// with_waker(async { /* ... */ }, &Waker::noop()).await;
-/// # }
-/// ```
-#[unstable(feature = "local_waker", issue = "118959")]
-impl<'a> From<&mut Context<'a>> for ContextBuilder<'a> {
-    #[inline]
-    fn from(value: &mut Context<'a>) -> Self {
-        let Context { waker, local_waker, _marker, _marker2 } = *value;
-        ContextBuilder { waker, local_waker }
+        let ContextBuilder { waker, local_waker, _marker, _marker2 } = self;
+        Context { waker, local_waker, _marker, _marker2 }
     }
 }
 
@@ -600,8 +538,7 @@ impl fmt::Debug for Waker {
 /// Implements [`Clone`], but neither [`Send`] nor [`Sync`]; therefore, a local waker may
 /// not be moved to other threads. In general, when deciding to use wakers or local wakers,
 /// local wakers are preferable unless the waker needs to be sent across threads. This is because
-/// wakers can incur in additional cost related to memory synchronization, and not all executors
-/// may support wakers.
+/// wakers can incur in additional cost related to memory synchronization.
 ///
 /// Note that it is preferable to use `local_waker.clone_from(&new_waker)` instead
 /// of `*local_waker = new_waker.clone()`, as the former will avoid cloning the waker
@@ -738,7 +675,7 @@ impl LocalWaker {
     /// use std::future::Future;
     /// use std::task::{ContextBuilder, LocalWaker};
     ///
-    /// let mut cx = task::ContextBuilder::new()
+    /// let mut cx = task::ContextBuilder::from_waker(Waker::noop())
     ///     .local_waker(LocalWaker::noop())
     ///     .build();
     ///