use crate::StackFuture;
use core::task::Poll;
use futures::channel::mpsc;
use futures::executor::block_on;
use futures::pin_mut;
use futures::Future;
use futures::SinkExt;
use futures::Stream;
use futures::StreamExt;
use std::sync::Arc;
use std::task::Context;
use std::task::Wake;
use std::thread;
#[test]
fn create_and_run() {
let f = StackFuture::<'_, _, 8>::from(async { 5 });
assert_eq!(block_on(f), 5);
}
enum Never {}
struct SuspendPoint;
impl Future for SuspendPoint {
type Output = Never;
fn poll(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
Poll::Pending
}
}
struct Waker;
impl Wake for Waker {
fn wake(self: std::sync::Arc<Self>) {
unimplemented!()
}
}
#[test]
fn destructor_runs() {
let mut destructed = false;
let _poll_result = {
let f = async {
struct DropMe<'a>(&'a mut bool);
impl Drop for DropMe<'_> {
fn drop(&mut self) {
*self.0 = true;
}
}
let _ = DropMe(&mut destructed);
SuspendPoint.await
};
let f = StackFuture::<'_, _, 32>::from(f);
let waker = Arc::new(Waker).into();
let mut cx = Context::from_waker(&waker);
pin_mut!(f);
f.poll(&mut cx)
};
assert!(destructed);
}
#[test]
fn test_size_failure() {
async fn fill_buf(buf: &mut [u8]) {
buf[0] = 42;
}
let f = async {
let mut buf = [0u8; 256];
fill_buf(&mut buf).await;
buf[0]
};
match StackFuture::<_, 4>::try_from(f) {
Ok(_) => panic!("conversion to StackFuture should not have succeeded"),
Err(e) => assert!(e.insufficient_space()),
}
}
#[test]
fn test_alignment() {
#[repr(align(8))]
struct BigAlignment(u32);
impl Future for BigAlignment {
type Output = Never;
fn poll(self: std::pin::Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Pending
}
}
let mut f = StackFuture::<'_, _, 1016>::from(BigAlignment(42));
assert!(is_aligned(f.as_mut_ptr::<BigAlignment>(), 8));
}
#[test]
fn test_alignment_failure() {
#[repr(align(256))]
struct BigAlignment(u32);
impl Future for BigAlignment {
type Output = Never;
fn poll(self: std::pin::Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Pending
}
}
match StackFuture::<'_, _, 1016>::try_from(BigAlignment(42)) {
Ok(_) => panic!("conversion to StackFuture should not have succeeded"),
Err(e) => assert!(e.alignment_too_small()),
}
}
#[cfg(feature = "alloc")]
#[test]
fn test_boxed_alignment() {
#[repr(align(256))]
struct BigAlignment(u32);
impl Future for BigAlignment {
type Output = Never;
fn poll(self: std::pin::Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Pending
}
}
StackFuture::<'_, _, 1016>::from_or_box(BigAlignment(42));
}
fn is_aligned<T>(ptr: *mut T, alignment: usize) -> bool {
(ptr as usize) & (alignment - 1) == 0
}
#[test]
fn stress_drop_sender() {
const ITER: usize = if cfg!(miri) { 10 } else { 10000 };
fn list() -> impl Stream<Item = i32> {
let (tx, rx) = mpsc::channel(1);
thread::spawn(move || {
block_on(send_one_two_three(tx));
});
rx
}
for _ in 0..ITER {
let v: Vec<_> = block_on(list().collect());
assert_eq!(v, vec![1, 2, 3]);
}
}
fn send_one_two_three(mut tx: mpsc::Sender<i32>) -> StackFuture<'static, (), 512> {
StackFuture::from(async move {
for i in 1..=3 {
tx.send(i).await.unwrap();
}
})
}
#[test]
fn try_from() {
let big_future = StackFuture::<_, 1000>::from(async {});
match StackFuture::<_, 10>::try_from(big_future) {
Ok(_) => panic!("try_from should not have succeeded"),
Err(big_future) => {
assert!(StackFuture::<_, 1500>::try_from(big_future.into_inner()).is_ok())
}
};
}
#[cfg(feature = "alloc")]
#[test]
fn from_or_box() {
let big_future = StackFuture::<_, 1000>::from(async {});
StackFuture::<_, 32>::from_or_box(big_future);
}