Expand description
§Non-compiling examples
The following examples will not compile, preventing unsoundness.
§Covariant escapes to inner
ⓘ
use nolife::{scope, BoxScope, Family};
struct Covariant<'a> {
x: &'a str,
}
struct CovariantFamily;
impl<'a> Family<'a> for CovariantFamily {
type Family = Covariant<'a>;
}
fn covariant_inner() {
{
let mut scope = BoxScope::<CovariantFamily, _>::new(scope!({
let mut f = Covariant { x: "bbb" };
loop {
freeze!(&mut f);
println!("Called {}", f.x)
}
}));
{
let s = String::from("foodog");
scope.enter(|f| {
f.x = &s;
});
}
}
}
§Covariant escapes to outer
ⓘ
use nolife::{scope, BoxScope, Family};
use std::cell::Cell;
struct Covariant<'a> {
x: &'a str,
}
struct CovariantFamily;
impl<'a> Family<'a> for CovariantFamily {
type Family = Covariant<'a>;
}
fn covariant_outer() {
let output = Cell::new("foo");
{
let mut scope = BoxScope::<CovariantFamily>::new_dyn(scope!({
let mut f = Covariant { x: "bbb" };
loop {
freeze!(&mut f);
println!("Called {}", f.x)
}
}));
{
scope.enter(|f| {
output.set(f.x);
});
}
}
println!("{}", output.get());
}
§Covariant escapes to inner 2
ⓘ
use nolife::{scope, BoxScope, Family};
struct Covariant<'a> {
x: &'a str,
}
struct CovariantFamily;
impl<'a> Family<'a> for CovariantFamily {
type Family = Covariant<'a>;
}
fn box_covariant_inner() {
{
let mut scope = BoxScope::<CovariantFamily, _>::new(scope!({
let x = String::from("aaaaa");
let mut f = Covariant { x: &x };
loop {
freeze!(&mut f);
println!("Called {}", f.x)
}
}));
{
let s = String::from("dangling");
scope.enter(|f| f.x = &s);
}
};
}
§Covariant escapes to outer 2
ⓘ
use nolife::{scope, BoxScope, Family};
use std::cell::Cell;
struct Covariant<'a> {
x: &'a str,
}
struct CovariantFamily;
impl<'a> Family<'a> for CovariantFamily {
type Family = Covariant<'a>;
}
fn box_covariant_outer() {
let outer = Cell::new("foo");
{
let mut scope = BoxScope::<CovariantFamily, _>::new(scope!({
let x = String::from("aaaaa");
let mut f = Covariant { x: &x };
loop {
freeze!(&mut f);
println!("Called {}", f.x)
}
}));
let inner = scope.enter(|f| f.x);
outer.set(inner);
};
println!("{}", outer.get());
}
§Covariant with Drop
ⓘ
use nolife::{scope, BoxScope, Family};
struct CovariantDrop<'a> {
x: &'a str,
}
impl<'a> Drop for CovariantDrop<'a> {
fn drop(&mut self) {
println!("Dropping {}", self.x)
}
}
struct CovariantDropFamily;
impl<'a> Family<'a> for CovariantDropFamily {
type Family = CovariantDrop<'a>;
}
fn covariant_drop() {
{
let mut scope = BoxScope::<CovariantDropFamily, _>::new(scope!({
let mut f = CovariantDrop { x: "inner" };
loop {
println!("Called {}", f.x);
freeze!(&mut f);
}
}));
let outer = String::from("outer");
{
scope.enter(|f| {
f.x = &outer;
});
}
}
}
§Contravariant example
ⓘ
use std::cell::Cell;
struct Contravariant<'a> {
f: Box<dyn FnMut(&'a mut str) + 'a>,
}
struct ContravariantFamily;
impl<'a> nolife::Family<'a> for ContravariantFamily {
type Family = Contravariant<'a>;
}
fn contravariant() {
let outer: Cell<&str> = Cell::new("toto");
{
let mut scope = nolife::BoxScope::<ContravariantFamily, _>::new(nolife::scope!({
loop {
let mut x = String::from("inner");
let mut f = Contravariant {
f: Box::new(|_| {}),
};
freeze!(&mut f);
(f.f)(&mut x);
}
}));
scope.enter(|f| {
f.f = Box::new(|inner| outer.set(inner));
});
}
println!("{}", outer.get());
}
§Covariant coming from a previous scope
ⓘ
use nolife::{scope, BoxScope, Family};
struct Covariant<'a> {
x: &'a str,
}
struct CovariantFamily;
impl<'a> Family<'a> for CovariantFamily {
type Family = Covariant<'a>;
}
fn covariant_inner() {
{
let mut scope = BoxScope::<CovariantFamily>::new_dyn(scope!({
let mut f = Covariant { x: "bbb" };
loop {
freeze!(&mut f);
println!("Called {}", f.x)
}
}));
{
let s = String::from("foodog");
{
scope.enter(|f| {
f.x = &s;
});
}
}
scope.enter(|_f| ());
}
}
§Signature of enter
is not sound, #7 https://github.com/dureuill/nolife/issues/7
Example lifted as-is from @steffahn
ⓘ
use nolife::{BoxScope, Family, TimeCapsule, scope};
struct Foo<'a> {
s: String,
r: Option<&'a mut String>,
}
struct FooFamily;
impl<'a> Family<'a> for FooFamily {
type Family = Foo<'a>;
}
fn storing_own_reference() {
{
let mut scope: BoxScope<FooFamily, _> = BoxScope::new(scope!({
let mut f = Foo {
s: String::from("Hello World!"),
r: None,
};
freeze_forever!(&mut f)
}));
scope.enter(|foo| {
foo.r = Some(&mut foo.s);
});
scope.enter(|foo| {
let alias1: &mut String = &mut foo.s;
let alias2: &mut String = foo.r.as_deref_mut().unwrap(); // miri will complain here already
// two aliasing mutable references!!
let s: &str = alias1;
let owner: String = std::mem::take(alias2);
println!("Now it exists: {s}");
drop(owner);
println!("Now it's gone: {s}");
})
}
}
§Recursion is not allowed
ⓘ
use nolife::{scope, SingleFamily, TopScope};
fn recursive_sub_scope() {
fn some_scope(x: u32) -> impl TopScope<Family = SingleFamily<u32>> {
scope!({
if x == 0 {
freeze_forever!(&mut 0)
} else {
sub_scope!(some_scope(x - 1));
freeze_forever!(&mut 0)
}
})
}
}
§Attempting to save the frozen future in an async block
ⓘ
use nolife::{scope, SingleFamily, TopScope};
fn forcing_inner_async() {
fn some_scope(x: u32) -> impl TopScope<Family = SingleFamily<u32>> {
scope!({
let fut = async {
freeze!(&mut 0);
};
// poll future
// bang!
panic!()
})
}
}
# Dropping a borrowed input to a scope.
ⓘ
use nolife::{scope, BoxScope, SingleFamily, TopScope};
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));
drop(x);
scope.enter(|x| assert_eq!(*x, 16));
}
# Dropping a borrowed input to a scope, erased version
ⓘ
use nolife::{scope, BoxScope, SingleFamily, TopScope};
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_dyn(scope_with_ref(&x));
drop(x);
scope.enter(|x| assert_eq!(*x, 16));
}