pub use crate::sync::{boxed::GenBoxed, engine::Co, generator::Gen};
#[cfg(feature = "proc_macro")]
pub use genawaiter_macro::sync_gen as gen;
#[cfg(feature = "proc_macro")]
pub use genawaiter_proc_macro::sync_producer_fn as producer_fn;
mod boxed;
mod engine;
mod generator;
mod iterator;
#[cfg(feature = "futures03")]
mod stream;
#[cfg(feature = "nightly")]
#[cfg(test)]
mod nightly_tests;
#[cfg(test)]
mod tests {
use crate::{
sync::{Co, Gen},
testing::{DummyFuture, SlowFuture},
GeneratorState,
};
use futures::executor::block_on;
use std::{
cell::{Cell, RefCell},
future::Future,
};
async fn simple_producer(co: Co<i32>) -> &'static str {
co.yield_(10).await;
"done"
}
#[test]
fn function() {
let mut gen = Gen::new(simple_producer);
assert_eq!(gen.resume(), GeneratorState::Yielded(10));
assert_eq!(gen.resume(), GeneratorState::Complete("done"));
}
#[test]
fn simple_closure() {
async fn gen(i: i32, co: Co<i32>) -> &'static str {
co.yield_(i * 2).await;
"done"
}
let mut gen = Gen::new(|co| gen(5, co));
assert_eq!(gen.resume(), GeneratorState::Yielded(10));
assert_eq!(gen.resume(), GeneratorState::Complete("done"));
}
#[test]
fn resume_args() {
async fn gen(resumes: &RefCell<Vec<&str>>, co: Co<i32, &'static str>) {
let resume_arg = co.yield_(10).await;
resumes.borrow_mut().push(resume_arg);
let resume_arg = co.yield_(20).await;
resumes.borrow_mut().push(resume_arg);
}
let resumes = RefCell::new(Vec::new());
let mut gen = Gen::new(|co| gen(&resumes, co));
assert_eq!(*resumes.borrow(), &[] as &[&str]);
assert_eq!(gen.resume_with("ignored"), GeneratorState::Yielded(10));
assert_eq!(*resumes.borrow(), &[] as &[&str]);
assert_eq!(gen.resume_with("abc"), GeneratorState::Yielded(20));
assert_eq!(*resumes.borrow(), &["abc"]);
assert_eq!(gen.resume_with("def"), GeneratorState::Complete(()));
assert_eq!(*resumes.borrow(), &["abc", "def"]);
}
#[test]
fn async_resume() {
async fn produce(co: Co<i32>) {
SlowFuture::new().await;
co.yield_(10).await;
SlowFuture::new().await;
co.yield_(20).await;
}
async fn run_test() {
let mut gen = Gen::new(produce);
let x = gen.async_resume().await;
assert_eq!(x, GeneratorState::Yielded(10));
let x = gen.async_resume().await;
assert_eq!(x, GeneratorState::Yielded(20));
let x = gen.async_resume().await;
assert_eq!(x, GeneratorState::Complete(()));
}
block_on(run_test());
}
#[test]
#[should_panic(expected = "non-async method")]
fn forbidden_await_helpful_message() {
async fn wrong(_: Co<i32>) {
DummyFuture.await;
}
let mut gen = Gen::new(wrong);
gen.resume();
}
#[test]
#[should_panic(expected = "Co::yield_")]
fn multiple_yield_helpful_message() {
async fn wrong(co: Co<i32>) {
let _ = co.yield_(10);
let _ = co.yield_(20);
}
let mut gen = Gen::new(wrong);
gen.resume();
}
#[test]
#[should_panic = "should have been dropped by now"]
fn escaped_co_helpful_message() {
async fn shenanigans(co: Co<i32>) -> Co<i32> {
co
}
let mut gen = Gen::new(shenanigans);
let escaped_co = match gen.resume() {
GeneratorState::Yielded(_) => panic!(),
GeneratorState::Complete(co) => co,
};
let _ = escaped_co.yield_(10);
}
#[test]
fn gen_is_movable() {
#[inline(never)]
async fn produce(addrs: &mut Vec<*const i32>, co: Co<i32>) -> &'static str {
let sentinel: Cell<i32> = Cell::new(0x8001);
let sentinel_ref: &Cell<i32> = &sentinel;
assert_eq!(sentinel.get(), 0x8001);
sentinel_ref.set(0x8002);
assert_eq!(sentinel.get(), 0x8002);
addrs.push(sentinel.as_ptr());
co.yield_(10).await;
assert_eq!(sentinel.get(), 0x8002);
sentinel_ref.set(0x8003);
assert_eq!(sentinel.get(), 0x8003);
addrs.push(sentinel.as_ptr());
co.yield_(20).await;
assert_eq!(sentinel.get(), 0x8003);
sentinel_ref.set(0x8004);
assert_eq!(sentinel.get(), 0x8004);
addrs.push(sentinel.as_ptr());
"done"
}
fn create_generator(
addrs: &mut Vec<*const i32>,
) -> Gen<i32, (), impl Future<Output = &'static str> + '_> {
let mut gen = Gen::new(move |co| produce(addrs, co));
assert_eq!(gen.resume(), GeneratorState::Yielded(10));
gen
}
let mut addrs = Vec::new();
let mut gen = create_generator(&mut addrs);
assert_eq!(gen.resume(), GeneratorState::Yielded(20));
assert_eq!(gen.resume(), GeneratorState::Complete("done"));
drop(gen);
assert!(addrs.iter().all(|&p| p == addrs[0]));
}
}