-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.