+2
.gitignore
+2
.gitignore
+16
-1
Cargo.lock
+16
-1
Cargo.lock
···
3
version = 4
4
5
[[package]]
6
+
name = "futures-combinators"
7
+
version = "0.1.0"
8
+
dependencies = [
9
+
"futures-core",
10
+
"futures-util",
11
+
]
12
+
13
+
[[package]]
14
+
name = "futures-core"
15
version = "0.1.0"
16
+
17
+
[[package]]
18
+
name = "futures-util"
19
+
version = "0.1.0"
20
+
dependencies = [
21
+
"futures-core",
22
+
]
+1
-1
Cargo.toml
+1
-1
Cargo.toml
+13
futures-combinators/Cargo.toml
+13
futures-combinators/Cargo.toml
···
···
1
+
[package]
2
+
name = "futures-combinators"
3
+
version.workspace = true
4
+
rust-version.workspace = true
5
+
edition.workspace = true
6
+
license.workspace = true
7
+
authors.workspace = true
8
+
repository.workspace = true
9
+
homepage.workspace = true
10
+
11
+
[dependencies]
12
+
futures-core = { path = "../futures-core" }
13
+
futures-util = { path = "../futures-util" }
+1
futures-combinators/src/lib.rs
+1
futures-combinators/src/lib.rs
···
···
1
+
mod join;
+11
futures-core/Cargo.toml
+11
futures-core/Cargo.toml
+12
futures-util/Cargo.toml
+12
futures-util/Cargo.toml
···
···
1
+
[package]
2
+
name = "futures-util"
3
+
version.workspace = true
4
+
rust-version.workspace = true
5
+
edition.workspace = true
6
+
license.workspace = true
7
+
authors.workspace = true
8
+
repository.workspace = true
9
+
homepage.workspace = true
10
+
11
+
[dependencies]
12
+
futures-core = { path = "../futures-core" }
+13
futures-util/src/lib.rs
+13
futures-util/src/lib.rs
···
···
1
+
mod maybe_done;
2
+
3
+
use futures_core::ScopedFuture;
4
+
pub use maybe_done::*;
5
+
6
+
// Just a helper function to ensure the futures we're returning all have the
7
+
// right implementations.
8
+
pub(crate) fn assert_future<'scope, T, F>(future: F) -> F
9
+
where
10
+
F: ScopedFuture<'scope, Output = T>,
11
+
{
12
+
future
13
+
}
+5
-4
futures/src/combinators/join.rs
futures-combinators/src/join.rs
+5
-4
futures/src/combinators/join.rs
futures-combinators/src/join.rs
···
1
-
use crate::{
2
-
future::{ScopedFuture, Wake},
3
-
utils::{MaybeDone, maybe_done},
4
-
};
5
use std::mem;
6
use std::{pin::Pin, sync::atomic::Ordering};
7
use std::{sync::atomic::AtomicBool, task::Poll};
···
63
/// This function returns a new future which polls all futures concurrently.
64
fn join(self) -> Self::Future;
65
}
66
struct WakeStore<'scope> {
67
parent: Option<&'scope dyn Wake<'scope>>,
68
ready: AtomicBool,
69
}
70
impl<'scope> WakeStore<'scope> {
71
fn new() -> Self {
72
Self {
···
78
self.ready.swap(false, Ordering::SeqCst)
79
}
80
}
81
impl<'scope> Wake<'scope> for WakeStore<'scope> {
82
fn wake(&self) {
83
self.ready.swap(true, Ordering::SeqCst);
···
1
+
use futures_core::{ScopedFuture, Wake};
2
+
use futures_util::{MaybeDone, maybe_done};
3
use std::mem;
4
use std::{pin::Pin, sync::atomic::Ordering};
5
use std::{sync::atomic::AtomicBool, task::Poll};
···
61
/// This function returns a new future which polls all futures concurrently.
62
fn join(self) -> Self::Future;
63
}
64
+
65
struct WakeStore<'scope> {
66
parent: Option<&'scope dyn Wake<'scope>>,
67
ready: AtomicBool,
68
}
69
+
70
impl<'scope> WakeStore<'scope> {
71
fn new() -> Self {
72
Self {
···
78
self.ready.swap(false, Ordering::SeqCst)
79
}
80
}
81
+
82
impl<'scope> Wake<'scope> for WakeStore<'scope> {
83
fn wake(&self) {
84
self.ready.swap(true, Ordering::SeqCst);
-10
futures/src/future.rs
futures-core/src/lib.rs
-10
futures/src/future.rs
futures-core/src/lib.rs
···
36
/// what occurs in `core::task::Future::poll()` is that the ref to a cx.waker
37
/// is cloned and stored by a reactor via some method.
38
///
39
-
///
40
/// The waker is no longer tied to the actual future's lifetime, making it
41
/// unsound to not have either static tasks or reference counting.
42
/// To avoid this, we want to use a &'scope waker instead, with 1 waker / task.
43
-
///
44
-
/// If waker is ownable/cloneable, that erases the lifetime's importance.
45
-
/// If the waker is a non clonable mutable reference that lives for 'scope,
46
-
/// it cannot be passed into `poll` every time the future is polled, instead it
47
-
/// must only be registered once, leading to a register_waker api that is very
48
-
/// cumbersome without unsafe poll/unsafe register_waker. Instead, it's easier
49
-
/// to use a non clonable immutable reference and have waking occur via
50
-
/// interior mutability (this is fine since combinators rely on interior
51
-
/// mutability anyway for a 1 parent : many children waker relationship)
52
pub trait ScopedFuture<'scope> {
53
type Output;
54
···
36
/// what occurs in `core::task::Future::poll()` is that the ref to a cx.waker
37
/// is cloned and stored by a reactor via some method.
38
///
39
/// The waker is no longer tied to the actual future's lifetime, making it
40
/// unsound to not have either static tasks or reference counting.
41
/// To avoid this, we want to use a &'scope waker instead, with 1 waker / task.
42
pub trait ScopedFuture<'scope> {
43
type Output;
44
+1
-1
futures/src/utils/maybe_done.rs
futures-util/src/maybe_done.rs
+1
-1
futures/src/utils/maybe_done.rs
futures-util/src/maybe_done.rs
futures/src/utils/mod.rs
futures-util/src/mod.rs
futures/src/utils/mod.rs
futures-util/src/mod.rs