-module(gladvent@internal@cmd@run). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). -export([run_command/0, run_all_command/0]). -export_type([run_err/0, solve_err/0, direction/0, gleam_err/0]). -type run_err() :: {failed_to_read_input, binary()} | {unregistered, integer()} | {other, binary()}. -type solve_err() :: undef | {run_failed, binary()}. -type direction() :: both. -type gleam_err() :: {gleam_err, gleam@erlang@atom:atom_(), binary(), binary(), integer(), binary(), gleam@option:option(gleam@dynamic:dynamic_())}. -spec run_err_to_snag(run_err()) -> snag:snag(). run_err_to_snag(Err) -> _pipe = case Err of {unregistered, Day} -> <<<<<<<<"day"/utf8, " "/utf8>>/binary, (gleam@int:to_string(Day))/binary>>/binary, " "/utf8>>/binary, "unregistered"/utf8>>; {failed_to_read_input, Input_path} -> <<"failed to read input file: "/utf8, Input_path/binary>>; {other, S} -> S end, snag:new(_pipe). -spec string_trim(binary(), direction(), binary()) -> binary(). string_trim(S, Dir, Sub) -> string:trim(S, Dir, unicode:characters_to_list(Sub)). -spec crash_to_dyn(gleam@erlang:crash()) -> gleam@dynamic:dynamic_(). crash_to_dyn(Err) -> case Err of {errored, Dyn} -> Dyn; {exited, Dyn} -> Dyn; {thrown, Dyn} -> Dyn end. -spec decode_gleam_err() -> fun((gleam@dynamic:dynamic_()) -> {ok, gleam_err()} | {error, list(gleam@dynamic:decode_error())}). decode_gleam_err() -> gleam@dynamic:decode6( fun(Field@0, Field@1, Field@2, Field@3, Field@4, Field@5) -> {gleam_err, Field@0, Field@1, Field@2, Field@3, Field@4, Field@5} end, gleam@dynamic:field( erlang:binary_to_atom(<<"gleam_error"/utf8>>), fun gleam_erlang_ffi:atom_from_dynamic/1 ), gleam@dynamic:field( erlang:binary_to_atom(<<"module"/utf8>>), fun gleam@dynamic:string/1 ), gleam@dynamic:field( erlang:binary_to_atom(<<"function"/utf8>>), fun gleam@dynamic:string/1 ), gleam@dynamic:field( erlang:binary_to_atom(<<"line"/utf8>>), fun gleam@dynamic:int/1 ), gleam@dynamic:field( erlang:binary_to_atom(<<"message"/utf8>>), fun gleam@dynamic:string/1 ), gleam@dynamic:any( [gleam@dynamic:field( erlang:binary_to_atom(<<"value"/utf8>>), gleam@dynamic:optional(fun gleam@dynamic:dynamic/1) ), fun(_) -> {ok, none} end] ) ). -spec gleam_err_to_string(gleam_err()) -> binary(). gleam_err_to_string(G) -> gleam@string:join( [<<"error:"/utf8>>, erlang:atom_to_binary(erlang:element(2, G)), <<"-"/utf8>>, erlang:element(6, G), <<"in module"/utf8>>, erlang:element(3, G), <<"in function"/utf8>>, erlang:element(4, G), <<"at line"/utf8>>, gleam@int:to_string(erlang:element(5, G)), begin _pipe = erlang:element(7, G), _pipe@1 = gleam@option:map( _pipe, fun(Val) -> <<"with value "/utf8, (gleam@string:inspect(Val))/binary>> end ), gleam@option:unwrap(_pipe@1, <<""/utf8>>) end], <<" "/utf8>> ). -spec crash_to_string(gleam@erlang:crash()) -> solve_err(). crash_to_string(Err) -> _pipe = crash_to_dyn(Err), _pipe@1 = (decode_gleam_err())(_pipe), _pipe@2 = gleam@result:map(_pipe@1, fun gleam_err_to_string/1), _pipe@3 = gleam@result:lazy_unwrap( _pipe@2, fun() -> <<"run failed for some reason: "/utf8, (gleam@string:inspect(Err))/binary>> end ), {run_failed, _pipe@3}. -spec do( integer(), integer(), gleam@map:map_(integer(), {fun((binary()) -> gleam@dynamic:dynamic_()), fun((binary()) -> gleam@dynamic:dynamic_())}), boolean() ) -> {ok, {{ok, gleam@dynamic:dynamic_()} | {error, solve_err()}, {ok, gleam@dynamic:dynamic_()} | {error, solve_err()}}} | {error, run_err()}. do(Year, Day, Runners, Allow_crash) -> gleam@result:then( begin _pipe = Runners, _pipe@1 = gleam@map:get(_pipe, Day), gleam@result:replace_error(_pipe@1, {unregistered, Day}) end, fun(_use0) -> {Pt_1, Pt_2} = _use0, Input_path = <<<<<<<<"input/"/utf8, (gleam@int:to_string(Year))/binary>>/binary, "/"/utf8>>/binary, (gleam@int:to_string(Day))/binary>>/binary, ".txt"/utf8>>, gleam@result:then( begin _pipe@2 = Input_path, _pipe@3 = simplifile:read(_pipe@2), _pipe@4 = gleam@result:map( _pipe@3, fun(_capture) -> string_trim(_capture, both, <<"\n"/utf8>>) end ), gleam@result:replace_error( _pipe@4, {failed_to_read_input, Input_path} ) end, fun(Input) -> case Allow_crash of true -> {ok, {{ok, Pt_1(Input)}, {ok, Pt_2(Input)}}}; false -> Pt_1@1 = begin _pipe@5 = fun() -> Pt_1(Input) end, _pipe@6 = gleam_erlang_ffi:rescue(_pipe@5), gleam@result:map_error( _pipe@6, fun crash_to_string/1 ) end, Pt_2@1 = begin _pipe@7 = fun() -> Pt_2(Input) end, _pipe@8 = gleam_erlang_ffi:rescue(_pipe@7), gleam@result:map_error( _pipe@8, fun crash_to_string/1 ) end, {ok, {Pt_1@1, Pt_2@1}} end end ) end ). -spec solve_err_to_string(solve_err()) -> binary(). solve_err_to_string(Solve_err) -> case Solve_err of undef -> <<"function undefined"/utf8>>; {run_failed, S} -> S end. -spec solve_res_to_string({ok, gleam@dynamic:dynamic_()} | {error, solve_err()}) -> binary(). solve_res_to_string(Res) -> case Res of {ok, Res@1} -> gleam@string:inspect(Res@1); {error, Err} -> solve_err_to_string(Err) end. -spec collect( integer(), {integer(), {ok, {{ok, gleam@dynamic:dynamic_()} | {error, solve_err()}, {ok, gleam@dynamic:dynamic_()} | {error, solve_err()}}} | {error, run_err()}} ) -> binary(). collect(Year, X) -> Day = gleam@int:to_string(erlang:element(1, X)), case erlang:element(2, X) of {ok, {Res_1, Res_2}} -> <<<<<<<<<<<<<<<<<<"Ran "/utf8, (gleam@int:to_string(Year))/binary>>/binary, " day "/utf8>>/binary, Day/binary>>/binary, ":\n"/utf8>>/binary, " Part 1: "/utf8>>/binary, (solve_res_to_string(Res_1))/binary>>/binary, "\n"/utf8>>/binary, " Part 2: "/utf8>>/binary, (solve_res_to_string(Res_2))/binary>>; {error, Err} -> _pipe = Err, _pipe@1 = run_err_to_snag(_pipe), _pipe@2 = snag:layer( _pipe@1, <<<<<<"Failed to run "/utf8, (gleam@int:to_string(Year))/binary>>/binary, " day "/utf8>>/binary, Day/binary>> ), snag:pretty_print(_pipe@2) end. -spec collect_async( integer(), {integer(), {ok, {ok, {{ok, gleam@dynamic:dynamic_()} | {error, solve_err()}, {ok, gleam@dynamic:dynamic_()} | {error, solve_err()}}} | {error, run_err()}} | {error, binary()}} ) -> binary(). collect_async(Year, X) -> _pipe = X, _pipe@1 = gleam@pair:map_second( _pipe, fun(_capture) -> gleam@result:map_error( _capture, fun(Field@0) -> {other, Field@0} end ) end ), _pipe@2 = gleam@pair:map_second(_pipe@1, fun gleam@result:flatten/1), collect(Year, _pipe@2). -spec timeout_flag() -> glint@flag:flag_builder(integer()). timeout_flag() -> _pipe = glint@flag:int(), _pipe@1 = glint@flag:constraint(_pipe, fun(I) -> case I > 0 of true -> {ok, nil}; false -> snag:error(<<"timeout value must greater than zero"/utf8>>) end end), glint@flag:description(_pipe@1, <<"Run with specified timeout"/utf8>>). -spec allow_crash_flag() -> glint@flag:flag_builder(boolean()). allow_crash_flag() -> _pipe = glint@flag:bool(), _pipe@1 = glint@flag:default(_pipe, false), glint@flag:description( _pipe@1, <<"Don't catch exceptions thrown by runners"/utf8>> ). -spec timing(gleam@map:map_(binary(), glint@flag:flag())) -> gladvent@internal@cmd:timing(). timing(Flags) -> _pipe = glint@flag:get_int(Flags, <<"timeout"/utf8>>), _pipe@1 = gleam@result:map(_pipe, fun(Field@0) -> {ending, Field@0} end), gleam@result:unwrap(_pipe@1, endless). -spec run_command() -> glint:command({ok, list(binary())} | {error, snag:snag()}). run_command() -> _pipe@2 = (glint:command( fun(Input) -> _assert_subject = glint@flag:get_int( erlang:element(3, Input), <<"year"/utf8>> ), {ok, Year} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"gladvent/internal/cmd/run"/utf8>>, function => <<"run_command"/utf8>>, line => 228}) end, gleam@result:then( gladvent@internal@runners:build_from_days_dir(Year), fun(Runners) -> gleam@result:'try'( glint@flag:get_bool( erlang:element(3, Input), <<"allow-crash"/utf8>> ), fun(Allow_crash) -> gleam@result:then( gladvent@internal@parse:days( erlang:element(2, Input) ), fun(Days) -> _pipe = Days, _pipe@1 = gladvent@internal@cmd:exec( _pipe, timing(erlang:element(3, Input)), fun(_capture) -> do( Year, _capture, Runners, Allow_crash ) end, fun(_capture@1) -> collect_async(Year, _capture@1) end ), {ok, _pipe@1} end ) end ) end ) end )), _pipe@3 = glint:flag(_pipe@2, <<"timeout"/utf8>>, timeout_flag()), _pipe@4 = glint:flag(_pipe@3, <<"allow-crash"/utf8>>, allow_crash_flag()), glint:description(_pipe@4, <<"Run the specified days"/utf8>>). -spec all_days(gleam@map:map_(integer(), any())) -> list(integer()). all_days(Runners) -> _pipe = Runners, _pipe@1 = gleam@map:keys(_pipe), gleam@list:sort(_pipe@1, fun gleam@int:compare/2). -spec run_all_command() -> glint:command({ok, list(binary())} | {error, snag:snag()}). run_all_command() -> _pipe@3 = (glint:command( fun(Input) -> gleam@result:then( glint@flag:get_bool( erlang:element(3, Input), <<"allow-crash"/utf8>> ), fun(Allow_crash) -> _assert_subject = glint@flag:get_int( erlang:element(3, Input), <<"year"/utf8>> ), {ok, Year} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"gladvent/internal/cmd/run"/utf8>>, function => <<"run_all_command"/utf8>>, line => 250}) end, gleam@result:then( gladvent@internal@runners:build_from_days_dir(Year), fun(Runners) -> _pipe = Runners, _pipe@1 = all_days(_pipe), _pipe@2 = gladvent@internal@cmd:exec( _pipe@1, timing(erlang:element(3, Input)), fun(_capture) -> do(Year, _capture, Runners, Allow_crash) end, fun(_capture@1) -> collect_async(Year, _capture@1) end ), {ok, _pipe@2} end ) end ) end )), _pipe@4 = glint:flag(_pipe@3, <<"timeout"/utf8>>, timeout_flag()), _pipe@5 = glint:flag(_pipe@4, <<"allow-crash"/utf8>>, allow_crash_flag()), glint:description(_pipe@5, <<"Run all registered days"/utf8>>).