use async_io::block_on; use std::{ future::Future, pin::Pin, task::{Context, Poll, Waker}, time::{Duration, Instant}, }; #[test] fn doesnt_poll_after_ready() { #[derive(Default)] struct Bomb { returned_ready: bool, } impl Future for Bomb { type Output = (); fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { if self.returned_ready { panic!("Future was polled again after returning Poll::Ready"); } else { self.returned_ready = true; Poll::Ready(()) } } } block_on(Bomb::default()) } #[test] fn recursive_wakers_are_different() { struct Outer; impl Future for Outer { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let outer_waker = cx.waker(); block_on(Inner { outer_waker }); Poll::Ready(()) } } struct Inner<'a> { pub outer_waker: &'a Waker, } impl Future for Inner<'_> { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let inner_waker = cx.waker(); assert!(!inner_waker.will_wake(self.outer_waker)); Poll::Ready(()) } } block_on(Outer); } #[test] fn inner_cannot_wake_outer() { #[derive(Default)] struct Outer { elapsed: Option, } impl Future for Outer { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if let Some(elapsed) = self.elapsed { assert!(elapsed.elapsed() >= Duration::from_secs(1)); Poll::Ready(()) } else { let outer_waker = cx.waker().clone(); block_on(Inner); std::thread::spawn(|| { std::thread::sleep(Duration::from_secs(1)); outer_waker.wake(); }); self.elapsed = Some(Instant::now()); Poll::Pending } } } struct Inner; impl Future for Inner { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let inner_waker = cx.waker(); inner_waker.wake_by_ref(); Poll::Ready(()) } } block_on(Outer::default()); } #[test] fn outer_cannot_wake_inner() { struct Outer; impl Future for Outer { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let outer_waker = cx.waker(); outer_waker.wake_by_ref(); block_on(Inner::default()); Poll::Ready(()) } } #[derive(Default)] struct Inner { elapsed: Option, } impl Future for Inner { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if let Some(elapsed) = self.elapsed { assert!(elapsed.elapsed() >= Duration::from_secs(1)); Poll::Ready(()) } else { let inner_waker = cx.waker().clone(); std::thread::spawn(|| { std::thread::sleep(Duration::from_secs(1)); inner_waker.wake(); }); self.elapsed = Some(Instant::now()); Poll::Pending } } } block_on(Outer); } #[test] fn first_cannot_wake_second() { struct First; impl Future for First { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let first_waker = cx.waker(); first_waker.wake_by_ref(); Poll::Ready(()) } } #[derive(Default)] struct Second { elapsed: Option, } impl Future for Second { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if let Some(elapsed) = self.elapsed { assert!(elapsed.elapsed() >= Duration::from_secs(1)); Poll::Ready(()) } else { let second_waker = cx.waker().clone(); std::thread::spawn(|| { std::thread::sleep(Duration::from_secs(1)); second_waker.wake(); }); self.elapsed = Some(Instant::now()); Poll::Pending } } } block_on(First); block_on(Second::default()); }