-module(outcome). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new_defect/1, new_failure/1, error_with_defect/1, error_with_failure/1, into_defect/1, into_failure/1, map_into_defect/2, as_defect/2, as_failure/2, problem_with_defect/2, with_defect/2, problem_with_failure/2, with_failure/2, add_to_problem_stack/2, add_context_to_problem/2, with_context/2, add_failure_to_problem_stack/2, add_defect_to_problem_stack/2, outcome_to_lines/1, pretty_print/1, pretty_print_outcome/1]). -export_type([problem/0, stack_entry/0]). -type problem() :: {defect, binary(), non_empty_list:non_empty_list(stack_entry())} | {failure, binary(), non_empty_list:non_empty_list(stack_entry())}. -type stack_entry() :: {stack_entry_context, binary()} | {stack_entry_defect, binary()} | {stack_entry_failure, binary()}. -spec new_defect(binary()) -> problem(). new_defect(Message) -> {defect, Message, non_empty_list:single({stack_entry_defect, Message})}. -spec new_failure(binary()) -> problem(). new_failure(Message) -> {failure, Message, non_empty_list:single({stack_entry_failure, Message})}. -spec error_with_defect(binary()) -> {ok, any()} | {error, problem()}. error_with_defect(Defect) -> {error, new_defect(Defect)}. -spec error_with_failure(binary()) -> {ok, any()} | {error, problem()}. error_with_failure(Failure) -> {error, new_failure(Failure)}. -spec into_defect({ok, GIN} | {error, binary()}) -> {ok, GIN} | {error, problem()}. into_defect(Result) -> gleam@result:map_error(Result, fun new_defect/1). -spec into_failure({ok, GIR} | {error, binary()}) -> {ok, GIR} | {error, problem()}. into_failure(Result) -> gleam@result:map_error(Result, fun new_failure/1). -spec map_into_defect({ok, GIV} | {error, GIW}, fun((GIW) -> binary())) -> {ok, GIV} | {error, problem()}. map_into_defect(Result, Mapper) -> _pipe = Result, _pipe@1 = gleam@result:map_error(_pipe, Mapper), into_defect(_pipe@1). -spec as_defect({ok, GJA} | {error, nil}, binary()) -> {ok, GJA} | {error, problem()}. as_defect(Result, E) -> gleam@result:replace_error(Result, new_defect(E)). -spec as_failure({ok, GJE} | {error, nil}, binary()) -> {ok, GJE} | {error, problem()}. as_failure(Result, E) -> gleam@result:replace_error(Result, new_failure(E)). -spec push_to_stack(non_empty_list:non_empty_list(stack_entry()), stack_entry()) -> non_empty_list:non_empty_list(stack_entry()). push_to_stack(Stack, Entry) -> non_empty_list:prepend(Stack, Entry). -spec problem_with_defect(problem(), binary()) -> problem(). problem_with_defect(Problem, Defect_message) -> case Problem of {defect, Current_defect_message, Stack} -> {defect, Current_defect_message, push_to_stack(Stack, {stack_entry_defect, Defect_message})}; {failure, _, Stack@1} -> {defect, Defect_message, push_to_stack(Stack@1, {stack_entry_defect, Defect_message})} end. -spec with_defect({ok, GJL} | {error, problem()}, binary()) -> {ok, GJL} | {error, problem()}. with_defect(Outcome, Defect_message) -> gleam@result:map_error( Outcome, fun(_capture) -> problem_with_defect(_capture, Defect_message) end ). -spec problem_with_failure(problem(), binary()) -> problem(). problem_with_failure(Problem, Failure_message) -> case Problem of {defect, Current_defect_message, Stack} -> {defect, Current_defect_message, push_to_stack(Stack, {stack_entry_failure, Failure_message})}; {failure, _, Stack@1} -> {failure, Failure_message, push_to_stack(Stack@1, {stack_entry_failure, Failure_message})} end. -spec with_failure({ok, GJO} | {error, problem()}, binary()) -> {ok, GJO} | {error, problem()}. with_failure(Outcome, Failure_message) -> gleam@result:map_error( Outcome, fun(_capture) -> problem_with_failure(_capture, Failure_message) end ). -spec add_to_problem_stack(problem(), stack_entry()) -> problem(). add_to_problem_stack(Problem, Stack_entry) -> case Problem of {defect, Problem@1, Stack} -> {defect, Problem@1, push_to_stack(Stack, Stack_entry)}; {failure, Problem@2, Stack@1} -> {failure, Problem@2, push_to_stack(Stack@1, Stack_entry)} end. -spec add_context_to_problem(problem(), binary()) -> problem(). add_context_to_problem(Problem, Value) -> add_to_problem_stack(Problem, {stack_entry_context, Value}). -spec with_context({ok, GJI} | {error, problem()}, binary()) -> {ok, GJI} | {error, problem()}. with_context(Outcome, Context) -> gleam@result:map_error( Outcome, fun(Problem) -> add_context_to_problem(Problem, Context) end ). -spec add_failure_to_problem_stack(problem(), binary()) -> problem(). add_failure_to_problem_stack(Problem, Failure) -> add_to_problem_stack(Problem, {stack_entry_failure, Failure}). -spec add_defect_to_problem_stack(problem(), binary()) -> problem(). add_defect_to_problem_stack(Problem, Failure) -> add_to_problem_stack(Problem, {stack_entry_failure, Failure}). -spec prettry_print_problem_value(problem()) -> binary(). prettry_print_problem_value(Problem) -> case Problem of {defect, Value, _} -> <<"Defect: "/utf8, Value/binary>>; {failure, Value@1, _} -> <<"Failure: "/utf8, Value@1/binary>> end. -spec pretty_print_stack_entry(stack_entry()) -> binary(). pretty_print_stack_entry(Entry) -> case Entry of {stack_entry_context, Value} -> <<"Context: "/utf8, Value/binary>>; {stack_entry_defect, Value@1} -> <<"Defect: "/utf8, Value@1/binary>>; {stack_entry_failure, Value@2} -> <<"Failure: "/utf8, Value@2/binary>> end. -spec stack_to_lines(non_empty_list:non_empty_list(stack_entry())) -> list(binary()). stack_to_lines(Stack) -> _pipe = Stack, _pipe@1 = non_empty_list:to_list(_pipe), gleam@list:map(_pipe@1, fun pretty_print_stack_entry/1). -spec outcome_to_lines({ok, any()} | {error, problem()}) -> list(binary()). outcome_to_lines(Outcome) -> case Outcome of {ok, _} -> []; {error, Problem} -> stack_to_lines(erlang:element(3, Problem)) end. -spec pretty_print(problem()) -> binary(). pretty_print(Problem) -> Stack = begin _pipe = erlang:element(3, Problem), _pipe@1 = stack_to_lines(_pipe), gleam@string:join(_pipe@1, <<"\n "/utf8>>) end, <<<<(prettry_print_problem_value(Problem))/binary, "\n\nstack:\n "/utf8>>/binary, Stack/binary>>. -spec pretty_print_outcome({ok, any()} | {error, problem()}) -> binary(). pretty_print_outcome(Outcome) -> case Outcome of {ok, _} -> <<"Ok"/utf8>>; {error, Problem} -> pretty_print(Problem) end.