-module(bath). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new/1, with_size/2, with_shutdown/2, with_checkout_strategy/2, with_creation_strategy/2, from_subject/1, apply/3, shutdown/3, child_spec/2, start/2]). -export_type([checkout_strategy/0, creation_strategy/0, pool_config/2, start_error/1, apply_error/1, shutdown_error/0, pool/2, state/2, live_resource/1, msg/2]). -type checkout_strategy() :: fifo | lifo. -type creation_strategy() :: lazy | eager. -opaque pool_config(HRG, HRH) :: {pool_config, integer(), fun(() -> {ok, HRG} | {error, HRH}), fun((HRG) -> nil), checkout_strategy(), creation_strategy()}. -type start_error(HRI) :: {pool_start_resource_create_error, HRI} | {actor_start_error, gleam@otp@actor:start_error()}. -type apply_error(HRJ) :: no_resources_available | {check_out_resource_create_error, HRJ} | check_out_timeout. -type shutdown_error() :: resources_in_use | shutdown_timeout | {callee_down, gleam@dynamic:dynamic_()}. -opaque pool(HRK, HRL) :: {pool, gleam@erlang@process:subject(msg(HRK, HRL))}. -opaque state(HRM, HRN) :: {state, checkout_strategy(), creation_strategy(), integer(), fun(() -> {ok, HRM} | {error, HRN}), fun((HRM) -> nil), gleam@deque:deque(HRM), integer(), gleam@dict:dict(gleam@erlang@process:pid_(), live_resource(HRM)), gleam@erlang@process:selector(msg(HRM, HRN))}. -type live_resource(HRO) :: {live_resource, HRO, gleam@erlang@process:process_monitor()}. -opaque msg(HRP, HRQ) :: {check_in, HRP, gleam@erlang@process:pid_()} | {check_out, gleam@erlang@process:subject({ok, HRP} | {error, apply_error(HRQ)}), gleam@erlang@process:pid_()} | {pool_exit, gleam@erlang@process:exit_message()} | {caller_down, gleam@erlang@process:process_down()} | {shutdown, gleam@erlang@process:subject({ok, nil} | {error, shutdown_error()}), boolean()}. -file("/Users/isaac/repos/bath/src/bath.gleam", 62). -spec new(fun(() -> {ok, HRV} | {error, HRW})) -> pool_config(HRV, HRW). new(Create_resource) -> {pool_config, 10, Create_resource, fun(_) -> nil end, fifo, lazy}. -file("/Users/isaac/repos/bath/src/bath.gleam", 75). -spec with_size(pool_config(HSB, HSC), integer()) -> pool_config(HSB, HSC). with_size(Pool_config, Size) -> erlang:setelement(2, Pool_config, Size). -file("/Users/isaac/repos/bath/src/bath.gleam", 83). -spec with_shutdown(pool_config(HSH, HSI), fun((HSH) -> nil)) -> pool_config(HSH, HSI). with_shutdown(Pool_config, Shutdown_resource) -> erlang:setelement(4, Pool_config, Shutdown_resource). -file("/Users/isaac/repos/bath/src/bath.gleam", 91). -spec with_checkout_strategy(pool_config(HSN, HSO), checkout_strategy()) -> pool_config(HSN, HSO). with_checkout_strategy(Pool_config, Checkout_strategy) -> erlang:setelement(5, Pool_config, Checkout_strategy). -file("/Users/isaac/repos/bath/src/bath.gleam", 99). -spec with_creation_strategy(pool_config(HST, HSU), creation_strategy()) -> pool_config(HST, HSU). with_creation_strategy(Pool_config, Creation_strategy) -> erlang:setelement(6, Pool_config, Creation_strategy). -file("/Users/isaac/repos/bath/src/bath.gleam", 165). -spec from_subject(gleam@erlang@process:subject(msg(HTM, HTN))) -> pool(HTM, HTN). from_subject(Subject) -> {pool, Subject}. -file("/Users/isaac/repos/bath/src/bath.gleam", 190). -spec check_out(pool(HUC, HUD), gleam@erlang@process:pid_(), integer()) -> {ok, HUC} | {error, apply_error(HUD)}. check_out(Pool, Caller, Timeout) -> _pipe = gleam@erlang@process:try_call( erlang:element(2, Pool), fun(_capture) -> {check_out, _capture, Caller} end, Timeout ), _pipe@1 = gleam@result:replace_error(_pipe, check_out_timeout), gleam@result:flatten(_pipe@1). -file("/Users/isaac/repos/bath/src/bath.gleam", 200). -spec check_in(pool(HUJ, any()), HUJ, gleam@erlang@process:pid_()) -> nil. check_in(Pool, Resource, Caller) -> gleam@erlang@process:send( erlang:element(2, Pool), {check_in, Resource, Caller} ). -file("/Users/isaac/repos/bath/src/bath.gleam", 219). -spec apply(pool(HUO, HUP), integer(), fun((HUO) -> HUS)) -> {ok, HUS} | {error, apply_error(HUP)}. apply(Pool, Timeout, Next) -> Self = erlang:self(), gleam@result:'try'( check_out(Pool, Self, Timeout), fun(Resource) -> Usage_result = Next(Resource), check_in(Pool, Resource, Self), {ok, Usage_result} end ). -file("/Users/isaac/repos/bath/src/bath.gleam", 241). -spec shutdown(pool(any(), any()), boolean(), integer()) -> {ok, nil} | {error, shutdown_error()}. shutdown(Pool, Force, Timeout) -> _pipe = gleam@erlang@process:try_call( erlang:element(2, Pool), fun(_capture) -> {shutdown, _capture, Force} end, Timeout ), _pipe@1 = gleam@result:map_error(_pipe, fun(Err) -> case Err of call_timeout -> shutdown_timeout; {callee_down, Reason} -> {callee_down, Reason} end end), gleam@result:flatten(_pipe@1). -file("/Users/isaac/repos/bath/src/bath.gleam", 520). -spec monitor_process( gleam@erlang@process:selector(msg(HVT, HVU)), gleam@erlang@process:pid_() ) -> {gleam@erlang@process:process_monitor(), gleam@erlang@process:selector(msg(HVT, HVU))}. monitor_process(Selector, Pid) -> Monitor = gleam@erlang@process:monitor_process(Pid), Selector@1 = begin _pipe = Selector, gleam@erlang@process:selecting_process_down( _pipe, Monitor, fun(Field@0) -> {caller_down, Field@0} end ) end, {Monitor, Selector@1}. -file("/Users/isaac/repos/bath/src/bath.gleam", 531). -spec demonitor_process( gleam@erlang@process:selector(msg(HVZ, HWA)), gleam@erlang@process:process_monitor() ) -> gleam@erlang@process:selector(msg(HVZ, HWA)). demonitor_process(Selector, Monitor) -> Selector@1 = begin _pipe = Selector, gleam@erlang@process:deselecting_process_down(_pipe, Monitor) end, Selector@1. -file("/Users/isaac/repos/bath/src/bath.gleam", 541). -spec log_resource_creation_error(any()) -> nil. log_resource_creation_error(Resource_create_error) -> logging:log( error, <<"Bath: Resource creation failed: "/utf8, (gleam@string:inspect(Resource_create_error))/binary>> ). -file("/Users/isaac/repos/bath/src/bath.gleam", 299). -spec handle_pool_message(msg(HVB, HVC), state(HVB, HVC)) -> gleam@otp@actor:next(msg(HVB, HVC), state(HVB, HVC)). handle_pool_message(Msg, State) -> case Msg of {check_in, Resource, Caller} -> Caller_live_resource = gleam_stdlib:map_get( erlang:element(9, State), Caller ), Live_resources = gleam@dict:delete(erlang:element(9, State), Caller), Selector = case Caller_live_resource of {ok, Live_resource} -> demonitor_process( erlang:element(10, State), erlang:element(3, Live_resource) ); {error, _} -> erlang:element(10, State) end, New_resources = gleam@deque:push_back( erlang:element(7, State), Resource ), gleam@otp@actor:with_selector( gleam@otp@actor:continue( erlang:setelement( 10, erlang:setelement( 9, erlang:setelement(7, State, New_resources), Live_resources ), Selector ) ), Selector ); {check_out, Reply_to, Caller@1} -> Get_result = case erlang:element(2, State) of fifo -> gleam@deque:pop_front(erlang:element(7, State)); lifo -> gleam@deque:pop_back(erlang:element(7, State)) end, Resource_result = case Get_result of {ok, {Resource@1, New_resources@1}} -> {ok, {Resource@1, New_resources@1, erlang:element(8, State)}}; {error, _} -> case erlang:element(8, State) < erlang:element(4, State) of true -> gleam@result:'try'( begin _pipe = (erlang:element(5, State))(), gleam@result:map_error( _pipe, fun(Err) -> log_resource_creation_error(Err), {check_out_resource_create_error, Err} end ) end, fun(Resource@2) -> {ok, {Resource@2, erlang:element(7, State), erlang:element(8, State) + 1}} end ); false -> {error, no_resources_available} end end, case Resource_result of {error, Err@1} -> gleam@otp@actor:send(Reply_to, {error, Err@1}), gleam@otp@actor:continue(State); {ok, {Resource@3, New_resources@2, New_current_size}} -> {Monitor, Selector@1} = monitor_process( erlang:element(10, State), Caller@1 ), Live_resources@1 = gleam@dict:insert( erlang:element(9, State), Caller@1, {live_resource, Resource@3, Monitor} ), gleam@otp@actor:send(Reply_to, {ok, Resource@3}), gleam@otp@actor:with_selector( gleam@otp@actor:continue( erlang:setelement( 9, erlang:setelement( 10, erlang:setelement( 8, erlang:setelement( 7, State, New_resources@2 ), New_current_size ), Selector@1 ), Live_resources@1 ) ), Selector@1 ) end; {pool_exit, Exit_message} -> _pipe@1 = erlang:element(7, State), _pipe@2 = gleam@deque:to_list(_pipe@1), gleam@list:each(_pipe@2, erlang:element(6, State)), {stop, erlang:element(3, Exit_message)}; {shutdown, Reply_to@1, Force} -> case {maps:size(erlang:element(9, State)), Force} of {0, _} -> _pipe@3 = erlang:element(7, State), _pipe@4 = gleam@deque:to_list(_pipe@3), gleam@list:each(_pipe@4, erlang:element(6, State)), gleam@otp@actor:send(Reply_to@1, {ok, nil}), {stop, normal}; {_, true} -> gleam@otp@actor:send(Reply_to@1, {ok, nil}), {stop, normal}; {_, false} -> gleam@otp@actor:send(Reply_to@1, {error, resources_in_use}), gleam@otp@actor:continue(State) end; {caller_down, Process_down} -> case gleam_stdlib:map_get( erlang:element(9, State), erlang:element(2, Process_down) ) of {error, _} -> gleam@otp@actor:continue(State); {ok, Live_resource@1} -> Selector@2 = demonitor_process( erlang:element(10, State), erlang:element(3, Live_resource@1) ), (erlang:element(6, State))( erlang:element(2, Live_resource@1) ), {New_resources@3, New_current_size@1} = case erlang:element( 3, State ) of lazy -> {erlang:element(7, State), erlang:element(8, State) - 1}; eager -> case (erlang:element(5, State))() of {ok, Resource@4} -> {gleam@deque:push_back( erlang:element(7, State), Resource@4 ), erlang:element(8, State)}; {error, Resource_create_error} -> log_resource_creation_error( Resource_create_error ), {erlang:element(7, State), erlang:element(8, State)} end end, gleam@otp@actor:with_selector( gleam@otp@actor:continue( erlang:setelement( 9, erlang:setelement( 10, erlang:setelement( 8, erlang:setelement( 7, State, New_resources@3 ), New_current_size@1 ), Selector@2 ), gleam@dict:delete( erlang:element(9, State), erlang:element(2, Process_down) ) ) ), Selector@2 ) end end. -file("/Users/isaac/repos/bath/src/bath.gleam", 481). -spec pool_spec( pool_config(HVI, HVJ), gleam@deque:deque(HVI), integer(), integer() ) -> gleam@otp@actor:spec(state(HVI, HVJ), msg(HVI, HVJ)). pool_spec(Pool_config, Resources, Current_size, Init_timeout) -> {spec, fun() -> Self = gleam@erlang@process:new_subject(), gleam_erlang_ffi:trap_exits(true), Selector = begin _pipe = gleam_erlang_ffi:new_selector(), _pipe@1 = gleam@erlang@process:selecting( _pipe, Self, fun gleam@function:identity/1 ), gleam@erlang@process:selecting_trapped_exits( _pipe@1, fun(Field@0) -> {pool_exit, Field@0} end ) end, State = {state, erlang:element(5, Pool_config), erlang:element(6, Pool_config), erlang:element(2, Pool_config), erlang:element(3, Pool_config), erlang:element(4, Pool_config), Resources, Current_size, maps:new(), Selector}, {ready, State, Selector} end, Init_timeout, fun handle_pool_message/2}. -file("/Users/isaac/repos/bath/src/bath.gleam", 136). -spec child_spec(pool_config(HSZ, HTA), integer()) -> {ok, gleam@otp@actor:spec(state(HSZ, HTA), msg(HSZ, HTA))} | {error, start_error(HTA)}. child_spec(Pool_config, Init_timeout) -> {Resources_result, Current_size} = case erlang:element(6, Pool_config) of lazy -> {{ok, gleam@deque:new()}, 0}; eager -> {begin _pipe = gleam@list:repeat( <<""/utf8>>, erlang:element(2, Pool_config) ), _pipe@1 = gleam@list:try_map( _pipe, fun(_) -> (erlang:element(3, Pool_config))() end ), _pipe@2 = gleam@result:map( _pipe@1, fun gleam@deque:from_list/1 ), gleam@result:map_error( _pipe@2, fun(Field@0) -> {pool_start_resource_create_error, Field@0} end ) end, erlang:element(2, Pool_config)} end, gleam@result:'try'( Resources_result, fun(Resources) -> {ok, pool_spec(Pool_config, Resources, Current_size, Init_timeout)} end ). -file("/Users/isaac/repos/bath/src/bath.gleam", 173). -spec start(pool_config(HTT, HTU), integer()) -> {ok, pool(HTT, HTU)} | {error, start_error(HTU)}. start(Pool_config, Init_timeout) -> gleam@result:'try'( child_spec(Pool_config, Init_timeout), fun(Spec) -> _pipe = gleam@otp@actor:start_spec(Spec), _pipe@1 = gleam@result:map( _pipe, fun(Subject) -> {pool, Subject} end ), gleam@result:map_error( _pipe@1, fun(Field@0) -> {actor_start_error, Field@0} end ) end ).