diff options
-rw-r--r-- | lib/stdlib/doc/src/gen_statem.xml | 23 | ||||
-rw-r--r-- | lib/stdlib/src/gen_statem.erl | 39 | ||||
-rw-r--r-- | lib/stdlib/test/gen_statem_SUITE.erl | 24 |
3 files changed, 67 insertions, 19 deletions
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index aeab09615c..5fbedb12f8 100644 --- a/lib/stdlib/doc/src/gen_statem.xml +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -535,6 +535,13 @@ erlang:'!' -----> Module:StateName/5 <desc> <taglist> <tag> + <c>{stop,<anno>Reason</anno>}</c> + </tag> + <item>The same as + <c>{stop,<anno>Reason</anno>,[],StateData}</c> + but keeps the old <c>StateData</c>. + </item> + <tag> <c>{stop,<anno>Reason</anno>,<anno>NewStateData</anno>}</c> </tag> <item>The same as @@ -553,6 +560,19 @@ erlang:'!' -----> Module:StateName/5 </item> <tag> <c> + {next_state,<anno>StateOps</anno>} + </c> + </tag> + <item>The same as + <c> + {next_state,State,StateData,<anno>StateOps</anno>} + </c>but keeps the old <c>State</c> and <c>StateData</c>. + Believe it or not, but this one has actually + been proven useful to <c>throw/1</c> from deep down + in the state logic. + </item> + <tag> + <c> {next_state,<anno>NewState</anno>,<anno>NewStateData</anno>} </c> </tag> @@ -805,6 +825,7 @@ erlang:'!' -----> Module:StateName/5 </func> <func> + <name name="reply" arity="1" /> <name name="reply" arity="2" /> <fsummary>Send a reply to a client</fsummary> <desc> @@ -820,6 +841,8 @@ erlang:'!' -----> Module:StateName/5 <c>{call,<anno>Client</anno>}</c> </seealso> argument to the <seealso marker="#state_function">state function</seealso>. + <c><anno>Client</anno></c> and <c><anno>Reply</anno></c> + an also be specified using <c><anno>ReplyOperation</anno></c>. </p> <note> <p>A reply sent with this function will not be visible diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index 32174687cf..486f61b1ed 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -25,7 +25,7 @@ stop/1,stop/3, cast/2,call/2,call/3, enter_loop/4,enter_loop/5,enter_loop/6, - reply/2]). + reply/1,reply/2]). %% gen callbacks -export( @@ -105,17 +105,21 @@ {'reply', % Reply to a client Client :: client(), Reply :: term()}. -type state_callback_result() :: - {stop, % Stop the server + {'stop', % Stop the server + Reason :: term()} | + {'stop', % Stop the server Reason :: term(), NewStateData :: state_data()} | - {stop, % Stop the server + {'stop', % Stop the server Reason :: term(), Replies :: [reply_operation()] | reply_operation(), NewStateData :: state_data()} | - {next_state, % {next_state,NewState,NewStateData,[]} + {'next_state', % {next_state,State,StateData,StateOps} % Actually useful + StateOps :: [state_op()] | state_op()} | + {'next_state', % {next_state,NewState,NewStateData,[]} NewState :: state(), NewStateData :: state_data()} | - {next_state, % State transition, maybe to the same state + {'next_state', % State transition, maybe to the same state NewState :: state(), NewStateData :: state_data(), StateOps :: [state_op()] | state_op()}. @@ -379,6 +383,10 @@ call(ServerRef, Request, Timeout) -> end. %% Reply from a state machine callback to whom awaits in call/2 +-spec reply(ReplyOperation :: reply_operation()) -> ok. +reply({reply,{_To,_Tag}=Client,Reply}) -> + reply(Client, Reply). +%% -spec reply(Client :: client(), Reply :: term()) -> ok. reply({To,Tag}, Reply) -> Msg = {Tag,Reply}, @@ -742,6 +750,8 @@ loop_events( %% Interpret all callback return value variants loop_event_result(Parent, Debug, S, Events, Event, Result) -> case Result of + {stop,Reason} -> + ?TERMINATE(Reason, Debug, S, [Event|Events]); {stop,Reason,NewStateData} -> ?TERMINATE( Reason, Debug, @@ -764,6 +774,11 @@ loop_event_result(Parent, Debug, S, Events, Event, Result) -> ?TERMINATE( {bad_return_value,{stop,Reason,BadReplies,NewStateData}}, Debug, NewS, Q); + {next_state,StateOps} -> + #{state := State, state_data := StateData} = S, + loop_event_state_ops( + Parent, Debug, S, Events, Event, + State, StateData, StateOps); {next_state,NewState,NewStateData} -> loop_event_state_ops( Parent, Debug, S, Events, Event, @@ -846,7 +861,12 @@ loop_event_state_ops( %% Server helpers collect_init_options(InitOps) -> - collect_init_options(InitOps, state_functions, []). + if + is_list(InitOps) -> + collect_init_options(InitOps, state_functions, []); + true -> + collect_init_options([InitOps], state_functions, []) + end. %% Keep the last of each kind collect_init_options([], CallbackMode, StateOps) -> {CallbackMode,lists:reverse(StateOps)}; @@ -864,7 +884,12 @@ collect_init_options([InitOp|InitOps] = IOIOs, CallbackMode, StateOps) -> end. collect_state_options(StateOps) -> - collect_state_options(StateOps, false, false, undefined, []). + if + is_list(StateOps) -> + collect_state_options(StateOps, false, false, undefined, []); + true -> + collect_state_options([StateOps], false, false, undefined, []) + end. %% Keep the last of each kind collect_state_options( [], Postpone, Hibernate, Timeout, Operations) -> diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 8b619b6a60..6249ada027 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1158,11 +1158,10 @@ idle(cast, badreturn, _, _, _Data) -> badreturn; idle({call,_From}, badreturn, _, _, _Data) -> badreturn; -idle({call,From}, {delayed_answer,T}, _, State, Data) -> +idle({call,From}, {delayed_answer,T}, _, _, _) -> receive after T -> - {next_state,State,Data, - [{reply,From,delayed}]} + throw({next_state,{reply,From,delayed}}) end; idle({call,From}, {timeout,Time}, _, State, _Data) -> {next_state,timeout,{From,Time}, @@ -1172,9 +1171,10 @@ idle(Type, Content, PrevState, State, Data) -> undefined -> case Type of {call,From} -> - {next_state,State,Data,[{reply,From,'eh?'}]}; + throw({next_state,[{reply,From,'eh?'}]}); _ -> - {stop,{unexpected,State,PrevState,Type,Content},Data} + throw( + {stop,{unexpected,State,PrevState,Type,Content}}) end; Result -> Result @@ -1208,8 +1208,8 @@ timeout3(_, _, _, State, Data) -> wfor_conf({call,From}, confirm, _, _, Data) -> {next_state,connected,Data, [{reply,From,yes}]}; -wfor_conf(cast, {ping,_,_}, _, State, Data) -> - {next_state,State,Data,[postpone]}; +wfor_conf(cast, {ping,_,_}, _, _, _) -> + {next_state,[postpone]}; wfor_conf(cast, confirm, _, _, Data) -> {next_state,connected,Data}; wfor_conf(Type, Content, PrevState, State, Data) -> @@ -1220,7 +1220,7 @@ wfor_conf(Type, Content, PrevState, State, Data) -> {next_state,idle,Data, [{reply,From,'eh?'}]}; _ -> - {next_state,State,Data} + throw({next_state,[]}) end; Result -> Result @@ -1320,12 +1320,12 @@ handle_common_events(cast, {get,Pid}, _, State, Data) -> {next_state,State,Data}; handle_common_events({call,From}, stop, _, _, Data) -> {stop,normal,[{reply,From,stopped}],Data}; -handle_common_events(cast, stop, _, _, Data) -> - {stop,normal,Data}; +handle_common_events(cast, stop, _, _, _) -> + {stop,normal}; handle_common_events({call,From}, {stop,Reason}, _, _, Data) -> {stop,Reason,{reply,From,stopped},Data}; -handle_common_events(cast, {stop,Reason}, _, _, Data) -> - {stop,Reason,Data}; +handle_common_events(cast, {stop,Reason}, _, _, _) -> + {stop,Reason}; handle_common_events({call,From}, 'alive?', _, State, Data) -> {next_state,State,Data, [{reply,From,yes}]}; |