#![warn(rustdoc::broken_intra_doc_links)]
#![warn(missing_docs)]
#![deny(elided_lifetimes_in_paths)]
#![deny(unsafe_op_in_unsafe_fn)]
#![doc = include_str!("../README.md")]
#![doc(
html_favicon_url = "https://raw.githubusercontent.com/dureuill/nolife/main/assets/nolife-tr.png?raw=true"
)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/dureuill/nolife/main/assets/nolife-tr.png?raw=true"
)]
mod box_scope;
#[cfg(not(miri))]
pub mod counterexamples;
mod raw_scope;
pub mod scope;
#[doc(hidden)]
pub use raw_scope::{FrozenFuture, TimeCapsule};
mod waker;
pub use box_scope::BoxScope;
pub use scope::Scope;
pub use scope::TopScope;
use std::marker::PhantomData;
pub enum Never {}
pub trait Family<'a> {
type Family: 'a;
}
pub struct SingleFamily<T: 'static>(PhantomData<T>);
impl<'a, T: 'static> Family<'a> for SingleFamily<T> {
type Family = T;
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn produce_output() {
let mut scope = BoxScope::<SingleFamily<u32>, _>::new(scope!({
let mut x = 0u32;
loop {
freeze!(&mut x);
x += 1;
}
}));
assert_eq!(scope.enter(|x| *x + 42), 42);
assert_eq!(scope.enter(|x| *x + 42), 43);
scope.enter(|x| *x += 100);
assert_eq!(scope.enter(|x| *x + 42), 145);
}
#[test]
fn produce_output_erased() {
let mut scope = BoxScope::<SingleFamily<u32>>::new_dyn(scope!({
let mut x = 0u32;
loop {
freeze!(&mut x);
x += 1;
}
}));
assert_eq!(scope.enter(|x| *x + 42), 42);
assert_eq!(scope.enter(|x| *x + 42), 43);
scope.enter(|x| *x += 100);
assert_eq!(scope.enter(|x| *x + 42), 145);
}
fn must_panic<F, R>(f: F)
where
F: FnOnce() -> R,
{
assert!(matches!(
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)),
Err(_)
));
}
#[test]
fn panicking_producer() {
must_panic(|| {
BoxScope::<SingleFamily<u32>, _>::new(unsafe {
crate::scope::new_scope(|_time_capsule| {
panic!("panicking producer");
#[allow(unreachable_code)]
async {
loop {}
}
})
})
});
}
#[test]
fn panicking_future() {
let mut scope = BoxScope::<SingleFamily<u32>, _>::new(scope!({ panic!() }));
must_panic(|| scope.enter(|x| println!("{x}")));
must_panic(|| scope.enter(|x| println!("{x}")));
}
#[test]
fn panicking_future_after_once() {
let mut scope = BoxScope::<SingleFamily<u32>, _>::new(scope!({
let mut x = 0u32;
freeze!(&mut x);
panic!()
}));
scope.enter(|x| println!("{x}"));
must_panic(|| scope.enter(|x| println!("{x}")));
must_panic(|| scope.enter(|x| println!("{x}")));
}
#[test]
fn panicking_enter() {
let mut scope = BoxScope::<SingleFamily<u32>, _>::new(scope!({
let mut x = 0u32;
loop {
freeze!(&mut x);
x += 1;
}
}));
scope.enter(|x| assert_eq!(*x, 0));
must_panic(|| scope.enter(|_| panic!()));
scope.enter(|x| assert_eq!(*x, 2));
}
#[test]
fn ref_scope() {
fn scope_with_ref<'scope, 'a: 'scope>(
s: &'a str,
) -> impl TopScope<Family = SingleFamily<usize>> + 'scope {
scope!({ freeze_forever!(&mut s.len()) })
}
let x = "Intel the Beagle".to_string();
let mut scope = BoxScope::<SingleFamily<usize>, _>::new(scope_with_ref(&x));
scope.enter(|x| assert_eq!(*x, 16));
}
#[test]
fn awaiting_in_scope_ready() {
let mut scope = BoxScope::<SingleFamily<u32>>::new_dyn(scope!({
freeze!(&mut 40);
std::future::ready(()).await;
freeze_forever!(&mut 42)
}));
scope.enter(|x| assert_eq!(*x, 40));
scope.enter(|x| assert_eq!(*x, 42));
}
#[test]
fn awaiting_in_scope_panics() {
let mut scope = BoxScope::<SingleFamily<u32>>::new_dyn(scope!({
freeze!(&mut 40);
let () = std::future::pending().await;
freeze_forever!(&mut 42)
}));
scope.enter(|x| assert_eq!(*x, 40));
must_panic(|| scope.enter(|x| assert_eq!(*x, 42)));
}
}