Packages

Binary and string parser combinator library for Gleam

Current section

Files

Jump to
bitty src bitty@bits.erl
Raw

src/bitty@bits.erl

-module(bitty@bits).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/bitty/bits.gleam").
-export([bit/0, align/0, uint/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Bit-level parsers for reading individual bits and sub-byte unsigned\n"
" integers. Bits are read MSB-first within each byte. Use `align()` to\n"
" return to byte-aligned parsing after bit-level operations.\n"
).
-file("src/bitty/bits.gleam", 17).
?DOC(
" Parse a single bit as a `Bool` (`True` for 1, `False` for 0).\n"
" Bits are read MSB-first within each byte.\n"
"\n"
" ```gleam\n"
" let assert Ok(#(flag, _)) =\n"
" bitty.run_partial(bits.bit(), on: <<0x80>>)\n"
" assert flag == True\n"
" ```\n"
).
-spec bit() -> bitty:parser(boolean()).
bit() ->
bitty:make_parser(
fun(State) ->
case gleam_stdlib:bit_array_slice(
erlang:element(2, State),
erlang:element(3, State),
1
) of
{ok, <<Byte>>} ->
Bit_val = erlang:'band'(
erlang:'bsr'(Byte, 7 - erlang:element(4, State)),
1
),
{New_byte, New_bit} = bitty:advance_bits(
erlang:element(3, State),
erlang:element(4, State),
1
),
{continue,
Bit_val =:= 1,
{state,
erlang:element(2, State),
New_byte,
New_bit,
erlang:element(5, State)},
true};
_ ->
bitty:stop_expected(State, <<"a bit"/utf8>>)
end
end
).
-file("src/bitty/bits.gleam", 49).
?DOC(
" Skip remaining bits in the current byte to reach the next byte boundary.\n"
" If already aligned, this is a no-op. Use after bit-level parsing to\n"
" resume byte-aligned operations.\n"
"\n"
" ```gleam\n"
" use flag <- bitty.then(bits.bit())\n"
" use _ <- bitty.then(bits.align())\n"
" use value <- bitty.then(num.u8())\n"
" bitty.success(#(flag, value))\n"
" ```\n"
).
-spec align() -> bitty:parser(nil).
align() ->
bitty:make_parser(fun(State) -> case erlang:element(4, State) =:= 0 of
true ->
{continue, nil, State, false};
false ->
{continue,
nil,
{state,
erlang:element(2, State),
erlang:element(3, State) + 1,
0,
erlang:element(5, State)},
true}
end end).
-file("src/bitty/bits.gleam", 77).
?DOC(
" Parse `count` bits as an unsigned integer. Does not require byte\n"
" alignment — can start mid-byte. On the JavaScript target, values\n"
" above 32 bits may lose precision due to IEEE 754 double-precision\n"
" limitations.\n"
"\n"
" ```gleam\n"
" let assert Ok(#(value, _)) =\n"
" bitty.run_partial(bits.uint(bits: 4), on: <<0xAB>>)\n"
" assert value == 0x0A\n"
" ```\n"
).
-spec uint(integer()) -> bitty:parser(integer()).
uint(Count) ->
bitty:make_parser(fun(State) -> case Count < 0 of
true ->
bitty:stop_expected(
State,
<<"non-negative bit count"/utf8>>
);
false ->
bitty:read_uint(State, Count, 0, Count > 0)
end end).