-module(automata@cron@iterator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/cron/iterator.gleam").
-export(['after'/2, step/1]).
-export_type([cron_iterator/0, step/0]).
-opaque cron_iterator() :: {cron_iterator,
automata@cron@normalize:cron_plan(),
automata@schedule@ast:date_time()}.
-type step() :: {yield,
automata@schedule@ast:valid_date_time(),
cron_iterator()} |
done.
-file("src/automata/cron/iterator.gleam", 40).
-spec start_cursor(automata@schedule@ast:boundary()) -> automata@schedule@ast:date_time().
start_cursor(Boundary) ->
case Boundary of
{inclusive, Valid} ->
Datetime = automata@schedule@ast:valid_datetime_value(Valid),
case erlang:element(4, erlang:element(3, Datetime)) =:= 0 of
true ->
Datetime;
false ->
automata@internal@calendar:ceil_to_next_minute(Datetime)
end;
{exclusive, Valid@1} ->
Datetime@1 = automata@schedule@ast:valid_datetime_value(Valid@1),
case erlang:element(4, erlang:element(3, Datetime@1)) =:= 0 of
true ->
automata@internal@calendar:add_minutes(Datetime@1, 1);
false ->
automata@internal@calendar:ceil_to_next_minute(Datetime@1)
end
end.
-file("src/automata/cron/iterator.gleam", 22).
-spec 'after'(
automata@cron@normalize:cron_plan(),
automata@schedule@ast:boundary()
) -> cron_iterator().
'after'(Plan, Boundary) ->
{cron_iterator, Plan, start_cursor(Boundary)}.
-file("src/automata/cron/iterator.gleam", 99).
-spec day_matches(
automata@cron@normalize:cron_plan(),
automata@schedule@ast:date_time()
) -> boolean().
day_matches(Plan, Candidate) ->
Dom_match = automata@cron@evaluator:int_set_contains(
erlang:element(4, Plan),
erlang:element(4, erlang:element(2, Candidate))
),
Dow_match = automata@cron@evaluator:int_set_contains(
erlang:element(6, Plan),
automata@internal@calendar:day_of_week_number(Candidate)
),
Dom_any = case erlang:element(4, Plan) of
{any_value, _, _} ->
true;
{values, _} ->
false
end,
Dow_any = case erlang:element(6, Plan) of
{any_value, _, _} ->
true;
{values, _} ->
false
end,
case {Dom_any, Dow_any} of
{true, true} ->
true;
{true, false} ->
Dow_match;
{false, true} ->
Dom_match;
{false, false} ->
Dom_match orelse Dow_match
end.
-file("src/automata/cron/iterator.gleam", 125).
-spec align_hour(
automata@cron@normalize:cron_plan(),
automata@schedule@ast:date_time()
) -> gleam@option:option(automata@schedule@ast:date_time()).
align_hour(Plan, Candidate) ->
case automata@cron@evaluator:next_value_at_or_after(
erlang:element(3, Plan),
erlang:element(2, erlang:element(3, Candidate))
) of
none ->
none;
{some, Hour} ->
case Hour =:= erlang:element(2, erlang:element(3, Candidate)) of
true ->
{some,
{date_time,
erlang:element(2, Candidate),
{time,
Hour,
erlang:element(3, erlang:element(3, Candidate)),
0}}};
false ->
{some,
{date_time,
erlang:element(2, Candidate),
{time,
Hour,
automata@cron@evaluator:first_value(
erlang:element(2, Plan)
),
0}}}
end
end.
-file("src/automata/cron/iterator.gleam", 148).
-spec align_minute(
automata@cron@normalize:cron_plan(),
automata@schedule@ast:date_time()
) -> gleam@option:option(automata@schedule@ast:date_time()).
align_minute(Plan, Candidate) ->
case automata@cron@evaluator:next_value_at_or_after(
erlang:element(2, Plan),
erlang:element(3, erlang:element(3, Candidate))
) of
none ->
none;
{some, Minute} ->
{some,
{date_time,
erlang:element(2, Candidate),
{time,
erlang:element(2, erlang:element(3, Candidate)),
Minute,
0}}}
end.
-file("src/automata/cron/iterator.gleam", 159).
-spec next_day_start(automata@schedule@ast:date_time()) -> automata@schedule@ast:date_time().
next_day_start(Candidate) ->
automata@internal@calendar:next_day(Candidate).
-file("src/automata/cron/iterator.gleam", 163).
-spec next_hour_start(automata@schedule@ast:date_time()) -> automata@schedule@ast:date_time().
next_hour_start(Candidate) ->
Next = automata@internal@calendar:add_minutes(
Candidate,
60 - erlang:element(3, erlang:element(3, Candidate))
),
{date_time,
erlang:element(2, Next),
{time, erlang:element(2, erlang:element(3, Next)), 0, 0}}.
-file("src/automata/cron/iterator.gleam", 171).
-spec roll_to_next_matching_month(
automata@cron@normalize:cron_plan(),
automata@schedule@ast:date_time()
) -> automata@schedule@ast:date_time().
roll_to_next_matching_month(Plan, Candidate) ->
Next = automata@internal@calendar:next_month(Candidate),
case automata@cron@evaluator:int_set_contains(
erlang:element(5, Plan),
erlang:element(3, erlang:element(2, Next))
) of
true ->
Next;
false ->
roll_to_next_matching_month(Plan, Next)
end.
-file("src/automata/cron/iterator.gleam", 59).
-spec find_next(
automata@cron@normalize:cron_plan(),
automata@schedule@ast:date_time(),
integer()
) -> gleam@option:option(automata@schedule@ast:date_time()).
find_next(Plan, Candidate, Guard) ->
case Guard > 5000000 of
true ->
none;
false ->
case automata@cron@evaluator:int_set_contains(
erlang:element(5, Plan),
erlang:element(3, erlang:element(2, Candidate))
) of
false ->
Next_month = roll_to_next_matching_month(Plan, Candidate),
find_next(Plan, Next_month, Guard + 1);
true ->
case day_matches(Plan, Candidate) of
false ->
find_next(
Plan,
next_day_start(Candidate),
Guard + 1
);
true ->
case align_hour(Plan, Candidate) of
none ->
find_next(
Plan,
next_day_start(Candidate),
Guard + 1
);
{some, Aligned_hour} ->
case align_minute(Plan, Aligned_hour) of
none ->
find_next(
Plan,
next_hour_start(Aligned_hour),
Guard + 1
);
{some, Aligned_minute} ->
case automata@cron@evaluator:matches(
Plan,
Aligned_minute
) of
true ->
{some, Aligned_minute};
false ->
find_next(
Plan,
automata@internal@calendar:add_minutes(
Aligned_minute,
1
),
Guard + 1
)
end
end
end
end
end
end.
-file("src/automata/cron/iterator.gleam", 26).
-spec step(cron_iterator()) -> step().
step(Iterator) ->
case find_next(erlang:element(2, Iterator), erlang:element(3, Iterator), 0) of
{some, At} ->
{yield,
automata@schedule@ast:unsafe_assume_valid(At),
{cron_iterator,
erlang:element(2, Iterator),
automata@internal@calendar:add_minutes(At, 1)}};
none ->
done
end.