-module(thrifty@fuzz_utils). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/thrifty/fuzz_utils.gleam"). -export([mutate_byte/3, mutate_bit_flip/3, mutate_insert_byte/3, mutate_delete_byte/2, mutate_multi_byte/4]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/thrifty/fuzz_utils.gleam", 28). ?DOC( " Replace the byte at position `pos` with the provided `value`.\n" "\n" " Inputs\n" " - `data`: the source `BitArray` to mutate.\n" " - `pos`: zero-based byte index to replace.\n" " - `value`: integer 0..255 to write at `pos`.\n" "\n" " Outputs\n" " - Returns a new `BitArray` with the replaced byte when `pos` is in range.\n" " - Returns the original `data` unchanged if `pos` is out of range or on\n" " unexpected slicing errors.\n" ). -spec mutate_byte(bitstring(), integer(), integer()) -> bitstring(). mutate_byte(Data, Pos, Value) -> Size = erlang:byte_size(Data), case (Pos < 0) orelse (Pos >= Size) of true -> Data; false -> case gleam_stdlib:bit_array_slice(Data, 0, Pos) of {error, _} -> Data; {ok, Prefix} -> Suffix_len = (Size - Pos) - 1, case gleam_stdlib:bit_array_slice(Data, Pos + 1, Suffix_len) of {error, _} -> gleam_stdlib:bit_array_concat( [Prefix, <>] ); {ok, Suffix} -> gleam_stdlib:bit_array_concat( [Prefix, <>, Suffix] ) end end end. -file("src/thrifty/fuzz_utils.gleam", 155). -spec pow2(integer()) -> integer(). pow2(Exp) -> case Exp =< 0 of true -> 1; false -> 2 * pow2(Exp - 1) end. -file("src/thrifty/fuzz_utils.gleam", 56). ?DOC( " Flip a single bit in the byte at `pos`.\n" "\n" " Inputs\n" " - `data`: source `BitArray`.\n" " - `pos`: byte index to modify.\n" " - `bit_index`: 0..7 bit to flip (0 is LSB).\n" "\n" " Outputs\n" " - `BitArray` with the selected bit flipped, or original data if out of range.\n" ). -spec mutate_bit_flip(bitstring(), integer(), integer()) -> bitstring(). mutate_bit_flip(Data, Pos, Bit_index) -> Size = erlang:byte_size(Data), case (((Pos < 0) orelse (Pos >= Size)) orelse (Bit_index < 0)) orelse (Bit_index > 7) of true -> Data; false -> case gleam_stdlib:bit_array_slice(Data, Pos, 1) of {error, _} -> Data; {ok, Bits} -> case Bits of <> -> Mask = pow2(Bit_index), Div = case Mask of 0 -> 0; Gleam@denominator -> B div Gleam@denominator end, Has_bit = (Div rem 2) =:= 1, New_byte = case Has_bit of true -> B - Mask; false -> B + Mask end, mutate_byte(Data, Pos, New_byte); _ -> Data end end end. -file("src/thrifty/fuzz_utils.gleam", 82). ?DOC(" Insert a single byte at position `pos` shifting the remainder to the right.\n"). -spec mutate_insert_byte(bitstring(), integer(), integer()) -> bitstring(). mutate_insert_byte(Data, Pos, Value) -> Size = erlang:byte_size(Data), case (Pos < 0) orelse (Pos > Size) of true -> Data; false -> case gleam_stdlib:bit_array_slice(Data, 0, Pos) of {error, _} -> Data; {ok, Prefix} -> case gleam_stdlib:bit_array_slice(Data, Pos, Size - Pos) of {error, _} -> gleam_stdlib:bit_array_concat( [Prefix, <>] ); {ok, Suffix} -> gleam_stdlib:bit_array_concat( [Prefix, <>, Suffix] ) end end end. -file("src/thrifty/fuzz_utils.gleam", 100). ?DOC(" Delete a single byte at position `pos`.\n"). -spec mutate_delete_byte(bitstring(), integer()) -> bitstring(). mutate_delete_byte(Data, Pos) -> Size = erlang:byte_size(Data), case (Pos < 0) orelse (Pos >= Size) of true -> Data; false -> case gleam_stdlib:bit_array_slice(Data, 0, Pos) of {error, _} -> Data; {ok, Prefix} -> case gleam_stdlib:bit_array_slice( Data, Pos + 1, (Size - Pos) - 1 ) of {error, _} -> Prefix; {ok, Suffix} -> gleam_stdlib:bit_array_concat([Prefix, Suffix]) end end end. -file("src/thrifty/fuzz_utils.gleam", 145). -spec gen_bytes(integer(), integer()) -> bitstring(). gen_bytes(Count, Value) -> case Count =< 0 of true -> <<>>; false -> Tail = gen_bytes(Count - 1, Value), <> end. -file("src/thrifty/fuzz_utils.gleam", 117). ?DOC(" Overwrite `len` bytes starting at `pos` with repeated `value` bytes.\n"). -spec mutate_multi_byte(bitstring(), integer(), integer(), integer()) -> bitstring(). mutate_multi_byte(Data, Pos, Len, Value) -> Size = erlang:byte_size(Data), case ((Pos < 0) orelse (Pos >= Size)) orelse (Len =< 0) of true -> Data; false -> Write_len = case (Pos + Len) > Size of true -> Size - Pos; false -> Len end, case gleam_stdlib:bit_array_slice(Data, 0, Pos) of {error, _} -> Data; {ok, Prefix} -> Repeated = gen_bytes(Write_len, Value), case gleam_stdlib:bit_array_slice( Data, Pos + Write_len, (Size - Pos) - Write_len ) of {error, _} -> gleam_stdlib:bit_array_concat([Prefix, Repeated]); {ok, Suffix} -> gleam_stdlib:bit_array_concat( [Prefix, Repeated, Suffix] ) end end end.