Skip to content

Commit 0260116

Browse files
committed
Get rid of Chain as the building block for other combinators and remove some unsafe code
1 parent 2f8943d commit 0260116

File tree

5 files changed

+63
-139
lines changed

5 files changed

+63
-139
lines changed

futures-util/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ memchr = { version = "2.2", optional = true }
4545
futures_01 = { version = "0.1.25", optional = true, package = "futures" }
4646
tokio-io = { version = "0.1.9", optional = true }
4747
pin-utils = "0.1.0-alpha.4"
48+
pin-project = "0.4.8"
4849

4950
[dev-dependencies]
5051
futures = { path = "../futures", version = "0.3.4", features = ["async-await", "thread-pool"] }

futures-util/src/future/future/chain.rs

-58
This file was deleted.
+58-30
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,84 @@
1-
use super::chain::Chain;
2-
use core::fmt;
1+
use core::fmt::{self, Debug};
32
use core::pin::Pin;
43
use futures_core::future::{FusedFuture, Future};
54
use futures_core::task::{Context, Poll};
6-
use pin_utils::unsafe_pinned;
5+
use pin_project::pin_project;
76

8-
/// Future for the [`flatten`](super::FutureExt::flatten) method.
9-
#[must_use = "futures do nothing unless you `.await` or poll them"]
10-
pub struct Flatten<Fut>
7+
#[pin_project]
8+
#[derive(Debug)]
9+
enum InternalFlatten<Fut: Future> {
10+
First(#[pin] Fut),
11+
Second(#[pin] Fut::Output),
12+
Empty,
13+
}
14+
15+
impl<Fut: Future> InternalFlatten<Fut> {
16+
fn new(future: Fut) -> Self {
17+
Self::First(future)
18+
}
19+
}
20+
21+
impl<Fut> FusedFuture for InternalFlatten<Fut>
1122
where Fut: Future,
23+
Fut::Output: Future,
1224
{
13-
state: Chain<Fut, Fut::Output, ()>,
25+
fn is_terminated(&self) -> bool {
26+
match self {
27+
Self::Empty => true,
28+
_ => false,
29+
}
30+
}
1431
}
1532

16-
impl<Fut> Flatten<Fut>
33+
impl<Fut> Future for InternalFlatten<Fut>
1734
where Fut: Future,
1835
Fut::Output: Future,
1936
{
20-
unsafe_pinned!(state: Chain<Fut, Fut::Output, ()>);
37+
type Output = <Fut::Output as Future>::Output;
2138

22-
pub(super) fn new(future: Fut) -> Flatten<Fut> {
23-
Flatten {
24-
state: Chain::new(future, ()),
25-
}
39+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
40+
Poll::Ready(loop {
41+
match self.as_mut().project() {
42+
__InternalFlattenProjection::First(f) => {
43+
let f = ready!(f.poll(cx));
44+
self.set(Self::Second(f));
45+
},
46+
__InternalFlattenProjection::Second(f) => {
47+
let output = ready!(f.poll(cx));
48+
self.set(Self::Empty);
49+
break output;
50+
},
51+
__InternalFlattenProjection::Empty => unreachable!()
52+
}
53+
})
2654
}
2755
}
2856

29-
impl<Fut> fmt::Debug for Flatten<Fut>
30-
where Fut: Future + fmt::Debug,
31-
Fut::Output: fmt::Debug,
32-
{
57+
/// Future for the [`flatten`](super::FutureExt::flatten) method.
58+
#[must_use = "futures do nothing unless you `.await` or poll them"]
59+
#[pin_project]
60+
pub struct Flatten<Fut: Future>(#[pin] InternalFlatten<Fut>);
61+
62+
impl<Fut: Debug + Future> Debug for Flatten<Fut> where Fut::Output: Debug {
3363
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34-
f.debug_struct("Flatten")
35-
.field("state", &self.state)
36-
.finish()
64+
self.0.fmt(f)
3765
}
3866
}
3967

40-
impl<Fut> FusedFuture for Flatten<Fut>
41-
where Fut: Future,
42-
Fut::Output: Future,
43-
{
44-
fn is_terminated(&self) -> bool { self.state.is_terminated() }
68+
impl<Fut: Future> Flatten<Fut> {
69+
pub(super) fn new(future: Fut) -> Self {
70+
Self(InternalFlatten::new(future))
71+
}
4572
}
4673

47-
impl<Fut> Future for Flatten<Fut>
48-
where Fut: Future,
49-
Fut::Output: Future,
50-
{
74+
impl<Fut: Future> FusedFuture for Flatten<Fut> where Fut::Output: Future {
75+
fn is_terminated(&self) -> bool { self.0.is_terminated() }
76+
}
77+
78+
impl<Fut: Future> Future for Flatten<Fut> where Fut::Output: Future {
5179
type Output = <Fut::Output as Future>::Output;
5280

5381
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
54-
self.state().poll(cx, |a, ()| a)
82+
self.project().0.poll(cx)
5583
}
5684
}

futures-util/src/future/future/mod.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,6 @@ mod shared;
7373
#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
7474
pub use self::shared::Shared;
7575

76-
// Implementation details
77-
78-
mod chain;
79-
pub(crate) use self::chain::Chain;
80-
8176
impl<T: ?Sized> FutureExt for T where T: Future {}
8277

8378
/// An extension trait for `Future`s that provides a variety of convenient
@@ -137,13 +132,13 @@ pub trait FutureExt: Future {
137132
/// assert_eq!(future_of_4.await, 4);
138133
/// # });
139134
/// ```
140-
fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
135+
fn then<Fut, F>(self, f: F) -> Then<Self, F>
141136
where
142137
F: FnOnce(Self::Output) -> Fut,
143138
Fut: Future,
144139
Self: Sized,
145140
{
146-
assert_future::<Fut::Output, _>(Then::new(self, f))
141+
assert_future::<Fut::Output, _>(Flatten::new(Map::new(self, f)))
147142
}
148143

149144
/// Wrap this future in an `Either` future, making it the left-hand variant
+2-44
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,4 @@
1-
use super::Chain;
2-
use core::pin::Pin;
3-
use futures_core::future::{FusedFuture, Future};
4-
use futures_core::task::{Context, Poll};
5-
use pin_utils::unsafe_pinned;
1+
use super::{Map, Flatten};
62

73
/// Future for the [`then`](super::FutureExt::then) method.
8-
#[derive(Debug)]
9-
#[must_use = "futures do nothing unless you `.await` or poll them"]
10-
pub struct Then<Fut1, Fut2, F> {
11-
chain: Chain<Fut1, Fut2, F>,
12-
}
13-
14-
impl<Fut1, Fut2, F> Then<Fut1, Fut2, F>
15-
where Fut1: Future,
16-
Fut2: Future,
17-
{
18-
unsafe_pinned!(chain: Chain<Fut1, Fut2, F>);
19-
20-
/// Creates a new `Then`.
21-
pub(super) fn new(future: Fut1, f: F) -> Then<Fut1, Fut2, F> {
22-
Then {
23-
chain: Chain::new(future, f),
24-
}
25-
}
26-
}
27-
28-
impl<Fut1, Fut2, F> FusedFuture for Then<Fut1, Fut2, F>
29-
where Fut1: Future,
30-
Fut2: Future,
31-
F: FnOnce(Fut1::Output) -> Fut2,
32-
{
33-
fn is_terminated(&self) -> bool { self.chain.is_terminated() }
34-
}
35-
36-
impl<Fut1, Fut2, F> Future for Then<Fut1, Fut2, F>
37-
where Fut1: Future,
38-
Fut2: Future,
39-
F: FnOnce(Fut1::Output) -> Fut2,
40-
{
41-
type Output = Fut2::Output;
42-
43-
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Fut2::Output> {
44-
self.as_mut().chain().poll(cx, |output, f| f(output))
45-
}
46-
}
4+
pub type Then<Fut1, F> = Flatten<Map<Fut1, F>>;

0 commit comments

Comments
 (0)