-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, <>} -> 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).