1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
Creates a generator on the stack.

This macro is deprecated. Use [`let_gen!`] or [`let_gen_using!`] instead.

[`let_gen!`]: stack/macro.let_gen.html
[`let_gen_using!`]: stack/macro.let_gen_using.html
*/
#[macro_export]
#[deprecated = "Use `let_gen_using!()` instead."]
macro_rules! generator_mut {
    ($name:ident, $producer:expr $(,)?) => {
        $crate::stack::let_gen_using!($name, $producer);
    };
}

/**
Creates a generator on the stack unsafely.

This macro is deprecated. Use [`let_gen!`] or [`let_gen_using!`] instead.

[`let_gen!`]: stack/macro.let_gen.html
[`let_gen_using!`]: stack/macro.let_gen_using.html
*/
#[macro_export]
#[deprecated = "Use `let_gen_using!()` instead."]
macro_rules! unsafe_create_generator {
    ($name:ident, $producer:expr $(,)?) => {
        let mut generator_state = $crate::stack::Shelf::new();
        #[allow(unused_mut)]
        let mut $name =
            unsafe { $crate::stack::Gen::new(&mut generator_state, $producer) };
    };
}

#[cfg(test)]
mod tests {
    use crate::{
        ops::GeneratorState,
        stack::{Co, Gen, Shelf},
    };

    /// This test proves that `Gen::new` is actually unsafe.
    #[test]
    #[ignore = "compile-only test"]
    fn unsafety() {
        async fn shenanigans(co: Co<'_, i32>) -> Co<'_, i32> {
            co
        }

        let mut shelf = Shelf::new();
        let mut gen = unsafe { Gen::new(&mut shelf, shenanigans) };

        // Get the `co` out of the generator (don't try this at home).
        let escaped_co = match gen.resume() {
            GeneratorState::Yielded(_) => panic!(),
            GeneratorState::Complete(co) => co,
        };
        // Drop the generator. This drops the airlock (inside the state), but `co` still
        // holds a reference to the airlock.
        drop(gen);
        // Now we're able to use an invalidated reference.
        let _ = escaped_co.yield_(10);
    }
}

#[allow(dead_code)]
mod doctests {
    /**
    ```compile_fail
    use genawaiter::{stack::{let_gen_using, Co}, Generator};

    async fn producer(co: Co<'_, i32>) {}

    fn create_generator() -> impl Generator {
        let_gen_using!(gen, producer);
        gen
    }
    ```
    */
    fn generator_cannot_escape() {}

    /**
    This test is exactly the same as above, but doesn't trigger the failure.

    ```
    use genawaiter::{stack::{let_gen_using, Co}, Generator};

    async fn producer(co: Co<'_, i32>) {}

    fn create_generator() { // -> impl Generator {
        let_gen_using!(gen, producer);
        // gen
    }
    ```
    */
    fn generator_cannot_escape_baseline() {}
}