From 1e6df51bd1dfbfadaec9f0a3d55f4d6fbb4538c3 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 May 2023 20:20:37 +0200 Subject: [PATCH] test --- library/core/src/future/future.rs | 32 +++++++++ library/core/src/future/map.rs | 37 ++++++++++ library/core/src/future/mod.rs | 4 ++ library/core/tests/future.rs | 113 +++--------------------------- library/core/tests/lib.rs | 10 +-- 5 files changed, 87 insertions(+), 109 deletions(-) create mode 100644 library/core/src/future/map.rs diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 8c7111cb3ff0b..41e8e71d83a94 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -1,5 +1,6 @@ #![stable(feature = "futures_api", since = "1.36.0")] +use crate::future::Map; use crate::marker::Unpin; use crate::ops; use crate::pin::Pin; @@ -103,6 +104,37 @@ pub trait Future { #[lang = "poll"] #[stable(feature = "futures_api", since = "1.36.0")] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; + + /// Map this future's output to a different type, returning a new future of + /// the resulting type. + /// + /// This function is similar to [`Option::map`] or [`Iterator::map`] where + /// it will change the type of the underlying future. This is useful to + /// chain along a computation once a future has been resolved. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it, similar to the existing `map` methods in the + /// standard library. + /// + /// # Examples + /// + /// ``` + /// #![feature(future_map)] + /// use core::future::Future; + /// # async fn f() { + /// let future = async { 1 }; + /// let new_future = future.map(|x| x + 3); + /// assert_eq!(new_future.await, 4); + /// # } + /// ``` + #[unstable(feature = "future_map", issue = "none")] + fn map(self, f: F) -> Map + where + F: FnOnce(Self::Output) -> U, + Self: Sized, + { + Map::new(self, f) + } } #[stable(feature = "futures_api", since = "1.36.0")] diff --git a/library/core/src/future/map.rs b/library/core/src/future/map.rs new file mode 100644 index 0000000000000..589f0324bf5ea --- /dev/null +++ b/library/core/src/future/map.rs @@ -0,0 +1,37 @@ +#![allow(unused)] + +use crate::fmt; +use crate::future::Future; +use crate::pin::Pin; +use crate::task::{Context, Poll}; + +/// A [`Future`] that maps the output of a wrapped [`Future`]. +/// +/// Returned by [`Future::map`]. +#[unstable(feature = "future_map", issue = "none")] +pub struct Map { + future: Option, + f: Option, +} + +impl Map { + pub(crate) fn new(future: Fut, f: F) -> Self { + Self { future: Some(future), f: Some(f) } + } +} + +#[unstable(feature = "future_map", issue = "none")] +impl fmt::Debug for Map { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Map").field("future", &self.future).finish() + } +} + +#[unstable(feature = "future_map", issue = "none")] +impl U, U> Future for Map { + type Output = U; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Poll::Pending + } +} diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 7a8d0cacdece5..0301487017fef 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -15,6 +15,7 @@ use crate::task::Context; mod future; mod into_future; mod join; +mod map; mod pending; mod poll_fn; mod ready; @@ -36,6 +37,9 @@ pub use ready::{ready, Ready}; #[stable(feature = "future_poll_fn", since = "1.64.0")] pub use poll_fn::{poll_fn, PollFn}; +#[unstable(feature = "future_map", issue = "none")] +pub use map::Map; + /// This type is needed because: /// /// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs index 74b6f74e4013c..e2ed99cec2df6 100644 --- a/library/core/tests/future.rs +++ b/library/core/tests/future.rs @@ -1,105 +1,9 @@ -use std::future::{join, Future}; -use std::pin::Pin; +use std::future::Future; use std::sync::Arc; use std::task::{Context, Poll, Wake}; use std::thread; -struct PollN { - val: usize, - polled: usize, - num: usize, -} - -impl Future for PollN { - type Output = usize; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.polled += 1; - - if self.polled == self.num { - return Poll::Ready(self.val); - } - - cx.waker().wake_by_ref(); - Poll::Pending - } -} - -fn poll_n(val: usize, num: usize) -> PollN { - PollN { val, num, polled: 0 } -} - -#[test] -#[cfg_attr(miri, ignore)] // self-referential generators do not work with Miri's aliasing checks -fn test_join() { - block_on(async move { - let x = join!(async { 0 }).await; - assert_eq!(x, 0); - - let x = join!(async { 0 }, async { 1 }).await; - assert_eq!(x, (0, 1)); - - let x = join!(async { 0 }, async { 1 }, async { 2 }).await; - assert_eq!(x, (0, 1, 2)); - - let x = join!( - poll_n(0, 1), - poll_n(1, 5), - poll_n(2, 2), - poll_n(3, 1), - poll_n(4, 2), - poll_n(5, 3), - poll_n(6, 4), - poll_n(7, 1) - ) - .await; - assert_eq!(x, (0, 1, 2, 3, 4, 5, 6, 7)); - - let y = String::new(); - let x = join!(async { - println!("{}", &y); - 1 - }) - .await; - assert_eq!(x, 1); - }); -} - -/// Tests that `join!(…)` behaves "like a function": evaluating its arguments -/// before applying any of its own logic. -/// -/// _e.g._, `join!(async_fn(&borrowed), …)` does not consume `borrowed`; -/// and `join!(opt_fut?, …)` does let that `?` refer to the callsite scope. -mod test_join_function_like_value_arg_semantics { - use super::*; - - async fn async_fn(_: impl Sized) {} - - // no need to _run_ this test, just to compile it. - fn _join_does_not_unnecessarily_move_mentioned_bindings() { - let not_copy = vec![()]; - let _ = join!(async_fn(¬_copy)); // should not move `not_copy` - let _ = ¬_copy; // OK - } - - #[test] - fn join_lets_control_flow_effects_such_as_try_flow_through() { - let maybe_fut = None; - if false { - *&mut { maybe_fut } = Some(async {}); - loop {} - } - assert!(Option::is_none(&try { join!(maybe_fut?, async { unreachable!() }) })); - } - - #[test] - fn join_is_able_to_handle_temporaries() { - let _ = join!(async_fn(&String::from("temporary"))); - let () = block_on(join!(async_fn(&String::from("temporary")))); - } -} - -fn block_on(fut: impl Future) { +fn block_on(fut: F) -> F::Output { struct Waker; impl Wake for Waker { fn wake(self: Arc) { @@ -113,16 +17,15 @@ fn block_on(fut: impl Future) { loop { match fut.as_mut().poll(&mut cx) { - Poll::Ready(_) => break, + Poll::Ready(value) => break value, Poll::Pending => thread::park(), } } } -// just tests by whether or not this compiles -fn _pending_impl_all_auto_traits() { - use std::panic::{RefUnwindSafe, UnwindSafe}; - fn all_auto_traits() {} - - all_auto_traits::>(); +#[test] +fn test_map() { + let future = async { 1 }; + let future = future.map(|x| x + 3); + assert_eq!(block_on(future), 4); } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 84859a54c2604..52852f82c068c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -36,6 +36,7 @@ #![feature(fmt_internals)] #![feature(float_minimum_maximum)] #![feature(future_join)] +#![feature(future_map)] #![feature(generic_assert_internals)] #![feature(array_try_from_fn)] #![feature(hasher_prefixfree_extras)] @@ -113,9 +114,9 @@ #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] -extern crate test; +//extern crate test; -mod alloc; +/*mod alloc; mod any; mod array; mod ascii; @@ -128,9 +129,9 @@ mod clone; mod cmp; mod const_ptr; mod convert; -mod fmt; +mod fmt;*/ mod future; -mod hash; +/*mod hash; mod intrinsics; mod iter; mod lazy; @@ -170,3 +171,4 @@ pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); rand::SeedableRng::from_seed(seed) } +*/