My working unpac space for OCaml projects in development
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge opam/patches/ocaml-bitstream

+607
+2
vendor/opam/ocaml-bitstream/.gitignore
··· 1 + _build/ 2 + *.install
+1
vendor/opam/ocaml-bitstream/dune
··· 1 + (vendored_dirs vendor)
+10
vendor/opam/ocaml-bitstream/dune-project
··· 1 + (lang dune 3.20) 2 + (name bitstream) 3 + 4 + (package 5 + (name bitstream) 6 + (synopsis "Bit-level I/O for binary format parsing and generation") 7 + (description "Forward and backward bitstream reading/writing for binary formats. Supports bit-level operations required by compression algorithms like FSE, ANS, and Huffman coding.") 8 + (depends 9 + (ocaml (>= 4.14)) 10 + (alcotest :with-test)))
+269
vendor/opam/ocaml-bitstream/src/bitstream.ml
··· 1 + (** Bitstream - Bit-level I/O for binary formats. 2 + 3 + Provides forward and backward bitstream reading and writing for parsing 4 + and generating binary formats that operate at the bit level. 5 + 6 + Forward streams read/write from the start of a buffer towards the end. 7 + Backward streams read/write from the end of a buffer towards the start, 8 + which is required by some compression algorithms (FSE, ANS). *) 9 + 10 + (** {1 Forward Bitstream Reader} *) 11 + 12 + module Forward_reader = struct 13 + type t = { 14 + src : bytes; 15 + limit : int; 16 + mutable byte_pos : int; 17 + mutable current_bits : int; 18 + mutable bits_remaining : int; 19 + } 20 + 21 + let create src ~pos ~len = 22 + { src; limit = pos + len; byte_pos = pos; 23 + current_bits = 0; bits_remaining = 0 } 24 + 25 + let of_bytes src = 26 + create src ~pos:0 ~len:(Bytes.length src) 27 + 28 + let byte_position t = 29 + t.byte_pos 30 + 31 + let remaining_bytes t = 32 + t.limit - t.byte_pos 33 + 34 + let[@inline] read_byte t = 35 + if t.byte_pos >= t.limit then 0 36 + else begin 37 + let b = Bytes.get_uint8 t.src t.byte_pos in 38 + t.byte_pos <- t.byte_pos + 1; 39 + b 40 + end 41 + 42 + let[@inline] read_bits t n = 43 + if n <= 0 then 0 44 + else if n > 32 then invalid_arg "read_bits: n > 32" 45 + else begin 46 + let result = ref 0 in 47 + let remaining = ref n in 48 + let shift = ref 0 in 49 + 50 + while !remaining > 0 do 51 + if t.bits_remaining = 0 then begin 52 + t.current_bits <- read_byte t; 53 + t.bits_remaining <- 8 54 + end; 55 + 56 + let take = min !remaining t.bits_remaining in 57 + let mask = (1 lsl take) - 1 in 58 + result := !result lor ((t.current_bits land mask) lsl !shift); 59 + t.current_bits <- t.current_bits lsr take; 60 + t.bits_remaining <- t.bits_remaining - take; 61 + remaining := !remaining - take; 62 + shift := !shift + take 63 + done; 64 + 65 + !result 66 + end 67 + 68 + let skip_bits t n = 69 + ignore (read_bits t n) 70 + 71 + let get_bytes t n = 72 + if n <= 0 then Bytes.empty 73 + else begin 74 + let result = Bytes.create n in 75 + Bytes.blit t.src t.byte_pos result 0 n; 76 + t.byte_pos <- t.byte_pos + n; 77 + result 78 + end 79 + 80 + let align_to_byte t = 81 + t.bits_remaining <- 0; 82 + t.current_bits <- 0 83 + end 84 + 85 + (** {1 Backward Bitstream Reader} 86 + 87 + Reads bits from the end of a buffer towards the start. The stream 88 + starts with a padding marker (highest 1-bit indicates start of data). *) 89 + 90 + module Backward_reader = struct 91 + type t = { 92 + src : bytes; 93 + start : int; 94 + mutable byte_pos : int; 95 + mutable bit_buf : int64; 96 + mutable bits_remaining : int; 97 + } 98 + 99 + let of_bytes src ~pos ~len = 100 + if len <= 0 then 101 + { src; start = pos; byte_pos = pos; bit_buf = 0L; bits_remaining = 0 } 102 + else begin 103 + let end_pos = pos + len - 1 in 104 + let byte_pos = ref end_pos in 105 + 106 + let init_bits = ref 0L in 107 + let num_bytes = min 8 len in 108 + for i = 0 to num_bytes - 1 do 109 + let b = Bytes.get_uint8 src (end_pos - i) in 110 + init_bits := Int64.logor !init_bits (Int64.shift_left (Int64.of_int b) (i * 8)) 111 + done; 112 + byte_pos := end_pos - num_bytes; 113 + 114 + let total_bits = num_bytes * 8 in 115 + let rec find_marker bits count = 116 + if count <= 0 then (bits, count) 117 + else if Int64.logand bits (Int64.shift_left 1L (count - 1)) <> 0L then 118 + (bits, count - 1) 119 + else 120 + find_marker bits (count - 1) 121 + in 122 + let (bits, remaining) = find_marker !init_bits total_bits in 123 + 124 + { src; start = pos; byte_pos = !byte_pos; bit_buf = bits; bits_remaining = remaining } 125 + end 126 + 127 + let[@inline] refill t = 128 + while t.bits_remaining <= 56 && t.byte_pos >= t.start do 129 + let b = Bytes.get_uint8 t.src t.byte_pos in 130 + t.bit_buf <- Int64.logor t.bit_buf 131 + (Int64.shift_left (Int64.of_int b) t.bits_remaining); 132 + t.bits_remaining <- t.bits_remaining + 8; 133 + t.byte_pos <- t.byte_pos - 1 134 + done 135 + 136 + let[@inline] read_bits t n = 137 + if n <= 0 then 0 138 + else if n > 32 then invalid_arg "read_bits: n > 32" 139 + else begin 140 + if t.bits_remaining < n then refill t; 141 + let mask = Int64.sub (Int64.shift_left 1L n) 1L in 142 + let result = Int64.to_int (Int64.logand t.bit_buf mask) in 143 + t.bit_buf <- Int64.shift_right_logical t.bit_buf n; 144 + t.bits_remaining <- t.bits_remaining - n; 145 + result 146 + end 147 + 148 + let[@inline] peek_bits t n = 149 + if n <= 0 then 0 150 + else if n > 32 then invalid_arg "peek_bits: n > 32" 151 + else begin 152 + if t.bits_remaining < n then refill t; 153 + let mask = Int64.sub (Int64.shift_left 1L n) 1L in 154 + Int64.to_int (Int64.logand t.bit_buf mask) 155 + end 156 + 157 + let remaining t = 158 + if t.bits_remaining > 0 then t.bits_remaining 159 + else (t.byte_pos - t.start + 1) * 8 160 + end 161 + 162 + (** {1 Forward Bitstream Writer} *) 163 + 164 + module Forward_writer = struct 165 + type t = { 166 + dst : bytes; 167 + mutable byte_pos : int; 168 + mutable bit_pos : int; 169 + mutable current_byte : int; 170 + } 171 + 172 + let create dst ~pos = 173 + { dst; byte_pos = pos; bit_pos = 0; current_byte = 0 } 174 + 175 + let of_bytes dst = 176 + create dst ~pos:0 177 + 178 + let flush t = 179 + if t.bit_pos > 0 then begin 180 + Bytes.set_uint8 t.dst t.byte_pos t.current_byte; 181 + t.byte_pos <- t.byte_pos + 1; 182 + t.bit_pos <- 0; 183 + t.current_byte <- 0 184 + end 185 + 186 + let[@inline] write_bits t value n = 187 + if n <= 0 then () 188 + else if n > 32 then invalid_arg "write_bits: n > 32" 189 + else begin 190 + let value = ref value in 191 + let remaining = ref n in 192 + 193 + while !remaining > 0 do 194 + let available = 8 - t.bit_pos in 195 + let to_write = min available !remaining in 196 + let mask = (1 lsl to_write) - 1 in 197 + t.current_byte <- t.current_byte lor ((!value land mask) lsl t.bit_pos); 198 + value := !value lsr to_write; 199 + remaining := !remaining - to_write; 200 + t.bit_pos <- t.bit_pos + to_write; 201 + 202 + if t.bit_pos = 8 then begin 203 + Bytes.set_uint8 t.dst t.byte_pos t.current_byte; 204 + t.byte_pos <- t.byte_pos + 1; 205 + t.bit_pos <- 0; 206 + t.current_byte <- 0 207 + end 208 + done 209 + end 210 + 211 + let write_byte t value = 212 + if t.bit_pos <> 0 then flush t; 213 + Bytes.set_uint8 t.dst t.byte_pos value; 214 + t.byte_pos <- t.byte_pos + 1 215 + 216 + let write_bytes t src = 217 + if t.bit_pos <> 0 then flush t; 218 + let len = Bytes.length src in 219 + Bytes.blit src 0 t.dst t.byte_pos len; 220 + t.byte_pos <- t.byte_pos + len 221 + 222 + let byte_position t = 223 + if t.bit_pos > 0 then t.byte_pos + 1 else t.byte_pos 224 + 225 + let finalize t = 226 + flush t; 227 + t.byte_pos 228 + end 229 + 230 + (** {1 Backward Bitstream Writer} 231 + 232 + Accumulates bits to be read backwards. Used for FSE and Huffman encoding. *) 233 + 234 + module Backward_writer = struct 235 + type t = { 236 + mutable bits : int64; 237 + mutable num_bits : int; 238 + buffer : bytes; 239 + mutable buf_pos : int; 240 + } 241 + 242 + let create size = 243 + { bits = 0L; num_bits = 0; buffer = Bytes.create size; buf_pos = size } 244 + 245 + let[@inline] write_bits t value n = 246 + if n > 0 then begin 247 + t.bits <- Int64.logor t.bits (Int64.shift_left (Int64.of_int value) t.num_bits); 248 + t.num_bits <- t.num_bits + n 249 + end 250 + 251 + let flush_bytes t = 252 + while t.num_bits >= 8 do 253 + t.buf_pos <- t.buf_pos - 1; 254 + Bytes.set_uint8 t.buffer t.buf_pos (Int64.to_int (Int64.logand t.bits 0xFFL)); 255 + t.bits <- Int64.shift_right_logical t.bits 8; 256 + t.num_bits <- t.num_bits - 8 257 + done 258 + 259 + let finalize t = 260 + write_bits t 1 1; 261 + if t.num_bits mod 8 <> 0 then 262 + t.num_bits <- ((t.num_bits + 7) / 8) * 8; 263 + flush_bytes t; 264 + let len = Bytes.length t.buffer - t.buf_pos in 265 + Bytes.sub t.buffer t.buf_pos len 266 + 267 + let current_size t = 268 + Bytes.length t.buffer - t.buf_pos + (t.num_bits + 7) / 8 269 + end
+161
vendor/opam/ocaml-bitstream/src/bitstream.mli
··· 1 + (** Bitstream - Bit-level I/O for binary formats. 2 + 3 + This library provides efficient bit-level reading and writing for parsing 4 + and generating binary formats. It supports both forward (start-to-end) and 5 + backward (end-to-start) operations, as required by various compression 6 + algorithms. 7 + 8 + {1 Overview} 9 + 10 + {[ 11 + (* Forward reading - parse a binary format *) 12 + let r = Bitstream.Forward_reader.of_bytes data in 13 + let magic = Bitstream.Forward_reader.read_bits r 32 in 14 + let flags = Bitstream.Forward_reader.read_bits r 8 in 15 + 16 + (* Forward writing - generate binary output *) 17 + let w = Bitstream.Forward_writer.of_bytes buffer in 18 + Bitstream.Forward_writer.write_bits w magic 32; 19 + Bitstream.Forward_writer.write_bits w flags 8; 20 + let len = Bitstream.Forward_writer.finalize w 21 + 22 + (* Backward reading - for FSE/ANS entropy decoding *) 23 + let r = Bitstream.Backward_reader.of_bytes data ~pos:0 ~len in 24 + let symbol = Bitstream.Backward_reader.read_bits r num_bits 25 + ]} 26 + 27 + {1 Forward vs Backward Streams} 28 + 29 + - {b Forward streams} read/write from the start of a buffer towards the end. 30 + This is the standard approach for most binary formats. 31 + 32 + - {b Backward streams} read/write from the end of a buffer towards the start. 33 + This is required by some compression algorithms (FSE, ANS, Huffman in zstd) 34 + where encoding happens forwards but decoding must happen backwards. *) 35 + 36 + (** {1 Forward Bitstream Reader} *) 37 + 38 + module Forward_reader : sig 39 + (** Forward bitstream reader state. *) 40 + type t 41 + 42 + val create : bytes -> pos:int -> len:int -> t 43 + (** [create src ~pos ~len] creates a reader for [len] bytes starting at [pos]. *) 44 + 45 + val of_bytes : bytes -> t 46 + (** [of_bytes src] creates a reader for the entire byte buffer. *) 47 + 48 + val byte_position : t -> int 49 + (** [byte_position t] returns the current byte position in the source. *) 50 + 51 + val remaining_bytes : t -> int 52 + (** [remaining_bytes t] returns the number of unread bytes. *) 53 + 54 + val read_byte : t -> int 55 + (** [read_byte t] reads and returns the next byte (0-255). 56 + Returns 0 if at end of stream. *) 57 + 58 + val read_bits : t -> int -> int 59 + (** [read_bits t n] reads and returns [n] bits (1-32) in little-endian order. 60 + @raise Invalid_argument if [n > 32]. *) 61 + 62 + val skip_bits : t -> int -> unit 63 + (** [skip_bits t n] skips [n] bits without returning them. *) 64 + 65 + val get_bytes : t -> int -> bytes 66 + (** [get_bytes t n] reads and returns the next [n] bytes as a new buffer. 67 + The reader must be byte-aligned. *) 68 + 69 + val align_to_byte : t -> unit 70 + (** [align_to_byte t] discards any remaining bits in the current byte, 71 + aligning the reader to the next byte boundary. *) 72 + end 73 + 74 + (** {1 Backward Bitstream Reader} 75 + 76 + Reads bits from the end of a buffer towards the start. The stream format 77 + includes a padding marker: the highest 1-bit in the final byte indicates 78 + where actual data begins. 79 + 80 + This format is used by FSE and ANS entropy coders in zstd. *) 81 + 82 + module Backward_reader : sig 83 + (** Backward bitstream reader state. *) 84 + type t 85 + 86 + val of_bytes : bytes -> pos:int -> len:int -> t 87 + (** [of_bytes src ~pos ~len] creates a backward reader. 88 + The stream is read from position [pos + len - 1] towards [pos]. 89 + Automatically handles the padding marker. *) 90 + 91 + val read_bits : t -> int -> int 92 + (** [read_bits t n] reads and returns [n] bits (1-32). 93 + @raise Invalid_argument if [n > 32]. *) 94 + 95 + val peek_bits : t -> int -> int 96 + (** [peek_bits t n] returns the next [n] bits without consuming them. 97 + @raise Invalid_argument if [n > 32]. *) 98 + 99 + val remaining : t -> int 100 + (** [remaining t] returns an estimate of remaining bits. *) 101 + end 102 + 103 + (** {1 Forward Bitstream Writer} *) 104 + 105 + module Forward_writer : sig 106 + (** Forward bitstream writer state. *) 107 + type t 108 + 109 + val create : bytes -> pos:int -> t 110 + (** [create dst ~pos] creates a writer starting at [pos] in buffer [dst]. *) 111 + 112 + val of_bytes : bytes -> t 113 + (** [of_bytes dst] creates a writer starting at position 0. *) 114 + 115 + val write_bits : t -> int -> int -> unit 116 + (** [write_bits t value n] writes the lower [n] bits (1-32) of [value] 117 + in little-endian order. 118 + @raise Invalid_argument if [n > 32]. *) 119 + 120 + val write_byte : t -> int -> unit 121 + (** [write_byte t value] writes a single byte. Flushes any partial bits first. *) 122 + 123 + val write_bytes : t -> bytes -> unit 124 + (** [write_bytes t src] writes all bytes from [src]. Flushes any partial bits first. *) 125 + 126 + val byte_position : t -> int 127 + (** [byte_position t] returns the current output position including any partial byte. *) 128 + 129 + val flush : t -> unit 130 + (** [flush t] writes any accumulated bits as a partial byte. *) 131 + 132 + val finalize : t -> int 133 + (** [finalize t] flushes and returns the total number of bytes written. *) 134 + end 135 + 136 + (** {1 Backward Bitstream Writer} 137 + 138 + Accumulates bits to produce output that will be read backwards. 139 + Used for FSE and Huffman encoding in zstd. *) 140 + 141 + module Backward_writer : sig 142 + (** Backward bitstream writer state. *) 143 + type t 144 + 145 + val create : int -> t 146 + (** [create size] creates a writer with an internal buffer of [size] bytes. *) 147 + 148 + val write_bits : t -> int -> int -> unit 149 + (** [write_bits t value n] accumulates [n] bits from [value]. *) 150 + 151 + val flush_bytes : t -> unit 152 + (** [flush_bytes t] flushes complete bytes to the internal buffer. *) 153 + 154 + val finalize : t -> bytes 155 + (** [finalize t] adds the padding marker, flushes, and returns the output. 156 + The returned bytes should be appended to the output and will be read 157 + backwards during decoding. *) 158 + 159 + val current_size : t -> int 160 + (** [current_size t] returns the current output size estimate. *) 161 + end
+4
vendor/opam/ocaml-bitstream/src/dune
··· 1 + (library 2 + (name bitstream) 3 + (public_name bitstream) 4 + (ocamlopt_flags (:standard -O3)))
+3
vendor/opam/ocaml-bitstream/test/dune
··· 1 + (test 2 + (name test_bitstream) 3 + (libraries bitstream alcotest))
+157
vendor/opam/ocaml-bitstream/test/test_bitstream.ml
··· 1 + (** Tests for Bitstream library *) 2 + 3 + let test_forward_reader_bytes () = 4 + let data = Bytes.of_string "\x12\x34\x56\x78" in 5 + let r = Bitstream.Forward_reader.of_bytes data in 6 + Alcotest.(check int) "byte 0" 0x12 (Bitstream.Forward_reader.read_byte r); 7 + Alcotest.(check int) "byte 1" 0x34 (Bitstream.Forward_reader.read_byte r); 8 + Alcotest.(check int) "byte 2" 0x56 (Bitstream.Forward_reader.read_byte r); 9 + Alcotest.(check int) "byte 3" 0x78 (Bitstream.Forward_reader.read_byte r); 10 + Alcotest.(check int) "past end" 0 (Bitstream.Forward_reader.read_byte r) 11 + 12 + let test_forward_reader_bits () = 13 + (* 0x12 = 0001_0010, 0x34 = 0011_0100 in little-endian bits: 14 + Reading 4 bits: 0010 = 2 15 + Reading 4 bits: 0001 = 1 16 + Reading 8 bits: 0011_0100 = 0x34 *) 17 + let data = Bytes.of_string "\x12\x34" in 18 + let r = Bitstream.Forward_reader.of_bytes data in 19 + Alcotest.(check int) "4 bits" 0x2 (Bitstream.Forward_reader.read_bits r 4); 20 + Alcotest.(check int) "4 bits" 0x1 (Bitstream.Forward_reader.read_bits r 4); 21 + Alcotest.(check int) "8 bits" 0x34 (Bitstream.Forward_reader.read_bits r 8) 22 + 23 + let test_forward_reader_mixed () = 24 + let data = Bytes.of_string "\xFF\x00\xAB\xCD" in 25 + let r = Bitstream.Forward_reader.of_bytes data in 26 + Alcotest.(check int) "16 bits LE" 0x00FF (Bitstream.Forward_reader.read_bits r 16); 27 + Alcotest.(check int) "remaining" 2 (Bitstream.Forward_reader.remaining_bytes r); 28 + let rest = Bitstream.Forward_reader.get_bytes r 2 in 29 + Alcotest.(check string) "get_bytes" "\xAB\xCD" (Bytes.to_string rest) 30 + 31 + let test_forward_reader_32bit () = 32 + let data = Bytes.of_string "\x78\x56\x34\x12" in 33 + let r = Bitstream.Forward_reader.of_bytes data in 34 + Alcotest.(check int) "32 bits LE" 0x12345678 (Bitstream.Forward_reader.read_bits r 32) 35 + 36 + let test_forward_writer_bytes () = 37 + let buf = Bytes.create 8 in 38 + let w = Bitstream.Forward_writer.of_bytes buf in 39 + Bitstream.Forward_writer.write_byte w 0x12; 40 + Bitstream.Forward_writer.write_byte w 0x34; 41 + let len = Bitstream.Forward_writer.finalize w in 42 + Alcotest.(check int) "length" 2 len; 43 + Alcotest.(check int) "byte 0" 0x12 (Bytes.get_uint8 buf 0); 44 + Alcotest.(check int) "byte 1" 0x34 (Bytes.get_uint8 buf 1) 45 + 46 + let test_forward_writer_bits () = 47 + let buf = Bytes.create 8 in 48 + let w = Bitstream.Forward_writer.of_bytes buf in 49 + Bitstream.Forward_writer.write_bits w 0x2 4; (* lower 4 bits *) 50 + Bitstream.Forward_writer.write_bits w 0x1 4; (* upper 4 bits *) 51 + Bitstream.Forward_writer.write_bits w 0x34 8; 52 + let len = Bitstream.Forward_writer.finalize w in 53 + Alcotest.(check int) "length" 2 len; 54 + Alcotest.(check int) "byte 0" 0x12 (Bytes.get_uint8 buf 0); 55 + Alcotest.(check int) "byte 1" 0x34 (Bytes.get_uint8 buf 1) 56 + 57 + let test_forward_writer_32bit () = 58 + let buf = Bytes.create 8 in 59 + let w = Bitstream.Forward_writer.of_bytes buf in 60 + Bitstream.Forward_writer.write_bits w 0x12345678 32; 61 + let len = Bitstream.Forward_writer.finalize w in 62 + Alcotest.(check int) "length" 4 len; 63 + Alcotest.(check int) "byte 0" 0x78 (Bytes.get_uint8 buf 0); 64 + Alcotest.(check int) "byte 1" 0x56 (Bytes.get_uint8 buf 1); 65 + Alcotest.(check int) "byte 2" 0x34 (Bytes.get_uint8 buf 2); 66 + Alcotest.(check int) "byte 3" 0x12 (Bytes.get_uint8 buf 3) 67 + 68 + let test_forward_roundtrip () = 69 + (* Write various bit patterns, then read them back *) 70 + let buf = Bytes.create 64 in 71 + let w = Bitstream.Forward_writer.of_bytes buf in 72 + Bitstream.Forward_writer.write_bits w 0b101 3; 73 + Bitstream.Forward_writer.write_bits w 0b11001 5; 74 + Bitstream.Forward_writer.write_bits w 0xABCD 16; 75 + Bitstream.Forward_writer.write_bits w 0b1111 4; 76 + let len = Bitstream.Forward_writer.finalize w in 77 + 78 + let r = Bitstream.Forward_reader.create buf ~pos:0 ~len in 79 + Alcotest.(check int) "3 bits" 0b101 (Bitstream.Forward_reader.read_bits r 3); 80 + Alcotest.(check int) "5 bits" 0b11001 (Bitstream.Forward_reader.read_bits r 5); 81 + Alcotest.(check int) "16 bits" 0xABCD (Bitstream.Forward_reader.read_bits r 16); 82 + Alcotest.(check int) "4 bits" 0b1111 (Bitstream.Forward_reader.read_bits r 4) 83 + 84 + let test_backward_roundtrip () = 85 + (* Write bits backwards, then read them backwards *) 86 + let w = Bitstream.Backward_writer.create 64 in 87 + Bitstream.Backward_writer.write_bits w 0b101 3; 88 + Bitstream.Backward_writer.write_bits w 0b11001 5; 89 + Bitstream.Backward_writer.write_bits w 0xAB 8; 90 + let data = Bitstream.Backward_writer.finalize w in 91 + 92 + let r = Bitstream.Backward_reader.of_bytes data ~pos:0 ~len:(Bytes.length data) in 93 + (* Read in same order as written (backward writer stores for backward reading) *) 94 + Alcotest.(check int) "3 bits" 0b101 (Bitstream.Backward_reader.read_bits r 3); 95 + Alcotest.(check int) "5 bits" 0b11001 (Bitstream.Backward_reader.read_bits r 5); 96 + Alcotest.(check int) "8 bits" 0xAB (Bitstream.Backward_reader.read_bits r 8) 97 + 98 + let test_backward_reader_peek () = 99 + let w = Bitstream.Backward_writer.create 64 in 100 + Bitstream.Backward_writer.write_bits w 0x5A 8; 101 + let data = Bitstream.Backward_writer.finalize w in 102 + 103 + let r = Bitstream.Backward_reader.of_bytes data ~pos:0 ~len:(Bytes.length data) in 104 + Alcotest.(check int) "peek 4" 0xA (Bitstream.Backward_reader.peek_bits r 4); 105 + Alcotest.(check int) "peek 4 again" 0xA (Bitstream.Backward_reader.peek_bits r 4); 106 + Alcotest.(check int) "read 4" 0xA (Bitstream.Backward_reader.read_bits r 4); 107 + Alcotest.(check int) "read 4" 0x5 (Bitstream.Backward_reader.read_bits r 4) 108 + 109 + let test_backward_empty () = 110 + let w = Bitstream.Backward_writer.create 64 in 111 + let data = Bitstream.Backward_writer.finalize w in 112 + (* Empty stream should just have padding marker *) 113 + Alcotest.(check bool) "not empty" true (Bytes.length data > 0); 114 + let r = Bitstream.Backward_reader.of_bytes data ~pos:0 ~len:(Bytes.length data) in 115 + Alcotest.(check int) "remaining" 0 (Bitstream.Backward_reader.remaining r) 116 + 117 + let test_forward_align () = 118 + let data = Bytes.of_string "\xFF\xAA" in 119 + let r = Bitstream.Forward_reader.of_bytes data in 120 + let _ = Bitstream.Forward_reader.read_bits r 3 in 121 + Bitstream.Forward_reader.align_to_byte r; 122 + Alcotest.(check int) "after align" 0xAA (Bitstream.Forward_reader.read_byte r) 123 + 124 + let test_edge_cases () = 125 + (* Zero bits *) 126 + let buf = Bytes.create 8 in 127 + let w = Bitstream.Forward_writer.of_bytes buf in 128 + Bitstream.Forward_writer.write_bits w 0 0; 129 + let len = Bitstream.Forward_writer.finalize w in 130 + Alcotest.(check int) "zero bits" 0 len; 131 + 132 + (* Read zero bits *) 133 + let data = Bytes.of_string "\xFF" in 134 + let r = Bitstream.Forward_reader.of_bytes data in 135 + Alcotest.(check int) "read 0 bits" 0 (Bitstream.Forward_reader.read_bits r 0); 136 + Alcotest.(check int) "byte still available" 0xFF (Bitstream.Forward_reader.read_byte r) 137 + 138 + let tests = [ 139 + "forward reader bytes", `Quick, test_forward_reader_bytes; 140 + "forward reader bits", `Quick, test_forward_reader_bits; 141 + "forward reader mixed", `Quick, test_forward_reader_mixed; 142 + "forward reader 32bit", `Quick, test_forward_reader_32bit; 143 + "forward writer bytes", `Quick, test_forward_writer_bytes; 144 + "forward writer bits", `Quick, test_forward_writer_bits; 145 + "forward writer 32bit", `Quick, test_forward_writer_32bit; 146 + "forward roundtrip", `Quick, test_forward_roundtrip; 147 + "backward roundtrip", `Quick, test_backward_roundtrip; 148 + "backward reader peek", `Quick, test_backward_reader_peek; 149 + "backward empty", `Quick, test_backward_empty; 150 + "forward align", `Quick, test_forward_align; 151 + "edge cases", `Quick, test_edge_cases; 152 + ] 153 + 154 + let () = 155 + Alcotest.run "Bitstream" [ 156 + "bitstream", tests; 157 + ]