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
#[macro_export]
/// Creates an asynchronous state machine with the given visibility, name and
/// state definitions.
macro_rules! state_machine {
    {
        $(#[$attr:meta])*
        $vis:vis $name:ident $(($($iname:ident: $itype:ty),+ $(,)?))? $({
            $(
                $(#[$vattr:meta])*
                $vname:ident: $vtype:ty = $vinit:expr
            ),+ $(,)?
        })? = $init:ident($($arg:expr),*);

        $(
            $(#[$fattr:meta])*
            $state:ident ($ctx:ident $(, $pname:ident: $ptype:ty)* $(,)?) $([$($vref:ident),*])? $(-> $fret:ty)? $body:block
        )*
    } => {
        #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
        /// State type used internally by the state machine. Auto-generated by the `state_machine!` macro.
        $vis enum State {
            $(
                #[allow(non_camel_case_types)]
                #[allow(missing_docs)]
                $state($($ptype),*),
            )*
        }

        #[derive(Clone)]
        struct Vars {
            $(
                $(
                    $(#[$vattr])*
                    $vname: $vtype,
                )+
            )?
        }

        impl Vars {
            $(
                fn $state(&mut self, $ctx: $crate::rtos::Context, $($pname: $ptype),*) $(-> $fret)? {
                    $(
                        $(
                            let $vref: &mut _ = &mut self.$vref;
                        )*
                    )?
                    $body
                }
            )*
        }

        struct Data {
            state: State,
            #[allow(dead_code)]
            promise: $crate::rtos::Promise<Vars>,
            ctxw: $crate::rtos::ContextWrapper,
        }

        $(#[$attr])*
        $vis struct $name($crate::rtos::Mutex<Data>);

        impl $name {
            pub fn new($($($iname: $itype),+)?) -> Self {
                let (promise, resolve) = $crate::rtos::Promise::new();
                $(
                    $(
                        let $vname = $vinit;
                    )+
                )?
                resolve(Vars {
                    $(
                        $(
                            $vname,
                        )+
                    )?
                });
                let state = State::$init($($arg),*);
                let r = Self($crate::rtos::Mutex::new(Data {
                    state: ::core::clone::Clone::clone(&state),
                    promise,
                    ctxw: $crate::rtos::ContextWrapper::new(),
                }));
                $crate::machine::StateMachine::transition(&r, state);
                r
            }

            $(
                $(#[$fattr])*
                pub fn $state(&self, $($pname: $ptype),*) -> $crate::rtos::Promise $(<$fret>)? {
                    let mut lock = self.0.lock();
                    let ctx = lock.ctxw.replace();
                    lock.state = State::$state($(::core::clone::Clone::clone($pname)),*);
                    let promise = lock.promise.then(move |vars: &Vars| {
                        let mut vars = ::core::clone::Clone::clone(vars);
                        let r = vars.$state(ctx, $($pname),*);
                        (vars, r)
                    });
                    lock.promise = promise.then(|(vars, _)| ::core::clone::Clone::clone(vars));
                    promise.then(|(_, r)| ::core::clone::Clone::clone(r))
                }
            )*
        }

        impl $crate::machine::StateMachine for $name {
            type State = State;

            #[inline]
            fn state(&self) -> State {
                self.0.lock().state.clone()
            }

            #[inline]
            fn transition(&self, state: State) {
                match state {
                    $(
                        State::$state($($pname),*) => self.$state($($pname),*),
                    )*
                };
            }
        }
    };
}