Current section
Files
Jump to
Current section
Files
src/puddle.erl
-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
).