Current section
Files
Jump to
Current section
Files
src/bitty@bytes.erl
-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,
<<Val:(lists:max([(Count), 0]))>>,
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,
<<Bytes/bitstring, Trail/bitstring>>,
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).