-module(glint@flag). -compile(no_auto_import). -export([int/2, float/2, float_list/2, int_list/2, string/2, string_list/2, bool/2, build_map/1, update_flags/2]). -export_type([flag_value/0, flag/0]). -type flag_value() :: {b, boolean()} | {i, integer()} | {li, list(integer())} | {f, float()} | {lf, list(float())} | {s, binary()} | {ls, list(binary())}. -type flag() :: {flag, binary(), flag_value()}. -spec int(binary(), integer()) -> flag(). int(Name, Value) -> {flag, Name, {i, Value}}. -spec float(binary(), float()) -> flag(). float(Name, Value) -> {flag, Name, {f, Value}}. -spec float_list(binary(), list(float())) -> flag(). float_list(Name, Value) -> {flag, Name, {lf, Value}}. -spec int_list(binary(), list(integer())) -> flag(). int_list(Name, Value) -> {flag, Name, {li, Value}}. -spec string(binary(), binary()) -> flag(). string(Name, Value) -> {flag, Name, {s, Value}}. -spec string_list(binary(), list(binary())) -> flag(). string_list(Name, Value) -> {flag, Name, {ls, Value}}. -spec bool(binary(), boolean()) -> flag(). bool(Name, Value) -> {flag, Name, {b, Value}}. -spec build_map(list(flag())) -> gleam@map:map_(binary(), flag_value()). build_map(Flags) -> gleam@list:fold( Flags, gleam@map:new(), fun(M, Flag) -> gleam@map:insert( M, erlang:element(2, Flag), erlang:element(3, Flag) ) end ). -spec update_flags(gleam@map:map_(binary(), flag_value()), binary()) -> {ok, gleam@map:map_(binary(), flag_value())} | {error, snag:snag()}. update_flags(Flags, Flag_input) -> Flag_input@1 = gleam@string:drop_left(Flag_input, 2), case gleam@string:split_once(Flag_input@1, <<"="/utf8>>) of {error, _@1} -> case begin _pipe = gleam@map:get(Flags, Flag_input@1), gleam@result:replace_error( _pipe, undefined_flag_err(Flag_input@1) ) end of {error, _try} -> {error, _try}; {ok, Default} -> case Default of {b, Val} -> {ok, gleam@map:insert( Flags, Flag_input@1, {b, gleam@bool:negate(Val)} )}; _@2 -> {error, no_value_flag_err(Flag_input@1)} end end; {ok, {Key, Value}} -> case begin _pipe@1 = gleam@map:get(Flags, Key), gleam@result:replace_error(_pipe@1, undefined_flag_err(Key)) end of {error, _try@1} -> {error, _try@1}; {ok, Default@1} -> _pipe@2 = case Default@1 of {i, _@3} -> fun parse_int/2; {li, _@4} -> fun parse_int_list/2; {f, _@5} -> fun parse_float/2; {lf, _@6} -> fun parse_float_list/2; {s, _@7} -> fun parse_string/2; {ls, _@8} -> fun parse_string_list/2; {b, _@9} -> fun parse_bool/2 end(Key, Value), gleam@result:map( _pipe@2, fun(_capture) -> gleam@map:insert(Flags, Key, _capture) end ) end end. -spec parse_int(binary(), binary()) -> {ok, flag_value()} | {error, snag:snag()}. parse_int(Key, Value) -> _pipe = parse_flag(Value, fun gleam@int:parse/1, fun(A) -> {i, A} end), gleam@result:replace_error(_pipe, cannot_parse(Key, Value, <<"int"/utf8>>)). -spec parse_int_list(binary(), binary()) -> {ok, flag_value()} | {error, snag:snag()}. parse_int_list(Key, Value) -> _pipe = parse_list_flag(Value, fun gleam@int:parse/1, fun(A) -> {li, A} end), gleam@result:replace_error( _pipe, cannot_parse(Key, Value, <<"int list"/utf8>>) ). -spec parse_float(binary(), binary()) -> {ok, flag_value()} | {error, snag:snag()}. parse_float(Key, Value) -> _pipe = parse_flag(Value, fun gleam@float:parse/1, fun(A) -> {f, A} end), gleam@result:replace_error( _pipe, cannot_parse(Key, Value, <<"float"/utf8>>) ). -spec parse_float_list(binary(), binary()) -> {ok, flag_value()} | {error, snag:snag()}. parse_float_list(Key, Value) -> _pipe = parse_list_flag( Value, fun gleam@float:parse/1, fun(A) -> {lf, A} end ), gleam@result:replace_error( _pipe, cannot_parse(Key, Value, <<"float list"/utf8>>) ). -spec parse_bool(binary(), binary()) -> {ok, flag_value()} | {error, snag:snag()}. parse_bool(Key, Value) -> case Value of <<"true"/utf8>> -> {ok, {b, true}}; <<"false"/utf8>> -> {ok, {b, false}}; _@1 -> {error, cannot_parse(Key, Value, <<"bool"/utf8>>)} end. -spec parse_string(binary(), binary()) -> {ok, flag_value()} | {error, snag:snag()}. parse_string(_, Value) -> parse_flag(Value, fun(A) -> {ok, A} end, fun(A) -> {s, A} end). -spec parse_string_list(binary(), binary()) -> {ok, flag_value()} | {error, snag:snag()}. parse_string_list(_, Value) -> parse_list_flag(Value, fun(A) -> {ok, A} end, fun(A) -> {ls, A} end). -spec parse_flag( binary(), fun((binary()) -> {ok, EGC} | {error, EGD}), fun((EGC) -> flag_value()) ) -> {ok, flag_value()} | {error, EGD}. parse_flag(Value, Parse, Construct) -> _pipe = Value, _pipe@1 = Parse(_pipe), gleam@result:map(_pipe@1, Construct). -spec parse_list_flag( binary(), fun((binary()) -> {ok, EGI} | {error, EGJ}), fun((list(EGI)) -> flag_value()) ) -> {ok, flag_value()} | {error, EGJ}. parse_list_flag(Value, Parse, Construct) -> _pipe = Value, _pipe@1 = gleam@string:split(_pipe, <<","/utf8>>), _pipe@2 = gleam@list:try_map(_pipe@1, Parse), gleam@result:map(_pipe@2, Construct). -spec layer_invalid_flag(snag:snag(), binary()) -> snag:snag(). layer_invalid_flag(Err, Flag) -> _pipe = [<<"invalid flag '"/utf8>>, Flag, <<"'"/utf8>>], _pipe@1 = gleam@string:concat(_pipe), snag:layer(Err, _pipe@1). -spec no_value_flag_err(binary()) -> snag:snag(). no_value_flag_err(Flag_input) -> _pipe = [<<"flag '"/utf8>>, Flag_input, <<"' has no assigned value"/utf8>>], _pipe@1 = gleam@string:concat(_pipe), _pipe@2 = snag:new(_pipe@1), layer_invalid_flag(_pipe@2, Flag_input). -spec undefined_flag_err(binary()) -> snag:snag(). undefined_flag_err(Key) -> _pipe = <<"flag provided but not defined"/utf8>>, _pipe@1 = snag:new(_pipe), layer_invalid_flag(_pipe@1, Key). -spec cannot_parse(binary(), binary(), binary()) -> snag:snag(). cannot_parse(Key, Value, Kind) -> _pipe = [<<"cannot parse flag '"/utf8>>, Key, <<"' value '"/utf8>>, Value, <<"' as "/utf8>>, Kind], _pipe@1 = gleam@string:concat(_pipe), _pipe@2 = snag:new(_pipe@1), layer_invalid_flag(_pipe@2, Key).