-module(puddle). -compile([no_auto_import, nowarn_unused_vars]). -export([apply/4, start/2]). -export_type([bookkeeping_message/2, usage_message/2]). -opaque bookkeeping_message(GVS, GVT) :: shutdown | {check_in, gleam@erlang@process:subject(usage_message(GVS, GVT))} | {check_out, gleam@erlang@process:subject({ok, gleam@erlang@process:subject(usage_message(GVS, GVT))} | {error, nil})}. -opaque usage_message(GVU, GVV) :: {usage_message, fun((GVU) -> GVV), gleam@erlang@process:subject({ok, GVV} | {error, nil})}. -spec check_out( gleam@erlang@process:subject(bookkeeping_message(GWS, GWT)), integer() ) -> {ok, gleam@erlang@process:subject(usage_message(GWS, GWT))} | {error, nil}. check_out(Manager, Timeout) -> gleam@erlang@process:call( Manager, fun(Field@0) -> {check_out, Field@0} end, Timeout ). -spec utilize( gleam@erlang@process:subject(usage_message(GWY, GWZ)), fun((GWY) -> GWZ), gleam@erlang@process:subject({ok, GWZ} | {error, nil}) ) -> nil. utilize(Subject, Fun, Mine) -> gleam@erlang@process:send(Subject, {usage_message, Fun, Mine}). -spec check_in( gleam@erlang@process:subject(bookkeeping_message(GXH, GXI)), gleam@erlang@process:subject(usage_message(GXH, GXI)) ) -> nil. check_in(Manager, Subject) -> gleam@erlang@process:send(Manager, {check_in, Subject}). -spec apply( gleam@erlang@process:subject(bookkeeping_message(GWL, GWM)), fun((GWL) -> GWM), integer(), fun(({ok, GWM} | {error, nil}) -> {ok, GZI} | {error, nil}) ) -> {ok, GZI} | {error, nil}. apply(Manager, Fun, Timeout, Rest) -> gleam@result:then( check_out(Manager, Timeout), fun(Subject) -> Mine = gleam@erlang@process:new_subject(), utilize(Subject, Fun, Mine), Selector = begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting(_pipe, Mine, fun(R) -> R end) end, Result = begin _pipe@1 = gleam_erlang_ffi:select(Selector, Timeout), gleam@result:flatten(_pipe@1) end, check_in(Manager, Subject), Rest(Result) end ). -spec handle_bookkeeping_message( bookkeeping_message(GXY, GXZ), list({gleam@erlang@process:pid_(), gleam@erlang@process:subject(usage_message(GXY, GXZ))}) ) -> gleam@otp@actor:next(any(), list({gleam@erlang@process:pid_(), gleam@erlang@process:subject(usage_message(GXY, GXZ))})). handle_bookkeeping_message(Msg, Puddle) -> case Msg of shutdown -> gleam@list:each( Puddle, fun(Item) -> gleam@erlang@process:kill(erlang:element(1, Item)) 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_usage_message(usage_message(GYF, any()), GYF) -> gleam@otp@actor:next(any(), GYF). handle_usage_message(Msg, Resource) -> case Msg of {usage_message, Fun, Client} -> Result = Fun(Resource), gleam@otp@actor:send(Client, {ok, Result}), gleam@otp@actor:continue(Resource) end. -spec new(integer(), fun(() -> {ok, GXQ} | {error, nil})) -> {ok, list({gleam@erlang@process:pid_(), gleam@erlang@process:subject(usage_message(GXQ, 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_usage_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, GWC} | {error, nil})) -> {ok, gleam@erlang@process:subject(bookkeeping_message(GWC, 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_bookkeeping_message/2) end ).