Packages

A CBOR (RFC 8949) decoder/encoder library implemented in pure Gleam

Current section

Files

Jump to
gleebor src gleebor.erl
Raw

src/gleebor.erl

-module(gleebor).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([decode_int/1, decode_bytes/1, decode_string/1, decode_list/2]).
-export_type([cbor_error/0]).
-type cbor_error() :: premature_eof |
{invalid_major_arg, integer()} |
{incorrect_type, integer()} |
malformed_utf8.
-spec decode_positive_int(bitstring()) -> {ok, {integer(), bitstring()}} |
{error, cbor_error()}.
decode_positive_int(A) ->
case A of
<<24:5/integer, Val:8/integer-unsigned, Rest/bitstring>> ->
{ok, {Val, Rest}};
<<25:5/integer, Val@1:16/integer-unsigned, Rest@1/bitstring>> ->
{ok, {Val@1, Rest@1}};
<<26:5/integer, Val@2:32/integer-unsigned, Rest@2/bitstring>> ->
{ok, {Val@2, Rest@2}};
<<27:5/integer, Val@3:64/integer-unsigned, Rest@3/bitstring>> ->
{ok, {Val@3, Rest@3}};
<<X:5/integer, _/bitstring>> when 27 < X ->
{error, {invalid_major_arg, X}};
<<X@1:5/integer, Rest@4/bitstring>> when X@1 < 24 ->
{ok, {X@1, Rest@4}};
_ ->
{error, premature_eof}
end.
-spec decode_negative_int(bitstring()) -> {ok, {integer(), bitstring()}} |
{error, cbor_error()}.
decode_negative_int(A) ->
case A of
<<24:5/integer, Val:8/integer-unsigned, Rest/bitstring>> ->
{ok, {1 - Val, Rest}};
<<25:5/integer, Val@1:16/integer-unsigned, Rest@1/bitstring>> ->
{ok, {1 - Val@1, Rest@1}};
<<26:5/integer, Val@2:32/integer-unsigned, Rest@2/bitstring>> ->
{ok, {1 - Val@2, Rest@2}};
<<27:5/integer, Val@3:64/integer-unsigned, Rest@3/bitstring>> ->
{ok, {1 - Val@3, Rest@3}};
<<X:5/integer, Rest@4/bitstring>> when X < 24 ->
{ok, {1 - X, Rest@4}};
<<X@1:5/integer, _/bitstring>> when 27 < X@1 ->
{error, {invalid_major_arg, X@1}};
_ ->
{error, premature_eof}
end.
-spec decode_int(bitstring()) -> {ok, {integer(), bitstring()}} |
{error, cbor_error()}.
decode_int(A) ->
case A of
<<0:3, Rest/bitstring>> ->
decode_positive_int(Rest);
<<1:3, Rest@1/bitstring>> ->
decode_negative_int(Rest@1);
<<_:3>> ->
{error, premature_eof};
<<X:3, _/bitstring>> ->
{error, {incorrect_type, X}};
_ ->
{error, premature_eof}
end.
-spec decode_bytes(bitstring()) -> {ok, {bitstring(), bitstring()}} |
{error, cbor_error()}.
decode_bytes(A) ->
case A of
<<2:3, Rest/bitstring>> ->
gleam@result:'try'(
decode_positive_int(Rest),
fun(_use0) ->
{Count, Rest@1} = _use0,
case Rest@1 of
<<X:Count/binary, Rest@2/bitstring>> ->
{ok, {X, Rest@2}};
_ ->
{error, premature_eof}
end
end
);
<<X@1:3, _/bitstring>> ->
{error, {invalid_major_arg, X@1}};
_ ->
{error, premature_eof}
end.
-spec decode_string(bitstring()) -> {ok, {binary(), bitstring()}} |
{error, cbor_error()}.
decode_string(A) ->
case A of
<<3:3, Rest/bitstring>> ->
gleam@result:'try'(
decode_positive_int(Rest),
fun(_use0) ->
{Count, Rest@1} = _use0,
case Rest@1 of
<<X:Count/binary, Rest@2/bitstring>> ->
gleam@result:'try'(
gleam@result:replace_error(
gleam@bit_array:to_string(X),
malformed_utf8
),
fun(S) -> {ok, {S, Rest@2}} end
);
_ ->
{error, premature_eof}
end
end
);
<<X@1:3, _/bitstring>> ->
{error, {invalid_major_arg, X@1}};
_ ->
{error, premature_eof}
end.
-spec decode_list(
bitstring(),
fun((bitstring()) -> {ok, {FKO, bitstring()}} | {error, cbor_error()})
) -> {ok,
gleam@iterator:iterator({ok, {FKO, bitstring()}} | {error, cbor_error()})} |
{error, cbor_error()}.
decode_list(A, F) ->
case A of
<<4:3, Rest/bitstring>> ->
gleam@result:'try'(
decode_positive_int(Rest),
fun(_use0) ->
{Count, Rest@1} = _use0,
{ok,
gleam@iterator:unfold(
{Count, Rest@1},
fun(N) -> case N of
{0, _} ->
done;
{Remaining, Rest@2} ->
case F(Rest@2) of
{ok, {Result, Rest@3}} ->
{next,
{ok, {Result, Rest@3}},
{Remaining - 1, Rest@3}};
{error, E} ->
{next, {error, E}, {0, Rest@2}}
end
end end
)}
end
);
<<X:3, _/bitstring>> ->
{error, {invalid_major_arg, X}};
_ ->
{error, premature_eof}
end.