]> git.proxmox.com Git - rustc.git/blame - src/libstd/future.rs
New upstream version 1.37.0+dfsg1
[rustc.git] / src / libstd / future.rs
CommitLineData
8faf50e0
XL
1//! Asynchronous values.
2
3use core::cell::Cell;
4use core::marker::Unpin;
0bf4aa26 5use core::pin::Pin;
8faf50e0
XL
6use core::option::Option;
7use core::ptr::NonNull;
532ac7d7 8use core::task::{Context, Poll};
8faf50e0
XL
9use core::ops::{Drop, Generator, GeneratorState};
10
11#[doc(inline)]
48663c56 12#[stable(feature = "futures_api", since = "1.36.0")]
8faf50e0
XL
13pub use core::future::*;
14
9fa01778 15/// Wrap a generator in a future.
8faf50e0
XL
16///
17/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
18/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
dc9dc135 19#[doc(hidden)]
8faf50e0
XL
20#[unstable(feature = "gen_future", issue = "50547")]
21pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
22 GenFuture(x)
23}
24
25/// A wrapper around generators used to implement `Future` for `async`/`await` code.
dc9dc135 26#[doc(hidden)]
8faf50e0
XL
27#[unstable(feature = "gen_future", issue = "50547")]
28#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
29struct GenFuture<T: Generator<Yield = ()>>(T);
30
31// We rely on the fact that async/await futures are immovable in order to create
32// self-referential borrows in the underlying generator.
33impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
34
dc9dc135 35#[doc(hidden)]
8faf50e0
XL
36#[unstable(feature = "gen_future", issue = "50547")]
37impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
38 type Output = T::Return;
532ac7d7 39 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
9fa01778
XL
40 // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
41 let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
532ac7d7 42 set_task_context(cx, || match gen.resume() {
8faf50e0
XL
43 GeneratorState::Yielded(()) => Poll::Pending,
44 GeneratorState::Complete(x) => Poll::Ready(x),
45 })
46 }
47}
48
49thread_local! {
532ac7d7 50 static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
8faf50e0
XL
51}
52
532ac7d7 53struct SetOnDrop(Option<NonNull<Context<'static>>>);
8faf50e0
XL
54
55impl Drop for SetOnDrop {
56 fn drop(&mut self) {
532ac7d7
XL
57 TLS_CX.with(|tls_cx| {
58 tls_cx.set(self.0.take());
8faf50e0
XL
59 });
60 }
61}
62
dc9dc135 63#[doc(hidden)]
8faf50e0
XL
64#[unstable(feature = "gen_future", issue = "50547")]
65/// Sets the thread-local task context used by async/await futures.
532ac7d7 66pub fn set_task_context<F, R>(cx: &mut Context<'_>, f: F) -> R
8faf50e0
XL
67where
68 F: FnOnce() -> R
69{
532ac7d7
XL
70 // transmute the context's lifetime to 'static so we can store it.
71 let cx = unsafe {
72 core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx)
73 };
74 let old_cx = TLS_CX.with(|tls_cx| {
75 tls_cx.replace(Some(NonNull::from(cx)))
8faf50e0 76 });
532ac7d7 77 let _reset = SetOnDrop(old_cx);
8faf50e0
XL
78 f()
79}
80
dc9dc135 81#[doc(hidden)]
8faf50e0 82#[unstable(feature = "gen_future", issue = "50547")]
532ac7d7 83/// Retrieves the thread-local task context used by async/await futures.
8faf50e0 84///
532ac7d7 85/// This function acquires exclusive access to the task context.
8faf50e0 86///
532ac7d7
XL
87/// Panics if no context has been set or if the context has already been
88/// retrieved by a surrounding call to get_task_context.
89pub fn get_task_context<F, R>(f: F) -> R
8faf50e0 90where
532ac7d7 91 F: FnOnce(&mut Context<'_>) -> R
8faf50e0 92{
532ac7d7 93 let cx_ptr = TLS_CX.with(|tls_cx| {
0bf4aa26 94 // Clear the entry so that nested `get_task_waker` calls
8faf50e0 95 // will fail or set their own value.
532ac7d7 96 tls_cx.replace(None)
8faf50e0 97 });
532ac7d7 98 let _reset = SetOnDrop(cx_ptr);
8faf50e0 99
532ac7d7
XL
100 let mut cx_ptr = cx_ptr.expect(
101 "TLS Context not set. This is a rustc bug. \
8faf50e0 102 Please file an issue on https://github.com/rust-lang/rust.");
532ac7d7
XL
103
104 // Safety: we've ensured exclusive access to the context by
105 // removing the pointer from TLS, only to be replaced once
106 // we're done with it.
107 //
108 // The pointer that was inserted came from an `&mut Context<'_>`,
109 // so it is safe to treat as mutable.
110 unsafe { f(cx_ptr.as_mut()) }
8faf50e0
XL
111}
112
dc9dc135 113#[doc(hidden)]
8faf50e0 114#[unstable(feature = "gen_future", issue = "50547")]
0bf4aa26 115/// Polls a future in the current thread-local task waker.
532ac7d7 116pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
8faf50e0
XL
117where
118 F: Future
119{
532ac7d7 120 get_task_context(|cx| F::poll(f, cx))
8faf50e0 121}