-module(bitty@bytes). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/bitty/bytes.gleam"). -export([take/1, skip/1, rest/0, peek/1, tag/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( " Byte-level parsers for reading, skipping, peeking, and matching raw\n" " bytes. These parsers work at any bit position — when unaligned, bytes\n" " are extracted bit-by-bit. When byte-aligned, zero-copy slicing is used.\n" " After bit-level parsing with `bitty/bits`, call `bitty.align()` before\n" " resuming byte-aligned operations.\n" ). -file("src/bitty/bytes.gleam", 14). ?DOC( " Parse exactly `count` bytes as a `BitArray`.\n" " When byte-aligned, returns a zero-copy slice.\n" ). -spec take(integer()) -> bitty:parser(bitstring()). take(Count) -> bitty:make_parser(fun(_capture) -> bitty:read_n_bytes(_capture, Count) end). -file("src/bitty/bytes.gleam", 19). ?DOC(" Advance the parser position by `count` bytes, discarding the data.\n"). -spec skip(integer()) -> bitty:parser(nil). skip(Count) -> bitty:make_parser( fun(State) -> gleam@bool:guard( Count < 0, bitty:stop_expected(State, <<"non-negative skip count"/utf8>>), fun() -> Total_bits = Count * 8, {New_byte, New_bit} = bitty:advance_bits( erlang:element(3, State), erlang:element(4, State), Total_bits ), Input_size = erlang:byte_size(erlang:element(2, State)), At_valid_position = case New_bit of 0 -> New_byte =< Input_size; _ -> New_byte < Input_size end, gleam@bool:guard( not At_valid_position, bitty:stop_expected( State, <<<<"at least "/utf8, (erlang:integer_to_binary(Count))/binary>>/binary, " bytes"/utf8>> ), fun() -> {continue, nil, {state, erlang:element(2, State), New_byte, New_bit, erlang:element(5, State)}, Count > 0} end ) end ) end ). -file("src/bitty/bytes.gleam", 83). -spec rest_read_bytes(bitty:state(), integer()) -> bitty:step(bitstring()). rest_read_bytes(State, Count) -> case Count > 0 of true -> bitty:read_n_bytes(State, Count); false -> {continue, <<>>, State, false} end. -file("src/bitty/bytes.gleam", 90). -spec rest_read_trailing(bitty:state(), integer()) -> bitty:step(bitstring()). rest_read_trailing(State, Count) -> case Count > 0 of true -> case bitty:read_uint(State, Count, 0, true) of {continue, Val, End_state, _} -> {continue, <>, End_state, true}; {stop, E, C, Cm} -> {stop, E, C, Cm} end; false -> {continue, <<>>, State, false} end. -file("src/bitty/bytes.gleam", 67). -spec rest_read(bitty:state(), integer(), integer()) -> bitty:step(bitstring()). rest_read(State, Remaining_bytes, Trailing_bits) -> case rest_read_bytes(State, Remaining_bytes) of {continue, Bytes, Mid_state, _} -> case rest_read_trailing(Mid_state, Trailing_bits) of {continue, Trail, End_state, _} -> {continue, <>, End_state, true}; {stop, E, C, Cm} -> {stop, E, C, Cm} end; {stop, E@1, C@1, Cm@1} -> {stop, E@1, C@1, Cm@1} end. -file("src/bitty/bytes.gleam", 50). ?DOC( " Consume all remaining input as a `BitArray`.\n" " Works at any bit position — the result may be non-byte-aligned.\n" ). -spec rest() -> bitty:parser(bitstring()). rest() -> bitty:make_parser( fun(State) -> Total_remaining_bits = ((erlang:byte_size(erlang:element(2, State)) - erlang:element(3, State)) * 8) - erlang:element(4, State), gleam@bool:guard( Total_remaining_bits =< 0, {continue, <<>>, State, false}, fun() -> Remaining_bytes = Total_remaining_bits div 8, Trailing_bits = Total_remaining_bits rem 8, rest_read(State, Remaining_bytes, Trailing_bits) end ) end ). -file("src/bitty/bytes.gleam", 103). ?DOC(" Look ahead at the next `count` bytes without consuming them.\n"). -spec peek(integer()) -> bitty:parser(bitstring()). peek(Count) -> bitty:make_parser(fun(State) -> case bitty:read_n_bytes(State, Count) of {continue, Bytes, _, _} -> {continue, Bytes, State, false}; {stop, Error, Consumed, Committed} -> {stop, Error, Consumed, Committed} end end). -file("src/bitty/bytes.gleam", 115). ?DOC( " Match an exact byte sequence at the current position and consume it.\n" " Fails if the bytes don't match. Useful for magic numbers and fixed headers.\n" ). -spec tag(bitstring()) -> bitty:parser(nil). tag(Expected) -> Len = erlang:byte_size(Expected), bitty:make_parser(fun(State) -> case bitty:read_n_bytes(State, Len) of {continue, Actual, New_state, Consumed} when Actual =:= Expected -> {continue, nil, New_state, Consumed}; {continue, _, _, _} -> bitty:stop_expected(State, <<"tag"/utf8>>); {stop, Error, Consumed@1, Committed} -> {stop, Error, Consumed@1, Committed} end end).