%% -*- erlang -*- %% %% A generic Petri net OTP behavior. %% %% Copyright 2016-2017 Jörgen Brandt %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% ------------------------------------------------------------------- %% @author Jörgen Brandt %% @version 0.1.4 %% @copyright 2016-2017 Jörgen Brandt %% @doc Callback function definitions for Petri net actor interface. %% %% In addition to the structure callback functions there are another seven %% callback functions that determine how the net instance appears as an Erlang %% actor to the outside world: %% %% %% %%

code_change/3

%% %% The `code_change/3' function determines what happens when a hot code reload %% appears. This callback is identical to the `code_change/3' function in the %% `gen_server' behavior. %% %% Example: %% ``` %% code_change( _OldVsn, NetState, _Extra ) -> {ok, NetState}. %% ''' %% %%

handle_call/3

%% %% The `handle_call/3' function performs a synchronous exchange of messages %% between the caller and the net instance. The first argument is the request %% message, the second argument is a tuple identifying the caller, and the third %% argument is a `#net_state{}' record instance describing the current state of %% the net. The `handle_call/3' function can generate a reply without changing %% the net marking by returning a `{reply, Reply}' tuple, it can generate a %% reply, consuming or producing tokens by returning a %% `{reply, Reply, ConsumeMap, ProduceMap}' tuple, it can defer replying without %% changing the net marking by returning `noreply', it can defer replying, %% consuming or producing tokens by returning a %% `{noreply, ConsumeMap, ProduceMap}' tuple, or it can stop the net instance by %% returning `{stop, Reason, Reply}'. %% %% Example: %% ``` %% handle_call( insert_coin, _From, _NetState ) -> %% {reply, ok, #{}, #{ coin_slot => [coin] }}; %% %% handle_call( remove_cookie_box, _From, NetState ) -> %% %% case gen_pnet:get_ls( compartment, NetState ) of %% [] -> {reply, {error, empty_compartment}}; %% [_|_] -> {reply, ok, #{ compartment => [cookie_box] }, #{}} %% end; %% %% handle_call( _Request, _From, _NetState ) -> {reply, {error, bad_msg}}. %% ''' %% Here, we react to two kinds of messages: Inserting a coin in the coin slot %% and removing a cookie box from the compartment. Thus, we react to an %% `insert_coin' message by replying with `ok', consuming nothing and producing %% a `coin' token on the `coin_slot' place. When receiving a `remove_cookie_box' %% message, we check whether the `compartment' place is empty, replying with an %% error message if it is, otherwise replying with `ok', consuming one %% `cookie_box' token from the `compartment' place, and producing nothing. Calls %% that are neither `insert_coin' nor `remove_cookie_box' are responded to with %% an error message. %% %%

handle_cast/2

%% %% The `handle_cast/2' function reacts to an asynchronous message received by %% the net instance. The first argument is the request while the second argument %% is a `#net_state{}' record instance. The `handle_cast/2' function can either %% leave the net unchanged by returning `noreply' or it can consume or produce %% tokens by returning a `{noreply, ConsumeMap, ProduceMap}' tuple. %% %% Example: %% ``` %% handle_cast( _Request, _NetState ) -> noreply. %% ''' %% Here, we just ignore any cast. %% %%

handle_info/2

%% %% The `handle_info/2' function reacts to an asynchronous, unformatted message %% received by the net instance. The first argument is the message term while %% the second argument is a `#net_state{}' record instance. The `handle_info/2' %% function can either leave the net unchanged by returning `noreply' or it can %% consume or produce tokens by returning a `{noreply, ConsumeMap, ProduceMap}' %% tuple. %% %% Example: %% ``` %% handle_info( _Request, _NetState ) -> noreply. %% ''' %% Here, we just ignore any message. %% %%

init/1

%% %% The `init/1' function initializes the net instance. It is given a start %% argument term which is the start argument term that was provided with %% `gen_pnet:start_link/n'. As a return value a tuple of the form %% `{ok, #net_state{}}' is expected. We can construct it with the help of %% `gen_pnet:new/2'. This function takes two arguments: The module implementing %% the net structure callback functions as well as a user info field. %% %% Example: %% ``` %% init( _Args ) -> {ok, gen_pnet:new( ?MODULE, [] )}. %% ''' %% Here, we instantiate a `#net_state{}' record denoting the current module as %% the Petri net structure callback module and the empty list as the user-info %% field. %% %%

terminate/2

%% %% The `terminate/2' function determines what happens when the net instance is %% stopped. The first argument is the reason for termination while the second %% argument is a `#net_state{}' record instance. This callback is identical to %% the `terminate/2' function in the `gen_server' behavior. %% %% Example: %% ``` %% terminate( _Reason, _NetState ) -> ok. %% ''' %% %%

trigger/3

%% %% The `trigger/3' function determines what happens when a token is produced on %% a given place. Its first argument `Place' is the place name, its second %% argument `Token' is the token about to be produced, and its third argument %% `NetState' is the current state of the net. The `trigger/3' function is %% expected to return either `pass' in which case the token is produced %% normally, or `drop' in which case the token is forgotten. %% %% Example: %% ``` %% trigger( _Place, _Token, _NetState ) -> pass. %% ''' %% Here, we simply let any token pass. %% %% @end %% ------------------------------------------------------------------- -module( gen_pnet_iface ). -include( "gen_pnet.hrl" ). -callback code_change( OldVsn :: _, NetState :: #net_state{}, Extra :: _ ) -> {ok, #net_state{}} | {error, _}. -callback handle_call( Request :: _, From :: {pid(), _}, NetState :: #net_state{} ) -> {reply, _} | {reply, _, #{ atom() => [_] }, #{ atom() => [_] }} | noreply | {noreply, #{ atom() => [_] }, #{ atom() => [_] }} | {stop, _, _}. -callback handle_cast( Request :: _, NetState :: #net_state{} ) -> noreply | {noreply, #{ atom() => [_] }, #{ atom() => [_] }} | {stop, _}. -callback handle_info( Info :: _, NetState :: #net_state{} ) -> noreply | {noreply, #{ atom() => [_] }, #{ atom() => [_] }} | {stop, _}. -callback init( Args :: _ ) -> {ok, #net_state{}}. -callback terminate( Reason :: _, NetState :: #net_state{} ) -> ok. -callback trigger( Place :: atom(), Token :: _, NetState :: #net_state{} ) -> pass | drop.