tests pass again

Changed files
+150 -156
futures
futures-combinators
futures-compat
src
futures-derive
src
futures-util
+1
Cargo.lock
··· 38 38 dependencies = [ 39 39 "futures-combinators", 40 40 "futures-compat", 41 + "futures-core", 41 42 "futures-derive", 42 43 ] 43 44
+2 -1
futures-combinators/src/join.rs
··· 138 138 #![no_std] 139 139 140 140 use futures_core::Future; 141 + use futures_util::{dummy_guard, poll_fn}; 141 142 142 - use crate::wake::{dummy_guard, local_wake, poll_fn}; 143 + use crate::wake::local_wake; 143 144 144 145 use super::*; 145 146
+2 -1
futures-combinators/src/race.rs
··· 144 144 use std::pin; 145 145 146 146 use futures_core::Future; 147 + use futures_util::{dummy_guard, poll_fn}; 147 148 148 - use crate::wake::{dummy_guard, local_wake, poll_fn}; 149 + use crate::wake::local_wake; 149 150 150 151 use super::*; 151 152
+1 -41
futures-combinators/src/wake.rs
··· 1 - use std::{ 2 - array, cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull, 3 - task::Poll, 4 - }; 1 + use std::{array, cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull}; 5 2 6 3 use futures_compat::{LocalWaker, WakePtr}; 7 4 use futures_core::Wake; ··· 115 112 // } 116 113 // } 117 114 // } 118 - 119 - pub struct PollFn<F, T>(F) 120 - where 121 - F: FnMut(&LocalWaker) -> Poll<T>; 122 - 123 - impl<F, T> futures_core::Future<LocalWaker> for PollFn<F, T> 124 - where 125 - F: FnMut(&LocalWaker) -> Poll<T>, 126 - { 127 - type Output = T; 128 - 129 - fn poll( 130 - self: Pin<&mut Self>, 131 - waker: Pin<&LocalWaker>, 132 - ) -> Poll<Self::Output> { 133 - (unsafe { &mut self.get_unchecked_mut().0 })(&waker) 134 - } 135 - } 136 - 137 - pub fn poll_fn<F, T>(f: F) -> impl futures_core::Future<LocalWaker, Output = T> 138 - where 139 - F: FnMut(&LocalWaker) -> Poll<T>, 140 - { 141 - PollFn(f) 142 - } 143 - 144 - pub struct DummyWaker; 145 - 146 - impl Wake for DummyWaker { 147 - fn wake(&self) { 148 - dbg!("awake!"); 149 - } 150 - } 151 - 152 - pub fn dummy_guard() -> ValueGuard<WakePtr> { 153 - ValueGuard::new(NonNull::new(&mut DummyWaker as *mut dyn Wake)) 154 - }
+2 -13
futures-compat/src/lib.rs
··· 116 116 } 117 117 } 118 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 - // } 129 - 130 119 #[cfg(test)] 131 120 mod test { 132 121 use std::pin; ··· 149 138 let waker = unsafe { guard_to_waker(guard.as_ref()) }; 150 139 let guard = unsafe { waker_to_guard(&waker) }; 151 140 assert_eq!( 152 - guard.get().unwrap().as_ptr(), 153 - &dummy as *const dyn Wake as *mut dyn Wake 141 + guard.get().unwrap().as_ptr() as *const () as usize, 142 + &dummy as *const _ as *const () as usize 154 143 ); 155 144 } 156 145 }
+72 -70
futures-derive/src/lib.rs
··· 1 1 use proc_macro::TokenStream; 2 2 use quote::{ToTokens, quote}; 3 3 use syn::{ 4 - Expr, ExprAwait, FnArg, GenericArgument, ItemFn, ReturnType, 5 - parse_macro_input, parse_quote, parse2, visit_mut::VisitMut, 4 + Expr, ExprAwait, ItemFn, ReturnType, parse_macro_input, parse_quote, 5 + parse2, visit_mut::VisitMut, 6 6 }; 7 7 8 8 /// Takes async fn that returns anonymous `Future` impl. 9 9 /// Generates fn that returns `UnscopedFutureWrapper` wrapper for the the anonymous `Future` impl. 10 10 /// 11 - /// ```rust 12 - /// fn my_func<'a, 'b>(a: &'a A, b: &'b B) -> impl ScopedFuture<'a + 'b, Output = T> + 'a + 'b { 11 + /// ```rust,ignore 12 + /// fn my_func<'a, 'b>(a: &'a A, b: &'b B) -> impl ScopedFuture<LifetimeGuard, Output = Output> { 13 13 /// let output = async move { [body] } // compilers turns this into -> impl Future<Output = T> + 'a + 'b 14 - /// unsafe { UnscopedFutureWrapper::from_future(output) } 14 + /// unsafe { futures_compat::std_future_to_bespoke(output) } 15 15 /// } 16 16 /// ``` 17 17 /// ··· 22 22 /// to actually implement this (capture all lifetimes) we use `ScopedFuture<'_> + '_` so the compiler can infer 23 23 /// lifetimes from the anonymous future impl returned by the actual inner async fn 24 24 #[proc_macro_attribute] 25 - pub fn async_scoped(_: TokenStream, item: TokenStream) -> TokenStream { 25 + pub fn async_function(_: TokenStream, item: TokenStream) -> TokenStream { 26 26 let mut item_fn = parse_macro_input!(item as ItemFn); 27 27 // Wraps *every* async expression within the function block with 28 - // `ScopedFutureWrapper`, allowing them to be treated as regular `Future` 28 + // `BespokeFutureWrapper`, allowing them to be treated as regular `Future` 29 29 // impls. 30 30 // 31 31 // This will cause a compiler error if any expression being awaited is not 32 32 // a `ScopedFuture`, which is intentional because the `Future` and 33 33 // `ScopedFuture` systems are incompatible. 34 - ScopedFutureWrappingVisitor.visit_item_fn_mut(&mut item_fn); 34 + BespokeFutureWrappingVisitor.visit_item_fn_mut(&mut item_fn); 35 35 36 36 // disable async since it is moved to the block 37 37 item_fn.sig.asyncness = None; ··· 41 41 *item_fn.block = parse_quote! { 42 42 { 43 43 let future = async move #block; 44 - unsafe { futures_compat::UnscopedFutureWrapper::from_future(future) } 44 + unsafe { futures_compat::std_future_to_bespoke(future) } 45 45 } 46 46 }; 47 47 48 - let output = match &item_fn.sig.output { 48 + let output_type = match &item_fn.sig.output { 49 49 ReturnType::Default => quote! { () }, 50 50 ReturnType::Type(_, ty) => quote! { #ty }, 51 51 }; 52 52 53 - let has_lifetime_dependency = 54 - item_fn.sig.inputs.iter().any(|param| match param { 55 - FnArg::Receiver(receiver) => receiver.reference.is_some(), 56 - FnArg::Typed(pat) => has_lifetime_dependency(&pat.ty), 57 - }); 53 + item_fn.sig.output = parse_quote! { -> impl futures_core::Future<LocalWaker, Output = #output_type> }; 58 54 59 - // set outer fn output to ScopedFuture<'_/'static, Output = #output> 60 - item_fn.sig.output = if has_lifetime_dependency { 61 - parse_quote! { -> impl futures_core::ScopedFuture<'_, Output = #output> + '_ } 62 - } else { 63 - parse_quote! { -> impl futures_core::ScopedFuture<'static, Output = #output> } 64 - }; 55 + // let has_lifetime_dependency = 56 + // item_fn.sig.inputs.iter().any(|param| match param { 57 + // FnArg::Receiver(receiver) => receiver.reference.is_some(), 58 + // FnArg::Typed(pat) => has_lifetime_dependency(&pat.ty), 59 + // }); 60 + 61 + // // set outer fn output to ScopedFuture<'_/'static, Output = #output> 62 + // item_fn.sig.output = if has_lifetime_dependency { 63 + // parse_quote! { -> impl futures_core::ScopedFuture<'_, Output = #output> + '_ } 64 + // } else { 65 + // parse_quote! { -> impl futures_core::ScopedFuture<'static, Output = #output> } 66 + // }; 65 67 66 68 item_fn.to_token_stream().into() 67 69 } ··· 72 74 /// Takes async fn that returns anonymous `Future` impl. 73 75 /// Generates fn that returns `UnscopedFutureWrapper` wrapper for the the anonymous `Future` impl. 74 76 /// 75 - /// ```rust 77 + /// ```rust,ignore 76 78 /// fn [original name]<'a, 'b>(a: &'a A, b: &'b B) -> impl ScopedFuture<'a + 'b, Output = T> + 'a + 'b { 77 79 /// async fn [__inner]<'a, 'b>(a: &'a A, b: &'b B) -> T { [body] } // compilers turns this into -> impl Future<Output = T> + 'a + 'b 78 80 /// unsafe { UnscopedFutureWrapper::from_future(__inner()) } ··· 123 125 /// 124 126 /// This generates a modified block of the form: 125 127 /// 126 - /// ```rust 128 + /// ```rust,ignore 127 129 /// { 128 130 /// let output = async { <original block, mapped to convert all `ScopedFuture` to `Future`> }; 129 131 /// unsafe { futures_compat::UnscopedFutureWrapper::from_future(output) } 130 132 /// } 131 133 /// ``` 132 134 #[proc_macro] 133 - pub fn block(input: TokenStream) -> TokenStream { 135 + pub fn async_block(input: TokenStream) -> TokenStream { 134 136 // block is formed { **expr/stmt }, so we need to surround the inputs in {} 135 137 let input = proc_macro2::TokenStream::from(input); 136 138 let block_input = quote! { { #input } }; 137 139 138 140 let mut block = parse2(block_input).expect("Failed to parse as block."); 139 141 140 - ScopedFutureWrappingVisitor.visit_block_mut(&mut block); 142 + BespokeFutureWrappingVisitor.visit_block_mut(&mut block); 141 143 142 144 quote! { 143 145 { 144 146 let output = async #block; 145 - unsafe { futures_compat::UnscopedFutureWrapper::from_future(output) } 147 + unsafe { futures_compat::std_future_to_bespoke(output) } 146 148 } 147 149 } 148 150 .into() ··· 150 152 151 153 /// Determines if typed pattern contains a reference or dependency on a 152 154 /// lifetime (used for deciding between '_ and 'static ScopedFuture). 153 - fn has_lifetime_dependency(ty: &syn::Type) -> bool { 154 - match ty { 155 - syn::Type::Reference(_) => true, 156 - syn::Type::Path(type_path) => { 157 - type_path.path.segments.iter().any(|segment| { 158 - if let syn::PathArguments::AngleBracketed(args) = 159 - &segment.arguments 160 - { 161 - args.args.iter().any(|arg| match arg { 162 - GenericArgument::Type(ty) => { 163 - has_lifetime_dependency(ty) 164 - } 165 - syn::GenericArgument::Lifetime(_) => true, 166 - _ => false, 167 - }) 168 - } else { 169 - false 170 - } 171 - }) 172 - } 173 - syn::Type::Tuple(tuple) => { 174 - tuple.elems.iter().any(has_lifetime_dependency) 175 - } 176 - syn::Type::Slice(slice) => has_lifetime_dependency(&slice.elem), 177 - syn::Type::Array(array) => has_lifetime_dependency(&array.elem), 178 - syn::Type::Ptr(ptr) => has_lifetime_dependency(&ptr.elem), 179 - syn::Type::Group(group) => has_lifetime_dependency(&group.elem), 180 - syn::Type::Paren(paren) => has_lifetime_dependency(&paren.elem), 181 - syn::Type::BareFn(bare_fn) => { 182 - bare_fn 183 - .inputs 184 - .iter() 185 - .any(|input| has_lifetime_dependency(&input.ty)) 186 - || match &bare_fn.output { 187 - ReturnType::Default => false, 188 - ReturnType::Type(_, ty) => has_lifetime_dependency(ty), 189 - } 190 - } 155 + // fn has_lifetime_dependency(ty: &syn::Type) -> bool { 156 + // match ty { 157 + // syn::Type::Reference(_) => true, 158 + // syn::Type::Path(type_path) => { 159 + // type_path.path.segments.iter().any(|segment| { 160 + // if let syn::PathArguments::AngleBracketed(args) = 161 + // &segment.arguments 162 + // { 163 + // args.args.iter().any(|arg| match arg { 164 + // GenericArgument::Type(ty) => { 165 + // has_lifetime_dependency(ty) 166 + // } 167 + // syn::GenericArgument::Lifetime(_) => true, 168 + // _ => false, 169 + // }) 170 + // } else { 171 + // false 172 + // } 173 + // }) 174 + // } 175 + // syn::Type::Tuple(tuple) => { 176 + // tuple.elems.iter().any(has_lifetime_dependency) 177 + // } 178 + // syn::Type::Slice(slice) => has_lifetime_dependency(&slice.elem), 179 + // syn::Type::Array(array) => has_lifetime_dependency(&array.elem), 180 + // syn::Type::Ptr(ptr) => has_lifetime_dependency(&ptr.elem), 181 + // syn::Type::Group(group) => has_lifetime_dependency(&group.elem), 182 + // syn::Type::Paren(paren) => has_lifetime_dependency(&paren.elem), 183 + // syn::Type::BareFn(bare_fn) => { 184 + // bare_fn 185 + // .inputs 186 + // .iter() 187 + // .any(|input| has_lifetime_dependency(&input.ty)) 188 + // || match &bare_fn.output { 189 + // ReturnType::Default => false, 190 + // ReturnType::Type(_, ty) => has_lifetime_dependency(ty), 191 + // } 192 + // } 191 193 192 - _ => false, 193 - } 194 - } 194 + // _ => false, 195 + // } 196 + // } 195 197 196 198 /// Uses the `syn::visit_mut` api to wrap every `.await` expression in 197 199 /// `ScopedFutureWrapper`. 198 - struct ScopedFutureWrappingVisitor; 200 + struct BespokeFutureWrappingVisitor; 199 201 200 - impl VisitMut for ScopedFutureWrappingVisitor { 202 + impl VisitMut for BespokeFutureWrappingVisitor { 201 203 fn visit_expr_mut(&mut self, expr: &mut syn::Expr) { 202 204 if let Expr::Await(ExprAwait { attrs, base, .. }) = expr { 203 205 *expr = syn::parse_quote! { 204 - unsafe { futures_compat::ScopedFutureWrapper::from_scoped(#(#attrs)* #base) }.await 206 + unsafe { futures_compat::bespoke_future_to_std(#(#attrs)* #base) }.await 205 207 }; 206 208 } 207 209
+17
futures-util/src/block_on.rs
··· 1 + use std::{ 2 + pin::{self, Pin}, 3 + task::Poll, 4 + }; 5 + 6 + use crate::{LocalWaker, dummy_guard}; 7 + 8 + pub fn block_on<F: futures_core::Future<LocalWaker>>( 9 + mut f: Pin<&mut F>, 10 + ) -> F::Output { 11 + let dummy_guard = pin::pin!(dummy_guard()); 12 + loop { 13 + if let Poll::Ready(out) = f.as_mut().poll(dummy_guard.as_ref()) { 14 + return out; 15 + } 16 + } 17 + }
+39 -1
futures-util/src/lib.rs
··· 1 - use std::ptr::NonNull; 1 + use std::{pin::Pin, ptr::NonNull, task::Poll}; 2 2 3 3 use futures_core::{Future, Wake}; 4 4 use lifetime_guard::{atomic_guard::AtomicValueGuard, guard::ValueGuard}; 5 5 6 + pub mod block_on; 6 7 pub mod maybe_done; 7 8 8 9 pub type WakePtr = Option<NonNull<dyn Wake>>; ··· 15 16 { 16 17 future 17 18 } 19 + 20 + pub struct PollFn<F, T>(F) 21 + where 22 + F: FnMut(&LocalWaker) -> Poll<T>; 23 + 24 + impl<F, T> futures_core::Future<LocalWaker> for PollFn<F, T> 25 + where 26 + F: FnMut(&LocalWaker) -> Poll<T>, 27 + { 28 + type Output = T; 29 + 30 + fn poll( 31 + self: Pin<&mut Self>, 32 + waker: Pin<&LocalWaker>, 33 + ) -> Poll<Self::Output> { 34 + (unsafe { &mut self.get_unchecked_mut().0 })(&waker) 35 + } 36 + } 37 + 38 + pub fn poll_fn<F, T>(f: F) -> impl futures_core::Future<LocalWaker, Output = T> 39 + where 40 + F: FnMut(&LocalWaker) -> Poll<T>, 41 + { 42 + PollFn(f) 43 + } 44 + 45 + pub struct DummyWaker; 46 + 47 + impl Wake for DummyWaker { 48 + fn wake(&self) { 49 + dbg!("awake!"); 50 + } 51 + } 52 + 53 + pub fn dummy_guard() -> ValueGuard<WakePtr> { 54 + ValueGuard::new(NonNull::new(&mut DummyWaker as *mut dyn Wake)) 55 + }
+7 -20
futures-util/src/maybe_done.rs
··· 15 15 /// 16 16 /// This is created by the [`maybe_done()`] function. 17 17 #[derive(Debug)] 18 - pub enum MaybeDone<Fut: Future<LocalWaker>> { 18 + pub enum MaybeDone<Fut: futures_core::Future<LocalWaker>> { 19 19 /// A not-yet-completed future 20 20 Future(/* #[pin] */ Fut), 21 21 /// The output of the completed future ··· 28 28 impl<Fut: Future<LocalWaker> + Unpin> Unpin for MaybeDone<Fut> {} 29 29 30 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> { 31 + pub fn maybe_done<Fut: futures_core::Future<LocalWaker>>( 32 + future: Fut, 33 + ) -> MaybeDone<Fut> { 49 34 assert_future::<(), _>(MaybeDone::Future(future)) 50 35 } 51 36 ··· 90 75 } 91 76 } 92 77 93 - impl<Fut: Future<LocalWaker>> Future<LocalWaker> for MaybeDone<Fut> { 78 + impl<Fut: Future<LocalWaker>> futures_core::Future<LocalWaker> 79 + for MaybeDone<Fut> 80 + { 94 81 type Output = (); 95 82 96 83 fn poll(
+1
futures/Cargo.toml
··· 9 9 homepage.workspace = true 10 10 11 11 [dependencies] 12 + futures-core = { workspace = true } 12 13 futures-combinators = { workspace = true } 13 14 futures-compat = { workspace = true } 14 15 futures-derive = { workspace = true }
+6 -9
futures/src/lib.rs
··· 1 1 #![no_std] 2 2 3 - pub use futures_combinators; 4 - pub use futures_core; 5 - use futures_core::ScopedFuture; 6 - pub use futures_derive::async_scoped; 7 - pub use futures_util; 3 + use futures_compat::LocalWaker; 4 + use futures_derive::async_function; 8 5 9 6 async fn evil() {} 10 7 11 - #[async_scoped] 8 + #[async_function] 12 9 fn inner(a: i32, b: &i32) -> i32 { 13 10 // evil().await; 14 11 1 15 12 } 16 13 17 - #[async_scoped] 14 + #[async_function] 18 15 fn test(a: i32, b: &i32) -> i32 { 19 - futures_derive::block! { 1 + *b; 2 }.await 16 + futures_derive::async_block! { let _ = 1 + *b; 2 }.await 20 17 } 21 18 22 - fn test2<'a>(a: i32) {} 19 + // fn test2<'a>(a: i32) {}