Current section
Files
Jump to
Current section
Files
src/lustre_limiter.erl
-module(lustre_limiter).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([debounce/2, throttle/2, push/2, update/2]).
-spec debounce(fun((lustre_limiter@internals:msg(OMJ)) -> OMJ), integer()) -> lustre_limiter@internals:limiter(OMJ).
debounce(Tagger, Delay) ->
{limiter, Tagger, {debounce, Delay, []}, open}.
-spec throttle(fun((lustre_limiter@internals:msg(OMM)) -> OMM), integer()) -> lustre_limiter@internals:limiter(OMM).
throttle(Tagger, Interval) ->
{limiter, Tagger, {throttle, Interval}, open}.
-spec push(OMP, lustre_limiter@internals:limiter(OMP)) -> {lustre_limiter@internals:limiter(OMP),
lustre@effect:effect(OMP)}.
push(Msg, Limiter) ->
case {erlang:element(4, Limiter), erlang:element(3, Limiter)} of
{open, {debounce, Cooldown, Queue}} ->
{erlang:setelement(3, Limiter, {debounce, Cooldown, [Msg | Queue]}),
lustre_limiter@internals:emit_after(
(erlang:element(2, Limiter))(
{emit_if_settled, erlang:length(Queue) + 1}
),
Cooldown
)};
{open, {throttle, Interval}} ->
{erlang:setelement(4, Limiter, close),
lustre@effect:batch(
[lustre_limiter@internals:emit_after(
(erlang:element(2, Limiter))(reopen),
Interval
),
lustre_limiter@internals:emit(Msg)]
)};
{close, _} ->
{Limiter, lustre@effect:none()}
end.
-spec update(
lustre_limiter@internals:msg(OMT),
lustre_limiter@internals:limiter(OMT)
) -> {lustre_limiter@internals:limiter(OMT), lustre@effect:effect(OMT)}.
update(Internal_msg, Limiter) ->
case {Internal_msg, erlang:element(4, Limiter), erlang:element(3, Limiter)} of
{{emit, Msg}, open, {throttle, Interval}} ->
{erlang:setelement(4, Limiter, close),
lustre@effect:batch(
[lustre_limiter@internals:emit_after(
(erlang:element(2, Limiter))(reopen),
Interval
),
lustre_limiter@internals:emit(Msg)]
)};
{{emit_if_settled, Count}, open, {debounce, Cooldown, Queue}} ->
case erlang:length(Queue) =:= Count of
true ->
{erlang:setelement(3, Limiter, {debounce, Cooldown, []}),
begin
_pipe = Queue,
_pipe@1 = gleam@list:first(_pipe),
_pipe@2 = gleam@result:map(
_pipe@1,
fun(Msg@1) ->
lustre_limiter@internals:emit(Msg@1)
end
),
gleam@result:unwrap(_pipe@2, lustre@effect:none())
end};
false ->
{Limiter, lustre@effect:none()}
end;
{reopen, _, _} ->
{erlang:setelement(4, Limiter, open), lustre@effect:none()};
{{push, Msg@2}, open, {debounce, Cooldown@1, Queue@1}} ->
{erlang:setelement(
3,
Limiter,
{debounce, Cooldown@1, [Msg@2 | Queue@1]}
),
lustre_limiter@internals:emit_after(
(erlang:element(2, Limiter))(
{emit_if_settled, erlang:length(Queue@1) + 1}
),
Cooldown@1
)};
{_, _, _} ->
{Limiter, lustre@effect:none()}
end.