fixed remaining join and race test cases

Changed files
+304 -208
futures-combinators
futures-compat
src
futures-core
src
futures-util
+6 -99
Cargo.lock
··· 42 42 ] 43 43 44 44 [[package]] 45 - name = "futures" 46 - version = "0.3.31" 47 - source = "registry+https://github.com/rust-lang/crates.io-index" 48 - checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 49 - dependencies = [ 50 - "futures-channel", 51 - "futures-core 0.3.31", 52 - "futures-executor", 53 - "futures-io", 54 - "futures-sink", 55 - "futures-task", 56 - "futures-util", 57 - ] 58 - 59 - [[package]] 60 - name = "futures-channel" 61 - version = "0.3.31" 62 - source = "registry+https://github.com/rust-lang/crates.io-index" 63 - checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 64 - dependencies = [ 65 - "futures-core 0.3.31", 66 - "futures-sink", 67 - ] 68 - 69 - [[package]] 70 45 name = "futures-combinators" 71 46 version = "0.0.2" 72 47 dependencies = [ 73 - "futures 0.3.31", 74 48 "futures-compat", 75 - "futures-core 0.0.2", 49 + "futures-core", 50 + "futures-util", 76 51 "lifetime-guard", 77 52 ] 78 53 ··· 80 55 name = "futures-compat" 81 56 version = "0.0.2" 82 57 dependencies = [ 83 - "futures-core 0.0.2", 58 + "futures-core", 84 59 "lifetime-guard", 85 60 ] 86 61 ··· 89 64 version = "0.0.2" 90 65 91 66 [[package]] 92 - name = "futures-core" 93 - version = "0.3.31" 94 - source = "registry+https://github.com/rust-lang/crates.io-index" 95 - checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 96 - 97 - [[package]] 98 67 name = "futures-derive" 99 68 version = "0.0.2" 100 69 dependencies = [ ··· 104 73 ] 105 74 106 75 [[package]] 107 - name = "futures-executor" 108 - version = "0.3.31" 109 - source = "registry+https://github.com/rust-lang/crates.io-index" 110 - checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 111 - dependencies = [ 112 - "futures-core 0.3.31", 113 - "futures-task", 114 - "futures-util", 115 - ] 116 - 117 - [[package]] 118 - name = "futures-io" 119 - version = "0.3.31" 120 - source = "registry+https://github.com/rust-lang/crates.io-index" 121 - checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 122 - 123 - [[package]] 124 - name = "futures-macro" 125 - version = "0.3.31" 126 - source = "registry+https://github.com/rust-lang/crates.io-index" 127 - checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 128 - dependencies = [ 129 - "proc-macro2", 130 - "quote", 131 - "syn", 132 - ] 133 - 134 - [[package]] 135 - name = "futures-sink" 136 - version = "0.3.31" 137 - source = "registry+https://github.com/rust-lang/crates.io-index" 138 - checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 139 - 140 - [[package]] 141 - name = "futures-task" 142 - version = "0.3.31" 143 - source = "registry+https://github.com/rust-lang/crates.io-index" 144 - checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 145 - 146 - [[package]] 147 76 name = "futures-util" 148 - version = "0.3.31" 149 - source = "registry+https://github.com/rust-lang/crates.io-index" 150 - checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 77 + version = "0.0.2" 151 78 dependencies = [ 152 - "futures-channel", 153 - "futures-core 0.3.31", 154 - "futures-io", 155 - "futures-macro", 156 - "futures-sink", 157 - "futures-task", 158 - "memchr", 159 - "pin-project-lite", 160 - "pin-utils", 161 - "slab", 79 + "futures-core", 80 + "lifetime-guard", 162 81 ] 163 82 164 83 [[package]] ··· 258 177 checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 259 178 260 179 [[package]] 261 - name = "pin-utils" 262 - version = "0.1.0" 263 - source = "registry+https://github.com/rust-lang/crates.io-index" 264 - checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 265 - 266 - [[package]] 267 180 name = "proc-macro2" 268 181 version = "1.0.95" 269 182 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 351 264 version = "1.3.0" 352 265 source = "registry+https://github.com/rust-lang/crates.io-index" 353 266 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 354 - 355 - [[package]] 356 - name = "slab" 357 - version = "0.4.11" 358 - source = "registry+https://github.com/rust-lang/crates.io-index" 359 - checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 360 267 361 268 [[package]] 362 269 name = "smallvec"
+2 -3
Cargo.toml
··· 1 1 [workspace] 2 2 resolver = "3" 3 - members = [ "futures", "futures-combinators", "futures-compat", "futures-core", "futures-derive", "lifetime-guard"] 3 + members = [ "futures", "futures-combinators", "futures-compat", "futures-core", "futures-derive", "futures-util", "lifetime-guard"] 4 4 5 5 [workspace.package] 6 6 version = "0.0.2" ··· 17 17 futures-compat = { path = "futures-compat", version = "0.0.2" } 18 18 futures-core = { path = "futures-core", version = "0.0.2" } 19 19 futures-derive = { path = "futures-derive", version = "0.0.2" } 20 + futures-util = { path = "futures-util", version = "0.0.2" } 20 21 lifetime-guard = { path = "lifetime-guard", version = "0.0.2" } 21 - # TODO probably vendor in 22 - futures = "0.3"
+24 -28
futures-combinators/src/join.rs
··· 137 137 mod tests { 138 138 #![no_std] 139 139 140 - use futures_core::{Future, Wake}; 141 - use lifetime_guard::guard::ValueGuard; 140 + use futures_core::Future; 142 141 143 - use crate::wake::{DummyWaker, local_wake, poll_fn}; 142 + use crate::wake::{dummy_guard, local_wake, poll_fn}; 144 143 145 144 use super::*; 146 145 147 146 use std::pin; 148 - use std::ptr::NonNull; 149 147 150 148 #[test] 151 149 fn counters() { ··· 169 167 Poll::Pending 170 168 } 171 169 }); 172 - let guard = pin::pin!(ValueGuard::new(NonNull::new( 173 - &mut DummyWaker as *mut dyn Wake, 174 - ))); 175 - let join = (f1, f2).join(); 176 - let mut pinned = pin::pin!(join); 170 + let guard = pin::pin!(dummy_guard()); 171 + let mut join = pin::pin!((f1, f2).join()); 177 172 for _ in 0..4 { 178 - assert_eq!(pinned.as_mut().poll(guard.as_ref()), Poll::Pending); 173 + assert_eq!(join.as_mut().poll(guard.as_ref()), Poll::Pending); 179 174 } 180 - assert_eq!(pinned.poll(guard.as_ref()), Poll::Ready((4, 5))); 175 + assert_eq!(join.poll(guard.as_ref()), Poll::Ready((4, 5))); 181 176 } 182 177 183 - // #[test] 184 - // fn never_wake() { 185 - // let f1 = poll_fn(|_| Poll::<i32>::Pending); 186 - // let f2 = poll_fn(|_| Poll::<i32>::Pending); 187 - // let dummy_waker = noop_wake(); 188 - // let join = (f1, f2).join(); 189 - // for _ in 0..10 { 190 - // assert_eq!(join.poll(&dummy_waker), Poll::Pending); 191 - // } 192 - // } 178 + #[test] 179 + fn never_wake() { 180 + let f1 = poll_fn(|_| Poll::<i32>::Ready(0)); 181 + let f2 = poll_fn(|_| Poll::<i32>::Pending); 182 + let guard = pin::pin!(dummy_guard()); 183 + let mut join = pin::pin!((f1, f2).join()); 184 + for _ in 0..10 { 185 + assert_eq!(join.as_mut().poll(guard.as_ref()), Poll::Pending); 186 + } 187 + } 193 188 194 - // #[test] 195 - // fn basic() { 196 - // let f1 = poll_fn(|_| Poll::Ready(1)); 197 - // let f2 = poll_fn(|_| Poll::Ready(2)); 198 - // let dummy_waker = noop_wake(); 199 - // assert_eq!(f1.along_with(f2).poll(&dummy_waker), Poll::Ready((1, 2))); 200 - // } 189 + #[test] 190 + fn immediate() { 191 + let f1 = poll_fn(|_| Poll::Ready(1)); 192 + let f2 = poll_fn(|_| Poll::Ready(2)); 193 + let join = pin::pin!(f1.along_with(f2)); 194 + let guard = pin::pin!(dummy_guard()); 195 + assert_eq!(join.poll(guard.as_ref()), Poll::Ready((1, 2))); 196 + } 201 197 }
+26 -36
futures-combinators/src/race.rs
··· 2 2 3 3 use crate::wake::WakeArray; 4 4 use std::pin::Pin; 5 - use std::task::Context; 6 - use std::{cell::Cell, task::Poll}; 5 + use std::task::Poll; 7 6 8 7 /// from [futures-concurrency](https://github.com/yoshuawuyts/futures-concurrency/tree/main) 9 8 /// Wait for the first future to complete. ··· 142 141 mod tests { 143 142 #![no_std] 144 143 145 - use std::{pin, ptr::NonNull}; 144 + use std::pin; 146 145 147 - use futures_core::{Future, Wake}; 148 - use lifetime_guard::guard::ValueGuard; 146 + use futures_core::Future; 149 147 150 - use crate::wake::{DummyWaker, local_wake, poll_fn}; 148 + use crate::wake::{dummy_guard, local_wake, poll_fn}; 151 149 152 150 use super::*; 153 151 ··· 173 171 Poll::Pending 174 172 } 175 173 }); 176 - let guard = pin::pin!(ValueGuard::new(NonNull::new( 177 - &mut DummyWaker as *mut dyn Wake, 178 - ))); 179 - let join = (f1, f2).race(); 180 - let mut pinned = pin::pin!(join); 181 - assert_eq!(pinned.as_mut().poll(guard.as_ref()), Poll::Pending); 182 - assert_eq!( 183 - pinned.poll(guard.as_ref()), 184 - Poll::Ready(RaceOutputs2::B(2)) 185 - ); 174 + let guard = pin::pin!(dummy_guard()); 175 + let mut race = pin::pin!((f1, f2).race()); 176 + assert_eq!(race.as_mut().poll(guard.as_ref()), Poll::Pending); 177 + assert_eq!(race.poll(guard.as_ref()), Poll::Ready(RaceOutputs2::B(2))); 186 178 } 187 179 188 - // #[test] 189 - // fn never_wake() { 190 - // let f1 = poll_fn(|_| Poll::<i32>::Pending); 191 - // let f2 = poll_fn(|_| Poll::<i32>::Pending); 192 - // let dummy_waker = noop_wake(); 193 - // let join = (f1, f2).race(); 194 - // for _ in 0..10 { 195 - // assert_eq!(join.poll(&dummy_waker), Poll::Pending); 196 - // } 197 - // } 180 + #[test] 181 + fn never_wake() { 182 + let f1 = poll_fn(|_| Poll::<i32>::Pending); 183 + let f2 = poll_fn(|_| Poll::<i32>::Pending); 184 + let mut race = pin::pin!((f1, f2).race()); 185 + let guard = pin::pin!(dummy_guard()); 186 + for _ in 0..10 { 187 + assert_eq!(race.as_mut().poll(guard.as_ref()), Poll::Pending); 188 + } 189 + } 198 190 199 - // #[test] 200 - // fn basic() { 201 - // let f1 = poll_fn(|_| Poll::Ready(1)); 202 - // let f2 = poll_fn(|_| Poll::Ready(2)); 203 - // let dummy_waker = noop_wake(); 204 - // assert_eq!( 205 - // f1.race_with(f2).poll(&dummy_waker), 206 - // Poll::Ready(RaceOutputs2::A(1)) 207 - // ); 208 - // } 191 + #[test] 192 + fn basic() { 193 + let f1 = poll_fn(|_| Poll::Ready(1)); 194 + let f2 = poll_fn(|_| Poll::Ready(2)); 195 + let race = pin::pin!(f1.race_with(f2)); 196 + let guard = pin::pin!(dummy_guard()); 197 + assert_eq!(race.poll(guard.as_ref()), Poll::Ready(RaceOutputs2::A(1))); 198 + } 209 199 }
+4
futures-combinators/src/wake.rs
··· 148 148 dbg!("awake!"); 149 149 } 150 150 } 151 + 152 + pub fn dummy_guard() -> ValueGuard<WakePtr> { 153 + ValueGuard::new(NonNull::new(&mut DummyWaker as *mut dyn Wake)) 154 + }
+57 -30
futures-compat/src/lib.rs
··· 2 2 //! with an executor/reactor intended for bcsc::Future is strictly unsound. 3 3 4 4 use std::{ 5 + hint::unreachable_unchecked, 5 6 mem::ManuallyDrop, 6 7 pin::Pin, 7 8 ptr::NonNull, ··· 11 12 use futures_core::Wake; 12 13 use lifetime_guard::{atomic_guard::AtomicValueGuard, guard::ValueGuard}; 13 14 14 - static EVIL_VTABLE: RawWakerVTable = RawWakerVTable::new( 15 - |_| panic!("wtf"), 16 - |_| panic!("wtf"), 17 - |_| panic!("wtf"), 18 - |_| panic!("wtf"), 19 - ); 20 - 21 15 pub type WakePtr = Option<NonNull<dyn Wake>>; 16 + pub type LocalWaker = ValueGuard<WakePtr>; 17 + pub type AtomicWaker = AtomicValueGuard<WakePtr>; 18 + 19 + static EVIL_VTABLE: RawWakerVTable = unsafe { 20 + RawWakerVTable::new( 21 + |_| unreachable_unchecked(), 22 + |_| unreachable_unchecked(), 23 + |_| unreachable_unchecked(), 24 + |_| unreachable_unchecked(), 25 + ) 26 + }; 22 27 23 28 /// Coerces a pinned `ValueGuard` reference to a `Waker` for use in 24 29 /// `core::future::Future` 25 30 /// 26 31 /// Any usage or storage of the resulting `Waker` is undefined behavior. 27 - pub unsafe fn guard_to_waker( 28 - guard: Pin<&ValueGuard<WakePtr>>, 29 - ) -> ManuallyDrop<Waker> { 32 + pub unsafe fn guard_to_waker(guard: Pin<&LocalWaker>) -> ManuallyDrop<Waker> { 30 33 ManuallyDrop::new(unsafe { 31 34 Waker::from_raw(RawWaker::new( 32 35 guard.get_ref() as *const ValueGuard<WakePtr> as *const (), ··· 34 37 )) 35 38 }) 36 39 } 40 + 37 41 pub unsafe fn atomic_guard_to_waker( 38 - guard: Pin<&AtomicValueGuard<WakePtr>>, 39 - ) -> Waker { 40 - unsafe { 42 + guard: Pin<&AtomicWaker>, 43 + ) -> ManuallyDrop<Waker> { 44 + ManuallyDrop::new(unsafe { 41 45 Waker::from_raw(RawWaker::new( 42 46 guard.get_ref() as *const AtomicValueGuard<WakePtr> as *const (), 43 47 &EVIL_VTABLE, 44 48 )) 45 - } 49 + }) 46 50 } 47 51 48 52 /// Coerces a `Waker` into a pinned `AtomicValueGuard` reference. 49 53 /// 50 54 /// This should only be used to undo the work of `guard_to_waker`. 51 - pub unsafe fn waker_to_guard<'a>( 52 - waker: &Waker, 53 - ) -> Pin<&'a ValueGuard<WakePtr>> { 55 + pub unsafe fn waker_to_guard<'a>(waker: &Waker) -> Pin<&LocalWaker> { 54 56 unsafe { 55 57 Pin::new_unchecked(&*(waker.data() as *const ValueGuard<WakePtr>)) 56 58 } 57 59 } 58 - pub unsafe fn waker_to_atomic_guard<'a>( 59 - waker: &Waker, 60 - ) -> Pin<&'a AtomicValueGuard<WakePtr>> { 60 + 61 + pub unsafe fn waker_to_atomic_guard<'a>(waker: &Waker) -> Pin<&AtomicWaker> { 61 62 unsafe { 62 63 Pin::new_unchecked(&*(waker.data() as *const AtomicValueGuard<WakePtr>)) 63 64 } 64 65 } 65 66 66 - // TODO should probably return impl futures_core::Future, same for next fn 67 67 pub unsafe fn std_future_to_bespoke<F: core::future::Future>( 68 68 future: F, 69 - ) -> NormalFutureWrapper<F> { 69 + ) -> impl futures_core::Future<LocalWaker, Output = F::Output> { 70 70 NormalFutureWrapper(future) 71 71 } 72 72 73 - pub unsafe fn bespoke_future_to_std<F: futures_core::Future>( 73 + pub unsafe fn bespoke_future_to_std<F: futures_core::Future<LocalWaker>>( 74 74 future: F, 75 - ) -> BespokeFutureWrapper<F> { 75 + ) -> impl core::future::Future<Output = F::Output> { 76 76 BespokeFutureWrapper(future) 77 77 } 78 78 ··· 80 80 #[repr(transparent)] 81 81 pub struct NormalFutureWrapper<F: core::future::Future>(F); 82 82 83 - impl<F: core::future::Future> futures_core::Future for NormalFutureWrapper<F> { 83 + impl<F: core::future::Future> futures_core::Future<LocalWaker> 84 + for NormalFutureWrapper<F> 85 + { 84 86 type Output = F::Output; 85 87 86 - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 87 - unsafe { self.map_unchecked_mut(|this| &mut this.0).poll(cx) } 88 + fn poll( 89 + self: Pin<&mut Self>, 90 + waker: Pin<&LocalWaker>, 91 + ) -> Poll<Self::Output> { 92 + unsafe { 93 + self.map_unchecked_mut(|this| &mut this.0) 94 + .poll(&mut Context::from_waker(&guard_to_waker(waker))) 95 + } 88 96 } 89 97 } 90 98 91 99 /// wraps custom `bcsc::Future` in impl of `core::future::Future` 92 100 #[repr(transparent)] 93 - pub struct BespokeFutureWrapper<F: futures_core::Future>(F); 101 + pub struct BespokeFutureWrapper<F>(F) 102 + where 103 + F: futures_core::Future<LocalWaker>; 94 104 95 - impl<F: futures_core::Future> core::future::Future for BespokeFutureWrapper<F> { 105 + impl<F> core::future::Future for BespokeFutureWrapper<F> 106 + where 107 + F: futures_core::Future<LocalWaker>, 108 + { 96 109 type Output = F::Output; 97 110 98 111 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 99 - unsafe { self.map_unchecked_mut(|this| &mut this.0).poll(cx) } 112 + unsafe { 113 + self.map_unchecked_mut(|this| &mut this.0) 114 + .poll(waker_to_guard(cx.waker())) 115 + } 100 116 } 101 117 } 118 + 119 + // impl<F> core::future::Future for F 120 + // where 121 + // F: for<'a> futures_core::Future<Context<'a>>, 122 + // { 123 + // type Output = F::Output; 124 + 125 + // fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 126 + // self.poll(cx.waker()) 127 + // } 128 + // } 102 129 103 130 #[cfg(test)] 104 131 mod test {
+43 -12
futures-core/src/lib.rs
··· 1 1 //! Redefinitions of task::Future to be incompatible with them 2 2 3 3 use std::{ 4 - ops, 4 + ops::{self, DerefMut}, 5 5 pin::Pin, 6 - task::{Context, Poll}, 6 + task::Poll, 7 7 }; 8 8 9 9 /// A future represents an asynchronous computation obtained by use of `async`. ··· 35 35 message = "`{Self}` is not a `bcsc::Future`", 36 36 note = "If you are trying to await a `core::future::Future` from within a `bcsc::Future`, note that the systems are incompatible." 37 37 )] 38 - pub trait Future { 38 + pub trait Future<Waker> { 39 39 /// The type of value produced on completion. 40 40 type Output; 41 41 ··· 99 99 /// [`Poll::Ready(val)`]: Poll::Ready 100 100 /// [`Waker`]: crate::task::Waker 101 101 /// [`Waker::wake`]: crate::task::Waker::wake 102 - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; 102 + fn poll(self: Pin<&mut Self>, waker: Pin<&Waker>) -> Poll<Self::Output>; 103 103 } 104 104 105 - impl<F: ?Sized + Future + Unpin> Future for &mut F { 105 + impl<Waker, F: ?Sized + Future<Waker> + Unpin> Future<Waker> for &mut F { 106 106 type Output = F::Output; 107 107 108 108 fn poll( 109 109 mut self: Pin<&mut Self>, 110 - cx: &mut Context<'_>, 110 + waker: Pin<&Waker>, 111 111 ) -> Poll<Self::Output> { 112 - F::poll(Pin::new(&mut **self), cx) 112 + F::poll(Pin::new(&mut **self), waker) 113 113 } 114 114 } 115 115 116 - impl<P> Future for Pin<P> 116 + impl<Waker, P> Future<Waker> for Pin<P> 117 117 where 118 - P: ops::DerefMut<Target: Future>, 118 + P: ops::DerefMut<Target: Future<Waker>>, 119 + { 120 + type Output = <<P as ops::Deref>::Target as Future<Waker>>::Output; 121 + 122 + fn poll(self: Pin<&mut Self>, waker: Pin<&Waker>) -> Poll<Self::Output> { 123 + <P::Target as Future<Waker>>::poll(self.as_deref_mut(), waker) 124 + } 125 + } 126 + 127 + /// A future which tracks whether or not the underlying future 128 + /// should no longer be polled. 129 + /// 130 + /// `is_terminated` will return `true` if a future should no longer be polled. 131 + /// Usually, this state occurs after `poll` (or `try_poll`) returned 132 + /// `Poll::Ready`. However, `is_terminated` may also return `true` if a future 133 + /// has become inactive and can no longer make progress and should be ignored 134 + /// or dropped rather than being `poll`ed again. 135 + pub trait FusedFuture<Waker>: Future<Waker> { 136 + /// Returns `true` if the underlying future should no longer be polled. 137 + fn is_terminated(&self) -> bool; 138 + } 139 + 140 + impl<Waker, F: FusedFuture<Waker> + ?Sized + Unpin> FusedFuture<Waker> 141 + for &mut F 119 142 { 120 - type Output = <<P as ops::Deref>::Target as Future>::Output; 143 + fn is_terminated(&self) -> bool { 144 + <F as FusedFuture<Waker>>::is_terminated(&**self) 145 + } 146 + } 121 147 122 - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 123 - <P::Target as Future>::poll(self.as_deref_mut(), cx) 148 + impl<Waker, P> FusedFuture<Waker> for Pin<P> 149 + where 150 + P: DerefMut + Unpin, 151 + P::Target: FusedFuture<Waker>, 152 + { 153 + fn is_terminated(&self) -> bool { 154 + <P::Target as FusedFuture<Waker>>::is_terminated(&**self) 124 155 } 125 156 } 126 157
+13
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 = { workspace = true } 13 + lifetime-guard = { workspace = true }
+17
futures-util/src/lib.rs
··· 1 + use std::ptr::NonNull; 2 + 3 + use futures_core::{Future, Wake}; 4 + use lifetime_guard::{atomic_guard::AtomicValueGuard, guard::ValueGuard}; 5 + 6 + pub mod maybe_done; 7 + 8 + pub type WakePtr = Option<NonNull<dyn Wake>>; 9 + pub type LocalWaker = ValueGuard<WakePtr>; 10 + pub type AtomicWaker = AtomicValueGuard<WakePtr>; 11 + 12 + pub(crate) fn assert_future<T, F>(future: F) -> F 13 + where 14 + F: Future<LocalWaker, Output = T>, 15 + { 16 + future 17 + }
+112
futures-util/src/maybe_done.rs
··· 1 + //! Definition of the MaybeDone combinator 2 + 3 + use futures_core::FusedFuture; 4 + 5 + use crate::LocalWaker; 6 + 7 + use super::assert_future; 8 + use core::mem; 9 + use core::pin::Pin; 10 + use futures_core::Future; 11 + use std::task::Poll; 12 + use std::task::ready; 13 + 14 + /// A future that may have completed. 15 + /// 16 + /// This is created by the [`maybe_done()`] function. 17 + #[derive(Debug)] 18 + pub enum MaybeDone<Fut: Future<LocalWaker>> { 19 + /// A not-yet-completed future 20 + Future(/* #[pin] */ Fut), 21 + /// The output of the completed future 22 + Done(Fut::Output), 23 + /// The empty variant after the result of a [`MaybeDone`] has been 24 + /// taken using the [`take_output`](MaybeDone::take_output) method. 25 + Gone, 26 + } 27 + 28 + impl<Fut: Future<LocalWaker> + Unpin> Unpin for MaybeDone<Fut> {} 29 + 30 + /// Wraps a future into a `MaybeDone` 31 + /// 32 + /// # Examples 33 + /// 34 + /// ``` 35 + /// # futures::executor::block_on(async { 36 + /// use core::pin::pin; 37 + /// 38 + /// use futures::future; 39 + /// 40 + /// let future = future::maybe_done(async { 5 }); 41 + /// let mut future = pin!(future); 42 + /// assert_eq!(future.as_mut().take_output(), None); 43 + /// let () = future.as_mut().await; 44 + /// assert_eq!(future.as_mut().take_output(), Some(5)); 45 + /// assert_eq!(future.as_mut().take_output(), None); 46 + /// # }); 47 + /// ``` 48 + pub fn maybe_done<Fut: Future<LocalWaker>>(future: Fut) -> MaybeDone<Fut> { 49 + assert_future::<(), _>(MaybeDone::Future(future)) 50 + } 51 + 52 + impl<Fut: Future<LocalWaker>> MaybeDone<Fut> { 53 + /// Returns an [`Option`] containing a mutable reference to the output of the future. 54 + /// The output of this method will be [`Some`] if and only if the inner 55 + /// future has been completed and [`take_output`](MaybeDone::take_output) 56 + /// has not yet been called. 57 + #[inline] 58 + pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { 59 + unsafe { 60 + match self.get_unchecked_mut() { 61 + Self::Done(res) => Some(res), 62 + _ => None, 63 + } 64 + } 65 + } 66 + 67 + /// Attempt to take the output of a `MaybeDone` without driving it 68 + /// towards completion. 69 + #[inline] 70 + pub fn take_output(self: Pin<&mut Self>) -> Option<Fut::Output> { 71 + match &*self { 72 + Self::Done(_) => {} 73 + Self::Future(_) | Self::Gone => return None, 74 + } 75 + unsafe { 76 + match mem::replace(self.get_unchecked_mut(), Self::Gone) { 77 + Self::Done(output) => Some(output), 78 + _ => unreachable!(), 79 + } 80 + } 81 + } 82 + } 83 + 84 + impl<Fut: Future<LocalWaker>> FusedFuture<LocalWaker> for MaybeDone<Fut> { 85 + fn is_terminated(&self) -> bool { 86 + match self { 87 + Self::Future(_) => false, 88 + Self::Done(_) | Self::Gone => true, 89 + } 90 + } 91 + } 92 + 93 + impl<Fut: Future<LocalWaker>> Future<LocalWaker> for MaybeDone<Fut> { 94 + type Output = (); 95 + 96 + fn poll( 97 + mut self: Pin<&mut Self>, 98 + waker: Pin<&LocalWaker>, 99 + ) -> Poll<Self::Output> { 100 + unsafe { 101 + match self.as_mut().get_unchecked_mut() { 102 + Self::Future(f) => { 103 + let res = ready!(Pin::new_unchecked(f).poll(waker)); 104 + self.set(Self::Done(res)); 105 + } 106 + Self::Done(_) => {} 107 + Self::Gone => panic!("MaybeDone polled after value taken"), 108 + } 109 + } 110 + Poll::Ready(()) 111 + } 112 + }