-module(booklet_ffi). -compiler([no_auto_import, nowarn_conflicting_behaviours, nowarn_nomatch]). -behaviour(application). -export([start/2, stop/1]). -behaviour(gen_server). % The nowarn rule doesn't work so I figured I can just disable that line % -behaviour(supervisor). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([make/1, get/1, update/2]). % -- Public API ---------------------------------------------------------------- make(DefaultValue) -> Table = gen_server:call(booklet, get), Key = make_ref(), true = ets:insert_new(Table, {Key, 0, DefaultValue}), {Table, Key}. get({Table, Key}) -> ets:lookup_element(Table, Key, 3). update({Table, Key}, Updater) -> [{Key, Rev, Value}] = ets:lookup(Table, Key), NewValue = Updater(Value), Pattern = {Key, Rev, '_'}, Replacement = {const, {Key, Rev + 1, NewValue}}, case ets:select_replace(Table, [{Pattern, [], [Replacement]}]) of 0 -> update({Table, Key}, Updater); _ -> NewValue end. % -- APPLICATION --------------------------------------------------------------- start(_StartType, _StartArgs) -> supervisor:start_link(?MODULE, supervisor). stop(_State) -> ok. % -- SUPERVISOR ---------------------------------------------------------------- init(supervisor) -> SupFlags = #{ strategy => one_for_one, intensity => 6, period => 3600 }, ChildSpec = #{ id => booklet, start => {gen_server, start_link, [{local, booklet}, ?MODULE, gen_server, []]}, shutdown => brutal_kill, modules => [?MODULE] }, {ok, {SupFlags, [ChildSpec]}}; % -- ACTOR --------------------------------------------------------------------- init(gen_server) -> Table = ets:new(booklet, [set, public, {keypos, 1}, {write_concurrency, auto}, {read_concurrency, true}]), {ok, Table}. handle_call(get, _From, Table) -> {reply, Table, Table}. handle_cast(_Msg, Table) -> {noreply, Table}. handle_info(_Info, Table) -> {noreply, Table}. terminate(_Reason, _Table) -> ok. code_change(_Prev, Table, _Extra) -> {ok, Table}.