Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 403718b

Browse files
committed
feat: add try_waker and From<&mut Context> for ContextBuilder to allow the extention of contexts by futures
1 parent 232cc2b commit 403718b

File tree

2 files changed

+78
-21
lines changed

2 files changed

+78
-21
lines changed

library/alloc/src/task.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,15 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
165165
166166
/// # Examples
167167
///
168-
/// A
169-
///
170168
/// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function
171169
/// is used to push new tasks onto the run queue, while the block on function will remove them
172170
/// and poll them. When a task is woken, it will put itself back on the run queue to be polled by the executor.
173171
///
174172
/// **Note:** A real world example would interlieve poll calls with calls to an io reactor to wait for events instead
175-
/// of spinning on a loop.
173+
/// of spinning on a loop.
176174
///
177175
/// ```rust
176+
/// #![feature(local_waker)]
178177
/// use std::task::{LocalWake, ContextBuilder, LocalWaker};
179178
/// use std::future::Future;
180179
/// use std::pin::Pin;
@@ -204,9 +203,9 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
204203
/// where
205204
/// F: Future<Output=()> + 'static + Send + Sync
206205
/// {
207-
/// let task = Rc::new(Box::pin(future));
206+
/// let task = RefCell::new(Box::pin(future));
208207
/// RUN_QUEUE.with_borrow_mut(|queue| {
209-
/// queue.push_back(task)
208+
/// queue.push_back(Rc::new(Task(task)));
210209
/// });
211210
/// }
212211
///
@@ -221,19 +220,22 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
221220
/// return;
222221
/// };
223222
/// // cast the Rc<Task> into a `LocalWaker`
224-
/// let waker: LocalWaker = task.into();
223+
/// let waker: LocalWaker = task.clone().into();
225224
/// // Build the context using `ContextBuilder`
226-
/// let mut cx = ContextBuilder::new()
227-
/// .local_waker(&waker)
225+
/// let mut cx = ContextBuilder::from_local_waker(&waker)
228226
/// .build();
229227
///
230228
/// // Poll the task
231-
/// task.0
229+
/// let _ = task.0
232230
/// .borrow_mut()
233231
/// .as_mut()
234232
/// .poll(&mut cx);
235233
/// }
236234
/// }
235+
///
236+
/// block_on(async {
237+
/// println!("hello world");
238+
/// });
237239
/// ```
238240
///
239241
#[unstable(feature = "local_waker", issue = "none")]

library/core/src/task/wake.rs

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -225,21 +225,32 @@ impl<'a> Context<'a> {
225225
/// # Panics
226226
/// This function will panic if no `Waker` was set on the context. This happens if
227227
/// the executor does not support working with thread safe wakers. An alternative
228-
/// may be to call [`.local_waker()`](Context::local_waker) instead.
228+
/// may be to call [`.local_waker()`](Context::local_waker) instead. For a fallible
229+
/// version of this function see [`.try_waker()`](Context::try_waker).
230+
#[inline]
231+
#[must_use]
229232
#[stable(feature = "futures_api", since = "1.36.0")]
230233
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
231-
#[must_use]
232-
#[inline]
233234
pub const fn waker(&self) -> &'a Waker {
234235
&self
235236
.waker
236237
.expect("no waker was set on this context, consider calling `local_waker` instead.")
237238
}
238239
/// Returns a reference to the [`LocalWaker`] for the current task.
240+
#[inline]
239241
#[unstable(feature = "local_waker", issue = "none")]
240-
pub fn local_waker(&self) -> &'a LocalWaker {
242+
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
243+
pub const fn local_waker(&self) -> &'a LocalWaker {
241244
&self.local_waker
242245
}
246+
/// Returns a `Some(&Waker)` if a waker was defined on the `Context`,
247+
/// otherwise it returns `None`.
248+
#[inline]
249+
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
250+
#[unstable(feature = "local_waker", issue = "none")]
251+
pub const fn try_waker(&self) -> Option<&'a Waker> {
252+
self.waker
253+
}
243254
}
244255

245256
#[stable(feature = "futures_api", since = "1.36.0")]
@@ -256,18 +267,19 @@ impl fmt::Debug for Context<'_> {
256267
/// ```
257268
/// #![feature(local_waker)]
258269
/// #![feature(noop_waker)]
259-
/// use std::task::{ContextBuilder, LocalWaker, Waker};
260-
///
270+
/// use std::task::{ContextBuilder, LocalWaker, Waker, Poll};
271+
/// use std::future::Future;
272+
///
261273
/// let local_waker = LocalWaker::noop();
262274
/// let waker = Waker::noop();
263275
///
264-
/// let context = ContextBuilder::from_local_waker(&local_waker)
276+
/// let mut cx = ContextBuilder::from_local_waker(&local_waker)
265277
/// .waker(&waker)
266278
/// .build();
267279
///
268-
/// let future = pin::pin!(async { 20 });
269-
/// let poll = future.poll(&mut context);
270-
/// assert_eq!(poll, task::Poll::Ready(20));
280+
/// let mut future = std::pin::pin!(async { 20 });
281+
/// let poll = future.as_mut().poll(&mut cx);
282+
/// assert_eq!(poll, Poll::Ready(20));
271283
///
272284
/// ```
273285
#[unstable(feature = "local_waker", issue = "none")]
@@ -323,6 +335,50 @@ impl<'a> ContextBuilder<'a> {
323335
}
324336
}
325337

338+
/// Construct a `ContextBuilder`` from a `Context`. This is useful for
339+
/// overriding values from a context.
340+
///
341+
/// # Examples
342+
/// An example of a future that allows to set a Waker on Context if none was defined.
343+
/// This can be used to await futures that require a `Waker` even if the runtime does not
344+
/// support `Waker`.
345+
/// ```rust
346+
/// #![feature(noop_waker, local_waker)]
347+
/// use std::task::{Waker, ContextBuilder};
348+
/// use std::future::{poll_fn, Future};
349+
/// use std::pin::pin;
350+
///
351+
/// async fn with_waker<F>(f: F, waker: &Waker) -> F::Output
352+
/// where
353+
/// F: Future
354+
/// {
355+
/// let mut f = pin!(f);
356+
/// poll_fn(move |cx| {
357+
/// let has_waker = cx.try_waker().is_some();
358+
/// if has_waker {
359+
/// return f.as_mut().poll(cx);
360+
/// }
361+
///
362+
/// let mut cx = ContextBuilder::from(cx)
363+
/// .waker(&waker)
364+
/// .build();
365+
/// f.as_mut().poll(&mut cx)
366+
/// }).await
367+
/// }
368+
///
369+
/// # async fn __() {
370+
/// with_waker(async { /* ... */ }, &Waker::noop()).await;
371+
/// # }
372+
/// ```
373+
#[unstable(feature = "local_waker", issue = "none")]
374+
impl<'a> From<&mut Context<'a>> for ContextBuilder<'a> {
375+
#[inline]
376+
fn from(value: &mut Context<'a>) -> Self {
377+
let Context { waker, local_waker, .. } = *value;
378+
ContextBuilder { waker, local_waker }
379+
}
380+
}
381+
326382
/// A `Waker` is a handle for waking up a task by notifying its executor that it
327383
/// is ready to be run.
328384
///
@@ -559,12 +615,11 @@ impl fmt::Debug for Waker {
559615
/// })
560616
/// }
561617
///
562-
/// # #[allow(unused_must_use)]
563618
/// # async fn __() {
564619
/// yield_now().await;
565620
/// # }
566621
/// ```
567-
///
622+
///
568623
/// [`Future::poll()`]: core::future::Future::poll
569624
/// [`Poll::Pending`]: core::task::Poll::Pending
570625
/// [`local_waker`]: core::task::Context::local_waker

0 commit comments

Comments
 (0)