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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#![cfg_attr(feature = "nightly",
    cfg_attr(all(), doc = include_str!("../README.md")),
)]
#![allow(nonstandard_style)]
#![no_std]

/// Shorthand for `with_state(()).try_eval(|_| …)`.
#[must_use = "\
    `try_eval()` is lazy and does nothing: you need to call `.finally()`\
"]
pub
fn try_eval<R, F> (
    f: F,
) -> state_machine::RunnerWithTryEval<(), impl FnOnce(&mut ()) -> R>
where
    F : FnOnce() -> R,
{
    with_state(())
        .try_eval(move |&mut ()| f())
}

/// Main entrypoint of the crate / of the builder pattern.
///
/// See the [`crate`] docs for more info.
#[must_use = "You need to call `.try_eval()`"]
pub
const
fn with_state<State> (state: State)
  -> state_machine::Runner<State>
{
    state_machine::Runner { state }
}

pub
mod state_machine {
    pub
    struct Runner<State> {
        pub(in super)
        state: State,
    }

    pub
    struct RunnerWithTryEval<State, try_eval> {
        state: State,
        try_eval: try_eval,
    }

    impl<State> Runner<State> {
        #[must_use = "\
            `.try_eval()` is lazy and does nothing: you need to call `.finally()`\
        "]
        pub
        fn try_eval<R, try_eval> (
            self: Runner<State>,
            __: try_eval,
        ) -> RunnerWithTryEval<State, try_eval>
        where
            try_eval: FnOnce(&'_ mut State) -> R,
        {
            let Runner { state } = self;
            RunnerWithTryEval {
                state,
                try_eval: __,
            }
        }

        #[doc(hidden)] pub
        fn finally<R, F> (
            self: Runner<State>,
            _: F,
        ) -> R
        where
            Self : __::missing_try_eval<F>,
        {
            <Self as __::missing_try_eval<F>>::unreachable()
        }
    }

    mod __ {
        pub
        trait missing_try_eval<F> {
            fn unreachable() -> !;
        }
    }

    impl<State, try_eval> RunnerWithTryEval<State, try_eval> {
        pub
        fn finally<R, finally> (
            self: RunnerWithTryEval<State, try_eval>,
            __: finally,
        ) -> R
        where
            try_eval : FnOnce(&'_ mut State) -> R,
            finally : FnOnce(State),
        {
            use ::core::mem::ManuallyDrop as MD;

            struct WithDrop<State, Finally>
            where
                Finally : FnOnce(State),
            {
                state: MD<State>,
                finally: MD<Finally>,
            }

            impl<State, Finally> Drop for WithDrop<State, Finally>
            where
                Finally : FnOnce(State),
            {
                fn drop (self: &'_ mut Self)
                {
                    unsafe {
                        let state = MD::take(&mut self.state);
                        let finally = MD::take(&mut self.finally);
                        let () = finally(state);
                    }
                }
            }

            let RunnerWithTryEval { state, try_eval } = self;
            let ref mut state_with_drop = WithDrop {
                state: MD::new(state),
                finally: MD::new(__),
            };
            try_eval(&mut state_with_drop.state)
        }
    }
}

#[cfg(all(doc, feature = "nightly"))]
#[cfg_attr(all(doc, feature = "nightly"),
    cfg_attr(all(), doc = include_str!("compile_fail_tests.md")),
)]
mod compile_fail_tests {}