Current section

Files

Jump to
glint src glint@flag.erl
Raw

src/glint@flag.erl

-module(glint@flag).
-compile([no_auto_import, nowarn_unused_vars]).
-export([new/1, build/1, description/2, constraint/2, default/2, build_map/1, flag_type_help/1, flags_help/1, update_flags/2, get_int_value/1, get_int/2, get_ints_value/1, get_ints/2, get_bool_value/1, get_bool/2, get_string_value/1, get_string/2, get_strings_value/1, get_strings/2, get_float_value/1, get_float/2, get_floats_value/1, get_floats/2]).
-export_type([value/0, internal/1, flag/0]).
-type value() :: {b, internal(boolean())} |
{i, internal(integer())} |
{li, internal(list(integer()))} |
{f, internal(float())} |
{lf, internal(list(float()))} |
{s, internal(binary())} |
{ls, internal(list(binary()))}.
-opaque internal(FYO) :: {internal,
gleam@option:option(FYO),
list(fun((FYO) -> {ok, nil} | {error, snag:snag()}))}.
-type flag() :: {flag, value(), binary()}.
-spec new(fun((internal(FYV)) -> value())) -> fun((internal(FYV)) -> flag()).
new(New) ->
fun(Internal) -> {flag, New(Internal), <<""/utf8>>} end.
-spec build(fun((internal(any())) -> flag())) -> flag().
build(New) ->
New({internal, none, []}).
-spec description(fun((internal(FZA)) -> flag()), binary()) -> fun((internal(FZA)) -> flag()).
description(Flag, Description) ->
fun(Internal) -> erlang:setelement(3, Flag(Internal), Description) end.
-spec constraint(
fun((internal(FZD)) -> flag()),
fun((FZD) -> {ok, nil} | {error, snag:snag()})
) -> fun((internal(FZD)) -> flag()).
constraint(Flag, Constraint) ->
fun(Internal) ->
Flag(
erlang:setelement(
3,
Internal,
[Constraint | erlang:element(3, Internal)]
)
)
end.
-spec default(fun((internal(FZH)) -> flag()), FZH) -> fun((internal(FZH)) -> flag()).
default(Val, Default) ->
fun(Internal) -> Val(erlang:setelement(2, Internal, {some, Default})) end.
-spec build_map(list({binary(), flag()})) -> gleam@map:map_(binary(), flag()).
build_map(Flags) ->
gleam@map:from_list(Flags).
-spec access_type_error(binary(), binary()) -> {ok, any()} |
{error, snag:snag()}.
access_type_error(Name, Flag_type) ->
snag:error(
<<<<<<"cannot access flag '"/utf8, Name/binary>>/binary, "' as "/utf8>>/binary,
Flag_type/binary>>
).
-spec flag_not_provided_error(binary()) -> {ok, any()} | {error, snag:snag()}.
flag_not_provided_error(Name) ->
snag:error(
<<<<"value for flag '"/utf8, Name/binary>>/binary,
"' not provided"/utf8>>
).
-spec apply_constraints(
binary(),
FZT,
list(fun((FZT) -> {ok, nil} | {error, snag:snag()}))
) -> {ok, FZT} | {error, snag:snag()}.
apply_constraints(Name, Val, Constraints) ->
_pipe = Constraints,
_pipe@1 = gleam@list:try_map(
_pipe,
fun(_capture) -> gleam@function:apply1(_capture, Val) end
),
_pipe@2 = snag:context(
_pipe@1,
<<<<"value for flag '"/utf8, Name/binary>>/binary,
"' does not satisfy constraints"/utf8>>
),
gleam@result:replace(_pipe@2, Val).
-spec parse_string(binary(), binary(), internal(binary())) -> {ok, value()} |
{error, snag:snag()}.
parse_string(Key, Value, Internal) ->
_pipe = apply_constraints(Key, Value, erlang:element(3, Internal)),
gleam@result:replace(
_pipe,
{s, erlang:setelement(2, Internal, {some, Value})}
).
-spec parse_string_list(binary(), binary(), internal(list(binary()))) -> {ok,
value()} |
{error, snag:snag()}.
parse_string_list(Key, Value, Internal) ->
Value@1 = gleam@string:split(Value, <<","/utf8>>),
_pipe = Value@1,
_pipe@1 = apply_constraints(Key, _pipe, erlang:element(3, Internal)),
gleam@result:replace(
_pipe@1,
{ls, erlang:setelement(2, Internal, {some, Value@1})}
).
-spec layer_invalid_flag(snag:snag(), binary()) -> snag:snag().
layer_invalid_flag(Err, Flag) ->
snag:layer(
Err,
<<<<"invalid flag '"/utf8, Flag/binary>>/binary,
((<<"'"/utf8>>))/binary>>
).
-spec no_value_flag_err(binary()) -> snag:snag().
no_value_flag_err(Flag_input) ->
_pipe = (<<<<"flag '"/utf8, Flag_input/binary>>/binary,
"' has no assigned value"/utf8>>),
_pipe@1 = snag:new(_pipe),
layer_invalid_flag(_pipe@1, 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/binary>>/binary,
"' value '"/utf8>>/binary,
Value/binary>>/binary,
"' as "/utf8>>/binary,
Kind/binary>>),
_pipe@1 = snag:new(_pipe),
layer_invalid_flag(_pipe@1, Key).
-spec parse_int(binary(), binary(), internal(integer())) -> {ok, value()} |
{error, snag:snag()}.
parse_int(Key, Value, Internal) ->
gleam@result:'try'(
begin
_pipe = gleam@int:parse(Value),
gleam@result:replace_error(
_pipe,
cannot_parse(Key, Value, <<"int"/utf8>>)
)
end,
fun(I) ->
_pipe@1 = apply_constraints(Key, I, erlang:element(3, Internal)),
gleam@result:replace(
_pipe@1,
{i, erlang:setelement(2, Internal, {some, I})}
)
end
).
-spec parse_int_list(binary(), binary(), internal(list(integer()))) -> {ok,
value()} |
{error, snag:snag()}.
parse_int_list(Key, Value, Internal) ->
gleam@result:'try'(
begin
_pipe = Value,
_pipe@1 = gleam@string:split(_pipe, <<","/utf8>>),
_pipe@2 = gleam@list:try_map(_pipe@1, fun gleam@int:parse/1),
gleam@result:replace_error(
_pipe@2,
cannot_parse(Key, Value, <<"int list"/utf8>>)
)
end,
fun(Li) ->
_pipe@3 = apply_constraints(Key, Li, erlang:element(3, Internal)),
gleam@result:replace(
_pipe@3,
{li, erlang:setelement(2, Internal, {some, Li})}
)
end
).
-spec parse_float(binary(), binary(), internal(float())) -> {ok, value()} |
{error, snag:snag()}.
parse_float(Key, Value, Internal) ->
gleam@result:'try'(
begin
_pipe = gleam@float:parse(Value),
gleam@result:replace_error(
_pipe,
cannot_parse(Key, Value, <<"float"/utf8>>)
)
end,
fun(F) ->
_pipe@1 = apply_constraints(Key, F, erlang:element(3, Internal)),
gleam@result:replace(
_pipe@1,
{f, erlang:setelement(2, Internal, {some, F})}
)
end
).
-spec parse_float_list(binary(), binary(), internal(list(float()))) -> {ok,
value()} |
{error, snag:snag()}.
parse_float_list(Key, Value, Internal) ->
gleam@result:'try'(
begin
_pipe = Value,
_pipe@1 = gleam@string:split(_pipe, <<","/utf8>>),
_pipe@2 = gleam@list:try_map(_pipe@1, fun gleam@float:parse/1),
gleam@result:replace_error(
_pipe@2,
cannot_parse(Key, Value, <<"float list"/utf8>>)
)
end,
fun(Lf) ->
_pipe@3 = apply_constraints(Key, Lf, erlang:element(3, Internal)),
gleam@result:replace(
_pipe@3,
{lf, erlang:setelement(2, Internal, {some, Lf})}
)
end
).
-spec parse_bool(binary(), binary(), internal(boolean())) -> {ok, value()} |
{error, snag:snag()}.
parse_bool(Key, Value, Internal) ->
gleam@result:'try'(case gleam@string:lowercase(Value) of
<<"true"/utf8>> ->
{ok, true};
<<"t"/utf8>> ->
{ok, true};
<<"false"/utf8>> ->
{ok, false};
<<"f"/utf8>> ->
{ok, false};
_ ->
{error, cannot_parse(Key, Value, <<"bool"/utf8>>)}
end, fun(Val) ->
_pipe = apply_constraints(Key, Val, erlang:element(3, Internal)),
gleam@result:replace(
_pipe,
{b, erlang:setelement(2, Internal, {some, Val})}
)
end).
-spec compute_flag(binary(), binary(), value()) -> {ok, value()} |
{error, snag:snag()}.
compute_flag(Name, Input, Default) ->
case Default of
{i, Internal} ->
parse_int(Name, Input, Internal);
{li, Internal@1} ->
parse_int_list(Name, Input, Internal@1);
{f, Internal@2} ->
parse_float(Name, Input, Internal@2);
{lf, Internal@3} ->
parse_float_list(Name, Input, Internal@3);
{s, Internal@4} ->
parse_string(Name, Input, Internal@4);
{ls, Internal@5} ->
parse_string_list(Name, Input, Internal@5);
{b, Internal@6} ->
parse_bool(Name, Input, Internal@6)
end.
-spec flag_type_help({binary(), flag()}) -> binary().
flag_type_help(Flag) ->
{Name, Contents} = Flag,
Kind = case erlang:element(2, Contents) of
{i, _} ->
<<"INT"/utf8>>;
{b, _} ->
<<"BOOL"/utf8>>;
{f, _} ->
<<"FLOAT"/utf8>>;
{lf, _} ->
<<"FLOAT_LIST"/utf8>>;
{li, _} ->
<<"INT_LIST"/utf8>>;
{ls, _} ->
<<"STRING_LIST"/utf8>>;
{s, _} ->
<<"STRING"/utf8>>
end,
<<<<<<<<<<"--"/utf8, Name/binary>>/binary, "="/utf8>>/binary, "<"/utf8>>/binary,
Kind/binary>>/binary,
">"/utf8>>.
-spec flag_help({binary(), flag()}) -> binary().
flag_help(Flag) ->
<<<<(flag_type_help(Flag))/binary, "\t\t"/utf8>>/binary,
(erlang:element(3, (erlang:element(2, Flag))))/binary>>.
-spec flags_help(gleam@map:map_(binary(), flag())) -> list(binary()).
flags_help(Flags) ->
_pipe = Flags,
_pipe@1 = gleam@map:to_list(_pipe),
gleam@list:map(_pipe@1, fun flag_help/1).
-spec access(gleam@map:map_(binary(), flag()), binary()) -> {ok, flag()} |
{error, snag:snag()}.
access(Flags, Name) ->
_pipe = gleam@map:get(Flags, Name),
gleam@result:replace_error(_pipe, undefined_flag_err(Name)).
-spec update_flag_value(gleam@map:map_(binary(), flag()), {binary(), binary()}) -> {ok,
gleam@map:map_(binary(), flag())} |
{error, snag:snag()}.
update_flag_value(Flags, Data) ->
{Key, Input} = Data,
gleam@result:'try'(
access(Flags, Key),
fun(Contents) ->
gleam@result:map(
compute_flag(Key, Input, erlang:element(2, Contents)),
fun(Value) ->
gleam@map:insert(
Flags,
Key,
erlang:setelement(2, Contents, Value)
)
end
)
end
).
-spec attempt_toggle_flag(gleam@map:map_(binary(), flag()), binary()) -> {ok,
gleam@map:map_(binary(), flag())} |
{error, snag:snag()}.
attempt_toggle_flag(Flags, Key) ->
gleam@result:'try'(
access(Flags, Key),
fun(Contents) -> case erlang:element(2, Contents) of
{b, {internal, none, _} = Internal} ->
_pipe = erlang:setelement(2, Internal, {some, true}),
_pipe@1 = {b, _pipe},
_pipe@2 = (fun(Val) ->
erlang:setelement(2, Contents, Val)
end)(_pipe@1),
_pipe@3 = gleam@map:insert(Flags, Key, _pipe@2),
{ok, _pipe@3};
{b, {internal, {some, Val@1}, _} = Internal@1} ->
_pipe@4 = erlang:setelement(
2,
Internal@1,
{some, not Val@1}
),
_pipe@5 = {b, _pipe@4},
_pipe@6 = (fun(Val@2) ->
erlang:setelement(2, Contents, Val@2)
end)(_pipe@5),
_pipe@7 = gleam@map:insert(Flags, Key, _pipe@6),
{ok, _pipe@7};
_ ->
{error, no_value_flag_err(Key)}
end end
).
-spec update_flags(gleam@map:map_(binary(), flag()), binary()) -> {ok,
gleam@map:map_(binary(), flag())} |
{error, snag:snag()}.
update_flags(Flags, Flag_input) ->
Flag_input@1 = gleam@string:drop_left(
Flag_input,
gleam@string:length(<<"--"/utf8>>)
),
case gleam@string:split_once(Flag_input@1, <<"="/utf8>>) of
{ok, Data} ->
update_flag_value(Flags, Data);
{error, _} ->
attempt_toggle_flag(Flags, Flag_input@1)
end.
-spec get_int_value({binary(), flag()}) -> {ok, integer()} |
{error, snag:snag()}.
get_int_value(Flag) ->
case erlang:element(2, (erlang:element(2, Flag))) of
{i, {internal, {some, Val}, _}} ->
{ok, Val};
{i, {internal, none, _}} ->
flag_not_provided_error(erlang:element(1, Flag));
_ ->
access_type_error(erlang:element(1, Flag), <<"int"/utf8>>)
end.
-spec get_int(gleam@map:map_(binary(), flag()), binary()) -> {ok, integer()} |
{error, snag:snag()}.
get_int(Flags, Name) ->
gleam@result:'try'(
access(Flags, Name),
fun(Value) -> get_int_value({Name, Value}) end
).
-spec get_ints_value({binary(), flag()}) -> {ok, list(integer())} |
{error, snag:snag()}.
get_ints_value(Flag) ->
case erlang:element(2, (erlang:element(2, Flag))) of
{li, {internal, {some, Val}, _}} ->
{ok, Val};
{li, {internal, none, _}} ->
flag_not_provided_error(erlang:element(1, Flag));
_ ->
access_type_error(erlang:element(1, Flag), <<"int list"/utf8>>)
end.
-spec get_ints(gleam@map:map_(binary(), flag()), binary()) -> {ok,
list(integer())} |
{error, snag:snag()}.
get_ints(Flags, Name) ->
gleam@result:'try'(
access(Flags, Name),
fun(Value) -> get_ints_value({Name, Value}) end
).
-spec get_bool_value({binary(), flag()}) -> {ok, boolean()} |
{error, snag:snag()}.
get_bool_value(Flag) ->
case erlang:element(2, (erlang:element(2, Flag))) of
{b, {internal, {some, Val}, _}} ->
{ok, Val};
{b, {internal, none, _}} ->
flag_not_provided_error(erlang:element(1, Flag));
_ ->
access_type_error(erlang:element(1, Flag), <<"bool"/utf8>>)
end.
-spec get_bool(gleam@map:map_(binary(), flag()), binary()) -> {ok, boolean()} |
{error, snag:snag()}.
get_bool(Flags, Name) ->
gleam@result:'try'(
access(Flags, Name),
fun(Value) -> get_bool_value({Name, Value}) end
).
-spec get_string_value({binary(), flag()}) -> {ok, binary()} |
{error, snag:snag()}.
get_string_value(Flag) ->
case erlang:element(2, (erlang:element(2, Flag))) of
{s, {internal, {some, Val}, _}} ->
{ok, Val};
{s, {internal, none, _}} ->
flag_not_provided_error(erlang:element(1, Flag));
_ ->
access_type_error(erlang:element(1, Flag), <<"string"/utf8>>)
end.
-spec get_string(gleam@map:map_(binary(), flag()), binary()) -> {ok, binary()} |
{error, snag:snag()}.
get_string(Flags, Name) ->
gleam@result:'try'(
access(Flags, Name),
fun(Value) -> get_string_value({Name, Value}) end
).
-spec get_strings_value({binary(), flag()}) -> {ok, list(binary())} |
{error, snag:snag()}.
get_strings_value(Flag) ->
case erlang:element(2, (erlang:element(2, Flag))) of
{ls, {internal, {some, Val}, _}} ->
{ok, Val};
{ls, {internal, none, _}} ->
flag_not_provided_error(erlang:element(1, Flag));
_ ->
access_type_error(erlang:element(1, Flag), <<"string list"/utf8>>)
end.
-spec get_strings(gleam@map:map_(binary(), flag()), binary()) -> {ok,
list(binary())} |
{error, snag:snag()}.
get_strings(Flags, Name) ->
gleam@result:'try'(
access(Flags, Name),
fun(Value) -> get_strings_value({Name, Value}) end
).
-spec get_float_value({binary(), flag()}) -> {ok, float()} |
{error, snag:snag()}.
get_float_value(Flag) ->
case erlang:element(2, (erlang:element(2, Flag))) of
{f, {internal, {some, Val}, _}} ->
{ok, Val};
{f, {internal, none, _}} ->
flag_not_provided_error(erlang:element(1, Flag));
_ ->
access_type_error(erlang:element(1, Flag), <<"float"/utf8>>)
end.
-spec get_float(gleam@map:map_(binary(), flag()), binary()) -> {ok, float()} |
{error, snag:snag()}.
get_float(Flags, Name) ->
gleam@result:'try'(
access(Flags, Name),
fun(Value) -> get_float_value({Name, Value}) end
).
-spec get_floats_value({binary(), flag()}) -> {ok, list(float())} |
{error, snag:snag()}.
get_floats_value(Flag) ->
case erlang:element(2, (erlang:element(2, Flag))) of
{lf, {internal, {some, Val}, _}} ->
{ok, Val};
{lf, {internal, none, _}} ->
flag_not_provided_error(erlang:element(1, Flag));
_ ->
access_type_error(erlang:element(1, Flag), <<"float list"/utf8>>)
end.
-spec get_floats(gleam@map:map_(binary(), flag()), binary()) -> {ok,
list(float())} |
{error, snag:snag()}.
get_floats(Flags, Name) ->
gleam@result:'try'(
access(Flags, Name),
fun(Value) -> get_floats_value({Name, Value}) end
).