-module(sprocket@internal@utils@timer). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/sprocket/internal/utils/timer.gleam"). -export([timer/2, interval/2, now/0, convert_time_unit/3, timed_operation/2]). -export_type([timer_msg/0, timed_operation/0, time_unit/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC(false). -type timer_msg() :: cancel | {timeout, fun(() -> nil)} | {interval, gleam@erlang@process:subject(timer_msg()), integer(), fun(() -> nil)}. -type timed_operation() :: {timed_operation, binary(), integer()}. -type time_unit() :: native | microsecond. -file("src/sprocket/internal/utils/timer.gleam", 17). ?DOC(false). -spec handle_timer_message(integer(), timer_msg()) -> gleam@otp@actor:next(integer(), timer_msg()). handle_timer_message(State, Msg) -> case Msg of cancel -> gleam@otp@actor:stop(); {timeout, Cb} -> Cb(), gleam@otp@actor:stop(); {interval, Actor, Interval_ms, Cb@1} -> Cb@1(), gleam@erlang@process:send_after( Actor, Interval_ms, {interval, Actor, Interval_ms, Cb@1} ), gleam@otp@actor:continue(State) end. -file("src/sprocket/internal/utils/timer.gleam", 37). ?DOC(false). -spec timer(integer(), fun(() -> nil)) -> gleam@erlang@process:timer(). timer(Interval_ms, Callback) -> Actor@1 = case begin _pipe = gleam@otp@actor:new(Interval_ms), _pipe@1 = gleam@otp@actor:on_message(_pipe, fun handle_timer_message/2), _pipe@2 = gleam@otp@actor:start(_pipe@1), gleam@result:map_error( _pipe@2, fun(Error) -> sprocket@internal@logger:error( <<"timer.timer: failed to start timer actor"/utf8>> ), Error end ) end of {ok, {started, _, Actor}} -> Actor; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/internal/utils/timer"/utf8>>, function => <<"timer"/utf8>>, line => 38, value => _assert_fail, start => 768, 'end' => 1027, pattern_start => 779, pattern_end => 813}) end, gleam@erlang@process:send_after(Actor@1, Interval_ms, {timeout, Callback}). -file("src/sprocket/internal/utils/timer.gleam", 51). ?DOC(false). -spec interval(integer(), fun(() -> nil)) -> fun(() -> nil). interval(Interval_ms, Callback) -> Actor@1 = case begin _pipe = gleam@otp@actor:new(Interval_ms), _pipe@1 = gleam@otp@actor:on_message(_pipe, fun handle_timer_message/2), _pipe@2 = gleam@otp@actor:start(_pipe@1), gleam@result:map_error( _pipe@2, fun(Error) -> sprocket@internal@logger:error( <<"timer.interval: failed to start timer actor"/utf8>> ), Error end ) end of {ok, {started, _, Actor}} -> Actor; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"sprocket/internal/utils/timer"/utf8>>, function => <<"interval"/utf8>>, line => 52, value => _assert_fail, start => 1190, 'end' => 1452, pattern_start => 1201, pattern_end => 1235}) end, gleam@erlang@process:send_after( Actor@1, Interval_ms, {interval, Actor@1, Interval_ms, Callback} ), fun() -> gleam@otp@actor:send(Actor@1, cancel) end. -file("src/sprocket/internal/utils/timer.gleam", 106). ?DOC(false). -spec now() -> integer(). now() -> erlang:monotonic_time(). -file("src/sprocket/internal/utils/timer.gleam", 79). ?DOC(false). -spec begin_timed_operation(binary()) -> timed_operation(). begin_timed_operation(Label) -> sprocket@internal@logger:debug( erlang:list_to_binary([<<"Starting "/utf8>>, Label, <<"..."/utf8>>]) ), {timed_operation, Label, erlang:monotonic_time()}. -file("src/sprocket/internal/utils/timer.gleam", 109). ?DOC(false). -spec convert_time_unit(integer(), time_unit(), time_unit()) -> integer(). convert_time_unit(A, B, C) -> erlang:convert_time_unit(A, B, C). -file("src/sprocket/internal/utils/timer.gleam", 85). ?DOC(false). -spec complete_timed_operation(timed_operation()) -> integer(). complete_timed_operation(Op) -> Elapsed = erlang:convert_time_unit( erlang:monotonic_time() - erlang:element(3, Op), native, microsecond ), Formatted_elapsed = case Elapsed > 1000 of true -> gleam@string:append( erlang:integer_to_binary(Elapsed div 1000), <<"ms"/utf8>> ); false -> gleam@string:append( erlang:integer_to_binary(Elapsed), <<"µs"/utf8>> ) end, _pipe = erlang:list_to_binary( [erlang:element(2, Op), <<" completed in "/utf8>>, Formatted_elapsed] ), sprocket@internal@logger:debug(_pipe), Elapsed. -file("src/sprocket/internal/utils/timer.gleam", 67). ?DOC(false). -spec timed_operation(binary(), fun(() -> IVE)) -> IVE. timed_operation(Label, Cb) -> Op_timer = begin_timed_operation(Label), Result = Cb(), complete_timed_operation(Op_timer), Result.