Skip to content

Commit 1a764a7

Browse files
Add futures scaffolding to libcore
1 parent 660326e commit 1a764a7

File tree

2 files changed

+97
-7
lines changed

2 files changed

+97
-7
lines changed

src/libcore/future/mod.rs

+79
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,85 @@
22

33
//! Asynchronous values.
44
5+
#[cfg(not(bootstrap))]
6+
use crate::{
7+
ops::{Generator, GeneratorState},
8+
pin::Pin,
9+
ptr::NonNull,
10+
task::{Context, Poll},
11+
};
12+
513
mod future;
614
#[stable(feature = "futures_api", since = "1.36.0")]
715
pub use self::future::Future;
16+
17+
/// This type is needed because:
18+
///
19+
/// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass
20+
/// a raw pointer.
21+
/// b) Raw pointers and `NonNull` aren't `Send` or `Sync`, so that would make every single future
22+
/// non-Send/Sync as well, and we don't want that.
23+
///
24+
/// It also simplifies the HIR lowering of `.await`.
25+
#[doc(hidden)]
26+
#[unstable(feature = "gen_future", issue = "50547")]
27+
#[cfg(not(bootstrap))]
28+
#[derive(Debug, Copy, Clone)]
29+
pub struct ResumeTy(pub NonNull<Context<'static>>);
30+
31+
#[unstable(feature = "gen_future", issue = "50547")]
32+
#[cfg(not(bootstrap))]
33+
unsafe impl Send for ResumeTy {}
34+
35+
#[unstable(feature = "gen_future", issue = "50547")]
36+
#[cfg(not(bootstrap))]
37+
unsafe impl Sync for ResumeTy {}
38+
39+
/// Wrap a generator in a future.
40+
///
41+
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
42+
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
43+
// This is `const` to avoid extra errors after we recover from `const async fn`
44+
#[doc(hidden)]
45+
#[unstable(feature = "gen_future", issue = "50547")]
46+
#[cfg(not(bootstrap))]
47+
#[inline]
48+
pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
49+
where
50+
T: Generator<ResumeTy, Yield = ()>
51+
{
52+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
53+
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
54+
55+
// We rely on the fact that async/await futures are immovable in order to create
56+
// self-referential borrows in the underlying generator.
57+
impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {}
58+
59+
impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
60+
type Output = T::Return;
61+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
62+
// Safety: Safe because we're !Unpin + !Drop mapping to a ?Unpin value
63+
let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
64+
65+
// Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The
66+
// `.await` lowering will safely cast that back to a `&mut Context`.
67+
match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
68+
GeneratorState::Yielded(()) => Poll::Pending,
69+
GeneratorState::Complete(x) => Poll::Ready(x),
70+
}
71+
}
72+
}
73+
74+
GenFuture(gen)
75+
}
76+
77+
#[doc(hidden)]
78+
#[unstable(feature = "gen_future", issue = "50547")]
79+
#[cfg(not(bootstrap))]
80+
#[inline]
81+
pub unsafe fn poll_with_context<F>(f: Pin<&mut F>, mut cx: ResumeTy) -> Poll<F::Output>
82+
where
83+
F: Future,
84+
{
85+
F::poll(f, cx.0.as_mut())
86+
}

src/libstd/future.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! Asynchronous values.
22
3-
use core::cell::Cell;
4-
use core::marker::Unpin;
5-
use core::ops::{Drop, Generator, GeneratorState};
6-
use core::option::Option;
7-
use core::pin::Pin;
8-
use core::ptr::NonNull;
9-
use core::task::{Context, Poll};
3+
#[cfg(bootstrap)]
4+
use core::{
5+
cell::Cell,
6+
marker::Unpin,
7+
ops::{Drop, Generator, GeneratorState},
8+
pin::Pin,
9+
ptr::NonNull,
10+
task::{Context, Poll},
11+
};
1012

1113
#[doc(inline)]
1214
#[stable(feature = "futures_api", since = "1.36.0")]
@@ -17,22 +19,26 @@ pub use core::future::*;
1719
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
1820
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
1921
// This is `const` to avoid extra errors after we recover from `const async fn`
22+
#[cfg(bootstrap)]
2023
#[doc(hidden)]
2124
#[unstable(feature = "gen_future", issue = "50547")]
2225
pub const fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
2326
GenFuture(x)
2427
}
2528

2629
/// A wrapper around generators used to implement `Future` for `async`/`await` code.
30+
#[cfg(bootstrap)]
2731
#[doc(hidden)]
2832
#[unstable(feature = "gen_future", issue = "50547")]
2933
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
3034
struct GenFuture<T: Generator<Yield = ()>>(T);
3135

3236
// We rely on the fact that async/await futures are immovable in order to create
3337
// self-referential borrows in the underlying generator.
38+
#[cfg(bootstrap)]
3439
impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
3540

41+
#[cfg(bootstrap)]
3642
#[doc(hidden)]
3743
#[unstable(feature = "gen_future", issue = "50547")]
3844
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
@@ -48,12 +54,15 @@ impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
4854
}
4955
}
5056

57+
#[cfg(bootstrap)]
5158
thread_local! {
5259
static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
5360
}
5461

62+
#[cfg(bootstrap)]
5563
struct SetOnDrop(Option<NonNull<Context<'static>>>);
5664

65+
#[cfg(bootstrap)]
5766
impl Drop for SetOnDrop {
5867
fn drop(&mut self) {
5968
TLS_CX.with(|tls_cx| {
@@ -64,13 +73,15 @@ impl Drop for SetOnDrop {
6473

6574
// Safety: the returned guard must drop before `cx` is dropped and before
6675
// any previous guard is dropped.
76+
#[cfg(bootstrap)]
6777
unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop {
6878
// transmute the context's lifetime to 'static so we can store it.
6979
let cx = core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx);
7080
let old_cx = TLS_CX.with(|tls_cx| tls_cx.replace(Some(NonNull::from(cx))));
7181
SetOnDrop(old_cx)
7282
}
7383

84+
#[cfg(bootstrap)]
7485
#[doc(hidden)]
7586
#[unstable(feature = "gen_future", issue = "50547")]
7687
/// Polls a future in the current thread-local task waker.

0 commit comments

Comments
 (0)