-module(puddle). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). -export([shutdown/2, apply/4, start/2]). -export_type([manager_message/2, resource_message/2]). -opaque manager_message(HFI, HFJ) :: {manager_shutdown, fun((HFI) -> nil)} | {check_in, gleam@erlang@process:subject(resource_message(HFI, HFJ))} | {check_out, gleam@erlang@process:subject({ok, gleam@erlang@process:subject(resource_message(HFI, HFJ))} | {error, nil})}. -opaque resource_message(HFK, HFL) :: {resource_usage, fun((HFK) -> HFL), gleam@erlang@process:subject({ok, HFL} | {error, nil})} | {resource_shutdown, fun((HFK) -> nil)}. -spec shutdown( gleam@erlang@process:subject(manager_message(HIQ, any())), fun((HIQ) -> nil) ) -> nil. shutdown(Manager, Shutdown_function) -> gleam@erlang@process:send(Manager, {manager_shutdown, Shutdown_function}). -spec check_out( gleam@erlang@process:subject(manager_message(HGL, HGM)), integer() ) -> {ok, {ok, gleam@erlang@process:subject(resource_message(HGL, HGM))} | {error, nil}} | {error, gleam@erlang@process:call_error({ok, gleam@erlang@process:subject(resource_message(HGL, HGM))} | {error, nil})}. check_out(Manager, Timeout) -> gleam@erlang@process:try_call( Manager, fun(Field@0) -> {check_out, Field@0} end, Timeout ). -spec utilize( gleam@erlang@process:subject(resource_message(HGR, HGS)), fun((HGR) -> HGS), gleam@erlang@process:subject({ok, HGS} | {error, nil}) ) -> nil. utilize(Subject, Fun, Mine) -> gleam@erlang@process:send(Subject, {resource_usage, Fun, Mine}). -spec check_in( gleam@erlang@process:subject(manager_message(HHA, HHB)), gleam@erlang@process:subject(resource_message(HHA, HHB)) ) -> nil. check_in(Manager, Subject) -> gleam@erlang@process:send(Manager, {check_in, Subject}). -spec apply( gleam@erlang@process:subject(manager_message(HGB, HGC)), fun((HGB) -> HGC), integer(), fun(({ok, HGC} | {error, nil}) -> {ok, HJE} | {error, nil}) ) -> {ok, HJE} | {error, nil}. apply(Manager, Fun, Timeout, Rest) -> gleam@result:then( begin _pipe = check_out(Manager, Timeout), _pipe@1 = gleam@result:replace_error(_pipe, nil), gleam@result:flatten(_pipe@1) end, fun(Subject) -> Mine = gleam@erlang@process:new_subject(), utilize(Subject, Fun, Mine), Selector = begin _pipe@2 = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting(_pipe@2, Mine, fun(R) -> R end) end, Result = begin _pipe@3 = gleam_erlang_ffi:select(Selector, Timeout), gleam@result:flatten(_pipe@3) end, check_in(Manager, Subject), Rest(Result) end ). -spec handle_manager_message( manager_message(HHR, HHS), list({gleam@erlang@process:pid_(), gleam@erlang@process:subject(resource_message(HHR, HHS))}) ) -> gleam@otp@actor:next(any(), list({gleam@erlang@process:pid_(), gleam@erlang@process:subject(resource_message(HHR, HHS))})). handle_manager_message(Msg, Puddle) -> case Msg of {manager_shutdown, Shutdown_function} -> gleam@list:each( Puddle, fun(Item) -> gleam@erlang@process:send( erlang:element(2, Item), {resource_shutdown, Shutdown_function} ) end ), {stop, normal}; {check_in, Subject} -> Pid = gleam@erlang@process:subject_owner(Subject), gleam@otp@actor:continue(gleam@list:prepend(Puddle, {Pid, Subject})); {check_out, Client} -> case Puddle of [] -> gleam@otp@actor:send(Client, {error, nil}), gleam@otp@actor:continue(Puddle); [{_, Chosen} | New_puddle] -> gleam@otp@actor:send(Client, {ok, Chosen}), gleam@otp@actor:continue(New_puddle) end end. -spec handle_resource_message(resource_message(HHY, any()), HHY) -> gleam@otp@actor:next(any(), HHY). handle_resource_message(Msg, Resource) -> case Msg of {resource_usage, Fun, Client} -> Result = Fun(Resource), gleam@otp@actor:send(Client, {ok, Result}), gleam@otp@actor:continue(Resource); {resource_shutdown, Shutdown} -> Shutdown(Resource), {stop, normal} end. -spec new(integer(), fun(() -> {ok, HHJ} | {error, nil})) -> {ok, list({gleam@erlang@process:pid_(), gleam@erlang@process:subject(resource_message(HHJ, any()))})} | {error, nil}. new(Size, New_resource) -> _pipe = gleam@list:repeat(<<""/utf8>>, Size), gleam@list:try_map(_pipe, fun(_) -> case New_resource() of {ok, Initial_state} -> _pipe@1 = gleam@otp@actor:start( Initial_state, fun handle_resource_message/2 ), _pipe@2 = gleam@result:map( _pipe@1, fun(Subject) -> Pid = gleam@erlang@process:subject_owner(Subject), {Pid, Subject} end ), gleam@result:nil_error(_pipe@2); {error, nil} -> {error, nil} end end). -spec start(integer(), fun(() -> {ok, HFS} | {error, nil})) -> {ok, gleam@erlang@process:subject(manager_message(HFS, any()))} | {error, gleam@otp@actor:start_error()}. start(Size, New_resource) -> gleam@result:then( begin _pipe = new(Size, New_resource), gleam@result:map_error( _pipe, fun(_) -> {init_failed, {abnormal, <<"Failed to create new resource"/utf8>>}} end ) end, fun(Puddle) -> gleam@otp@actor:start(Puddle, fun handle_manager_message/2) end ).