1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
16use std::io;
17use std::ops::Range;
18
19use crate::directories::OwnedBytes;
20
21use super::vint::{read_vint, write_vint};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct BlockAddr {
26 pub offset: u64,
27 pub length: u32,
28}
29
30impl BlockAddr {
31 pub fn byte_range(&self) -> Range<u64> {
32 self.offset..self.offset + self.length as u64
33 }
34}
35
36#[derive(Debug)]
45pub struct BlockAddrStore {
46 num_blocks: u32,
47 offset_bits: u8,
48 length_bits: u8,
49 addrs: Vec<BlockAddr>,
51}
52
53impl BlockAddrStore {
54 pub fn build(addrs: &[BlockAddr]) -> io::Result<Vec<u8>> {
56 if addrs.is_empty() {
57 let mut buf = Vec::with_capacity(6);
58 buf.write_u32::<LittleEndian>(0)?;
59 buf.write_u8(0)?;
60 buf.write_u8(0)?;
61 return Ok(buf);
62 }
63
64 let mut deltas = Vec::with_capacity(addrs.len());
66 let mut prev_end: u64 = 0;
67 let mut max_delta: u64 = 0;
68 let mut max_length: u32 = 0;
69
70 for addr in addrs {
71 let delta = addr.offset.saturating_sub(prev_end);
73 deltas.push(delta);
74 max_delta = max_delta.max(delta);
75 max_length = max_length.max(addr.length);
76 prev_end = addr.offset.checked_add(addr.length as u64).ok_or_else(|| {
77 io::Error::new(io::ErrorKind::InvalidInput, "block address overflow")
78 })?;
79 }
80
81 let offset_bits = if max_delta == 0 {
83 1
84 } else {
85 (64 - max_delta.leading_zeros()) as u8
86 };
87 let length_bits = if max_length == 0 {
88 1
89 } else {
90 (32 - max_length.leading_zeros()) as u8
91 };
92
93 let bits_per_entry = offset_bits as usize + length_bits as usize;
95 let total_bits = bits_per_entry.checked_mul(addrs.len()).ok_or_else(|| {
96 io::Error::new(io::ErrorKind::InvalidInput, "block address table too large")
97 })?;
98 let packed_bytes = total_bits.div_ceil(8);
99
100 let mut buf = Vec::with_capacity(6 + packed_bytes);
101 buf.write_u32::<LittleEndian>(addrs.len() as u32)?;
102 buf.write_u8(offset_bits)?;
103 buf.write_u8(length_bits)?;
104
105 let mut bit_writer = BitWriter::new(&mut buf);
107 for (i, addr) in addrs.iter().enumerate() {
108 bit_writer.write(deltas[i], offset_bits)?;
109 bit_writer.write(addr.length as u64, length_bits)?;
110 }
111 bit_writer.flush()?;
112
113 Ok(buf)
114 }
115
116 pub fn load(data: OwnedBytes) -> io::Result<Self> {
118 if data.len() < 6 {
119 return Err(io::Error::new(
120 io::ErrorKind::InvalidData,
121 "BlockAddrStore data too short",
122 ));
123 }
124
125 let mut reader = data.as_slice();
126 let num_blocks = reader.read_u32::<LittleEndian>()?;
127 let offset_bits = reader.read_u8()?;
128 let length_bits = reader.read_u8()?;
129
130 if offset_bits > 64 || length_bits > 32 {
131 return Err(io::Error::new(
132 io::ErrorKind::InvalidData,
133 "invalid block address bit width",
134 ));
135 }
136 if num_blocks > 0 && (offset_bits == 0 || length_bits == 0) {
137 return Err(io::Error::new(
138 io::ErrorKind::InvalidData,
139 "non-empty block address table has a zero bit width",
140 ));
141 }
142
143 let bits_per_entry = offset_bits as usize + length_bits as usize;
144 let total_bits = bits_per_entry
145 .checked_mul(num_blocks as usize)
146 .ok_or_else(|| {
147 io::Error::new(io::ErrorKind::InvalidData, "block address table overflow")
148 })?;
149 let packed_len = total_bits.checked_add(7).ok_or_else(|| {
150 io::Error::new(io::ErrorKind::InvalidData, "block address table overflow")
151 })? / 8;
152 if packed_len > data.len() - 6 {
153 return Err(io::Error::new(
154 io::ErrorKind::UnexpectedEof,
155 "block address table truncated",
156 ));
157 }
158
159 let packed_data = &data.as_slice()[6..6 + packed_len];
161 let mut bit_reader = BitReader::new(packed_data);
162 let mut addrs = Vec::new();
163 addrs.try_reserve_exact(num_blocks as usize).map_err(|_| {
164 io::Error::new(io::ErrorKind::InvalidData, "block address table too large")
165 })?;
166 let mut current_offset: u64 = 0;
167
168 for _ in 0..num_blocks {
169 let delta = bit_reader.read(offset_bits)?;
170 let length = bit_reader.read(length_bits)?;
171 let offset = current_offset.checked_add(delta).ok_or_else(|| {
172 io::Error::new(io::ErrorKind::InvalidData, "block address offset overflow")
173 })?;
174 let length = u32::try_from(length).map_err(|_| {
175 io::Error::new(io::ErrorKind::InvalidData, "block length exceeds u32")
176 })?;
177 current_offset = offset.checked_add(length as u64).ok_or_else(|| {
178 io::Error::new(io::ErrorKind::InvalidData, "block address end overflow")
179 })?;
180 addrs.push(BlockAddr { offset, length });
181 }
182
183 Ok(Self {
184 num_blocks,
185 offset_bits,
186 length_bits,
187 addrs,
188 })
189 }
190
191 pub fn len(&self) -> usize {
193 self.num_blocks as usize
194 }
195
196 pub fn is_empty(&self) -> bool {
198 self.num_blocks == 0
199 }
200
201 #[inline]
203 pub fn get(&self, idx: usize) -> Option<BlockAddr> {
204 self.addrs.get(idx).copied()
205 }
206
207 pub fn all(&self) -> Vec<BlockAddr> {
209 self.addrs.clone()
210 }
211}
212
213#[cfg(feature = "fst-index")]
218pub struct FstBlockIndex {
219 fst: fst::Map<OwnedBytes>,
220 block_addrs: BlockAddrStore,
221}
222
223#[cfg(feature = "fst-index")]
224impl FstBlockIndex {
225 pub fn build(entries: &[(Vec<u8>, BlockAddr)]) -> io::Result<Vec<u8>> {
227 static EMPTY: std::sync::OnceLock<Vec<u8>> = std::sync::OnceLock::new();
231 if entries.is_empty() {
232 if let Some(bytes) = EMPTY.get() {
233 return Ok(bytes.clone());
234 }
235 let bytes = Self::build_uncached(entries)?;
236 let _ = EMPTY.set(bytes.clone());
238 return Ok(bytes);
239 }
240 Self::build_uncached(entries)
241 }
242
243 fn build_uncached(entries: &[(Vec<u8>, BlockAddr)]) -> io::Result<Vec<u8>> {
244 use fst::MapBuilder;
245
246 let mut fst_builder = MapBuilder::memory();
248 for (i, (key, _)) in entries.iter().enumerate() {
249 fst_builder
250 .insert(key, i as u64)
251 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
252 }
253 let fst_bytes = fst_builder
254 .into_inner()
255 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
256
257 let addrs: Vec<BlockAddr> = entries.iter().map(|(_, addr)| *addr).collect();
259 let addr_bytes = BlockAddrStore::build(&addrs)?;
260
261 let mut result = Vec::with_capacity(4 + fst_bytes.len() + addr_bytes.len());
263 result.write_u32::<LittleEndian>(fst_bytes.len() as u32)?;
264 result.extend_from_slice(&fst_bytes);
265 result.extend_from_slice(&addr_bytes);
266
267 Ok(result)
268 }
269
270 pub fn load(data: OwnedBytes) -> io::Result<Self> {
272 if data.len() < 4 {
273 return Err(io::Error::new(
274 io::ErrorKind::InvalidData,
275 "FstBlockIndex data too short",
276 ));
277 }
278
279 let fst_len = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
280
281 let fst_end = 4usize.checked_add(fst_len).ok_or_else(|| {
282 io::Error::new(io::ErrorKind::InvalidData, "FstBlockIndex length overflow")
283 })?;
284 if data.len() < fst_end {
285 return Err(io::Error::new(
286 io::ErrorKind::InvalidData,
287 "FstBlockIndex FST data truncated",
288 ));
289 }
290
291 let fst_data = data.slice(4..fst_end);
292 let addr_data = data.slice(fst_end..data.len());
293
294 let fst =
295 fst::Map::new(fst_data).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
296 let block_addrs = BlockAddrStore::load(addr_data)?;
297
298 if fst.len() != block_addrs.len() {
299 return Err(io::Error::new(
300 io::ErrorKind::InvalidData,
301 "FST key count does not match block address count",
302 ));
303 }
304 use fst::Streamer;
305 let mut entries = fst.stream();
306 let mut expected_ordinal = 0u64;
307 while let Some((_key, ordinal)) = entries.next() {
308 if ordinal != expected_ordinal {
309 return Err(io::Error::new(
310 io::ErrorKind::InvalidData,
311 "FST block ordinals are not contiguous",
312 ));
313 }
314 expected_ordinal += 1;
315 }
316
317 Ok(Self { fst, block_addrs })
318 }
319
320 pub fn locate(&self, key: &[u8]) -> Option<usize> {
324 if let Some(ordinal) = self.fst.get(key) {
326 return Some(ordinal as usize);
327 }
328
329 use fst::{IntoStreamer, Streamer};
331 let mut stream = self.fst.range().gt(key).into_stream();
332 match stream.next() {
333 Some((_, ordinal)) if ordinal > 0 => Some(ordinal as usize - 1),
334 Some(_) => None, None => {
336 let len = self.fst.len();
338 if len > 0 { Some(len - 1) } else { None }
339 }
340 }
341 }
342
343 pub fn get_addr(&self, ordinal: usize) -> Option<BlockAddr> {
345 self.block_addrs.get(ordinal)
346 }
347
348 pub fn len(&self) -> usize {
350 self.block_addrs.len()
351 }
352
353 pub fn is_empty(&self) -> bool {
355 self.block_addrs.is_empty()
356 }
357
358 pub fn all_addrs(&self) -> Vec<BlockAddr> {
360 self.block_addrs.all()
361 }
362}
363
364pub struct MmapBlockIndex {
370 data: OwnedBytes,
371 num_blocks: u32,
372 block_addrs: BlockAddrStore,
373 keys_offset: usize,
375 keys_end: usize,
377 restart_array_offset: usize,
379 restart_count: usize,
381 restart_interval: usize,
383}
384
385const RESTART_INTERVAL: usize = 16;
387
388impl MmapBlockIndex {
389 pub fn build(entries: &[(Vec<u8>, BlockAddr)]) -> io::Result<Vec<u8>> {
394 if entries.is_empty() {
395 let mut buf = Vec::with_capacity(16);
396 buf.write_u32::<LittleEndian>(0)?; buf.extend_from_slice(&BlockAddrStore::build(&[])?);
398 buf.write_u32::<LittleEndian>(0)?; buf.write_u16::<LittleEndian>(RESTART_INTERVAL as u16)?;
401 return Ok(buf);
402 }
403
404 let addrs: Vec<BlockAddr> = entries.iter().map(|(_, addr)| *addr).collect();
406 let addr_bytes = BlockAddrStore::build(&addrs)?;
407
408 let mut keys_buf = Vec::new();
410 let mut prev_key: Vec<u8> = Vec::new();
411 let mut restart_offsets: Vec<u32> = Vec::new();
412
413 for (i, (key, _)) in entries.iter().enumerate() {
414 let is_restart = i % RESTART_INTERVAL == 0;
415
416 if is_restart {
417 restart_offsets.push(keys_buf.len() as u32);
418 write_vint(&mut keys_buf, 0)?;
420 write_vint(&mut keys_buf, key.len() as u64)?;
421 keys_buf.extend_from_slice(key);
422 } else {
423 let prefix_len = common_prefix_len(&prev_key, key);
424 let suffix = &key[prefix_len..];
425 write_vint(&mut keys_buf, prefix_len as u64)?;
426 write_vint(&mut keys_buf, suffix.len() as u64)?;
427 keys_buf.extend_from_slice(suffix);
428 }
429
430 prev_key.clear();
431 prev_key.extend_from_slice(key);
432 }
433
434 let restart_count = restart_offsets.len();
436 let mut result =
437 Vec::with_capacity(4 + addr_bytes.len() + keys_buf.len() + restart_count * 4 + 6);
438 result.write_u32::<LittleEndian>(entries.len() as u32)?;
439 result.extend_from_slice(&addr_bytes);
440 result.extend_from_slice(&keys_buf);
441
442 for &off in &restart_offsets {
444 result.write_u32::<LittleEndian>(off)?;
445 }
446
447 result.write_u32::<LittleEndian>(restart_count as u32)?;
449 result.write_u16::<LittleEndian>(RESTART_INTERVAL as u16)?;
450
451 Ok(result)
452 }
453
454 pub fn load(data: OwnedBytes) -> io::Result<Self> {
456 if data.len() < 16 {
457 return Err(io::Error::new(
458 io::ErrorKind::InvalidData,
459 "MmapBlockIndex data too short",
460 ));
461 }
462
463 let num_blocks = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
464
465 let addr_data_start = 4;
467 let remaining = data.slice(addr_data_start..data.len());
468 let block_addrs = BlockAddrStore::load(remaining.clone())?;
469
470 if block_addrs.len() != num_blocks as usize {
471 return Err(io::Error::new(
472 io::ErrorKind::InvalidData,
473 "block address count does not match key count",
474 ));
475 }
476
477 let bits_per_entry = block_addrs.offset_bits as usize + block_addrs.length_bits as usize;
479 let total_bits = bits_per_entry
480 .checked_mul(num_blocks as usize)
481 .ok_or_else(|| {
482 io::Error::new(io::ErrorKind::InvalidData, "block index size overflow")
483 })?;
484 let addr_packed_size = total_bits.checked_add(7).ok_or_else(|| {
485 io::Error::new(io::ErrorKind::InvalidData, "block index size overflow")
486 })? / 8;
487 let keys_offset = addr_data_start
488 .checked_add(6)
489 .and_then(|v| v.checked_add(addr_packed_size))
490 .ok_or_else(|| {
491 io::Error::new(io::ErrorKind::InvalidData, "block index offset overflow")
492 })?; if data.len() < keys_offset + 6 {
496 return Err(io::Error::new(
497 io::ErrorKind::InvalidData,
498 "MmapBlockIndex missing restart footer",
499 ));
500 }
501 let footer_start = data.len() - 6;
502 let restart_count = u32::from_le_bytes([
503 data[footer_start],
504 data[footer_start + 1],
505 data[footer_start + 2],
506 data[footer_start + 3],
507 ]) as usize;
508 let restart_interval =
509 u16::from_le_bytes([data[footer_start + 4], data[footer_start + 5]]) as usize;
510
511 if restart_interval == 0 {
512 return Err(io::Error::new(
513 io::ErrorKind::InvalidData,
514 "block index restart interval is zero",
515 ));
516 }
517
518 let expected_restart_count = (num_blocks as usize).div_ceil(restart_interval);
519 if restart_count != expected_restart_count {
520 return Err(io::Error::new(
521 io::ErrorKind::InvalidData,
522 "block index restart count is inconsistent",
523 ));
524 }
525
526 let restart_bytes = restart_count.checked_mul(4).ok_or_else(|| {
528 io::Error::new(io::ErrorKind::InvalidData, "restart table size overflow")
529 })?;
530 let restart_array_offset = footer_start.checked_sub(restart_bytes).ok_or_else(|| {
531 io::Error::new(io::ErrorKind::InvalidData, "restart table out of bounds")
532 })?;
533 if restart_array_offset < keys_offset {
534 return Err(io::Error::new(
535 io::ErrorKind::InvalidData,
536 "restart table overlaps block keys",
537 ));
538 }
539
540 let keys_end = restart_array_offset;
542
543 let keys_data = &data.as_slice()[keys_offset..keys_end];
547 let mut reader = keys_data;
548 let mut current_key = Vec::new();
549 let mut previous_key: Option<Vec<u8>> = None;
550 for ordinal in 0..num_blocks as usize {
551 let entry_offset = keys_data.len() - reader.len();
552 if ordinal % restart_interval == 0 {
553 let restart_idx = ordinal / restart_interval;
554 let pos = restart_array_offset + restart_idx * 4;
555 let recorded =
556 u32::from_le_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]])
557 as usize;
558 if recorded != entry_offset {
559 return Err(io::Error::new(
560 io::ErrorKind::InvalidData,
561 "block index restart offset is inconsistent",
562 ));
563 }
564 }
565
566 let prefix_len = usize::try_from(read_vint(&mut reader)?).map_err(|_| {
567 io::Error::new(io::ErrorKind::InvalidData, "block key prefix is too large")
568 })?;
569 let suffix_len = usize::try_from(read_vint(&mut reader)?).map_err(|_| {
570 io::Error::new(io::ErrorKind::InvalidData, "block key suffix is too large")
571 })?;
572 if ordinal % restart_interval == 0 && prefix_len != 0 {
573 return Err(io::Error::new(
574 io::ErrorKind::InvalidData,
575 "block index restart key uses a prefix",
576 ));
577 }
578 if prefix_len > current_key.len() || suffix_len > reader.len() {
579 return Err(io::Error::new(
580 io::ErrorKind::UnexpectedEof,
581 "block index key is truncated",
582 ));
583 }
584 current_key.truncate(prefix_len);
585 current_key.extend_from_slice(&reader[..suffix_len]);
586 reader = &reader[suffix_len..];
587
588 if previous_key
589 .as_ref()
590 .is_some_and(|previous| previous.as_slice() >= current_key.as_slice())
591 {
592 return Err(io::Error::new(
593 io::ErrorKind::InvalidData,
594 "block index keys are not strictly increasing",
595 ));
596 }
597 previous_key = Some(current_key.clone());
598 }
599 if !reader.is_empty() {
600 return Err(io::Error::new(
601 io::ErrorKind::InvalidData,
602 "block index contains trailing key data",
603 ));
604 }
605
606 Ok(Self {
607 data,
608 num_blocks,
609 block_addrs,
610 keys_offset,
611 keys_end,
612 restart_array_offset,
613 restart_count,
614 restart_interval,
615 })
616 }
617
618 #[inline]
620 fn restart_offset(&self, idx: usize) -> u32 {
621 let pos = self.restart_array_offset + idx * 4;
622 u32::from_le_bytes([
623 self.data[pos],
624 self.data[pos + 1],
625 self.data[pos + 2],
626 self.data[pos + 3],
627 ])
628 }
629
630 fn decode_restart_key<'a>(&self, keys_data: &'a [u8], restart_idx: usize) -> &'a [u8] {
632 let offset = self.restart_offset(restart_idx) as usize;
633 let mut reader = &keys_data[offset..];
634
635 let prefix_len = read_vint(&mut reader).unwrap_or(0) as usize;
636 debug_assert_eq!(prefix_len, 0, "restart point should have prefix_len=0");
637 let suffix_len = read_vint(&mut reader).unwrap_or(0) as usize;
638
639 &reader[..suffix_len]
641 }
642
643 pub fn locate(&self, target: &[u8]) -> Option<usize> {
646 if self.num_blocks == 0 {
647 return None;
648 }
649
650 let keys_data = &self.data.as_slice()[self.keys_offset..self.keys_end];
651
652 let mut lo = 0usize;
654 let mut hi = self.restart_count;
655
656 while lo < hi {
657 let mid = lo + (hi - lo) / 2;
658 let key = self.decode_restart_key(keys_data, mid);
659 match key.cmp(target) {
660 std::cmp::Ordering::Equal => {
661 return Some(mid * self.restart_interval);
662 }
663 std::cmp::Ordering::Less => lo = mid + 1,
664 std::cmp::Ordering::Greater => hi = mid,
665 }
666 }
667
668 if lo == 0 {
671 }
674
675 let restart_idx = if lo > 0 { lo - 1 } else { 0 };
676 let start_ordinal = restart_idx * self.restart_interval;
677 let end_ordinal = if restart_idx + 1 < self.restart_count {
678 (restart_idx + 1) * self.restart_interval
679 } else {
680 self.num_blocks as usize
681 };
682
683 let scan_offset = self.restart_offset(restart_idx) as usize;
685 let mut reader = &keys_data[scan_offset..];
686 let mut current_key = Vec::new();
687 let mut last_le_block: Option<usize> = None;
688
689 for i in start_ordinal..end_ordinal {
690 let prefix_len = match read_vint(&mut reader) {
691 Ok(v) => v as usize,
692 Err(_) => break,
693 };
694 let suffix_len = match read_vint(&mut reader) {
695 Ok(v) => v as usize,
696 Err(_) => break,
697 };
698
699 current_key.truncate(prefix_len);
700 if suffix_len > reader.len() {
701 break;
702 }
703 current_key.extend_from_slice(&reader[..suffix_len]);
704 reader = &reader[suffix_len..];
705
706 match current_key.as_slice().cmp(target) {
707 std::cmp::Ordering::Equal => return Some(i),
708 std::cmp::Ordering::Less => last_le_block = Some(i),
709 std::cmp::Ordering::Greater => return last_le_block,
710 }
711 }
712
713 last_le_block
714 }
715
716 pub fn get_addr(&self, ordinal: usize) -> Option<BlockAddr> {
718 self.block_addrs.get(ordinal)
719 }
720
721 pub fn len(&self) -> usize {
723 self.num_blocks as usize
724 }
725
726 pub fn is_empty(&self) -> bool {
728 self.num_blocks == 0
729 }
730
731 pub fn all_addrs(&self) -> Vec<BlockAddr> {
733 self.block_addrs.all()
734 }
735
736 pub fn all_keys(&self) -> Vec<Vec<u8>> {
738 let mut result = Vec::with_capacity(self.num_blocks as usize);
739 let keys_data = &self.data.as_slice()[self.keys_offset..self.keys_end];
740 let mut reader = keys_data;
741 let mut current_key = Vec::new();
742
743 for _ in 0..self.num_blocks {
744 let prefix_len = match read_vint(&mut reader) {
745 Ok(v) => v as usize,
746 Err(_) => break,
747 };
748 let suffix_len = match read_vint(&mut reader) {
749 Ok(v) => v as usize,
750 Err(_) => break,
751 };
752
753 current_key.truncate(prefix_len);
754 if suffix_len > reader.len() {
755 break;
756 }
757 current_key.extend_from_slice(&reader[..suffix_len]);
758 reader = &reader[suffix_len..];
759
760 result.push(current_key.clone());
761 }
762
763 result
764 }
765}
766
767pub enum BlockIndex {
769 #[cfg(feature = "fst-index")]
770 Fst(FstBlockIndex),
771 Mmap(MmapBlockIndex),
772}
773
774impl BlockIndex {
775 pub fn locate(&self, key: &[u8]) -> Option<usize> {
777 match self {
778 #[cfg(feature = "fst-index")]
779 BlockIndex::Fst(idx) => idx.locate(key),
780 BlockIndex::Mmap(idx) => idx.locate(key),
781 }
782 }
783
784 pub fn get_addr(&self, ordinal: usize) -> Option<BlockAddr> {
786 match self {
787 #[cfg(feature = "fst-index")]
788 BlockIndex::Fst(idx) => idx.get_addr(ordinal),
789 BlockIndex::Mmap(idx) => idx.get_addr(ordinal),
790 }
791 }
792
793 pub fn len(&self) -> usize {
795 match self {
796 #[cfg(feature = "fst-index")]
797 BlockIndex::Fst(idx) => idx.len(),
798 BlockIndex::Mmap(idx) => idx.len(),
799 }
800 }
801
802 pub fn is_empty(&self) -> bool {
804 self.len() == 0
805 }
806
807 pub fn all_addrs(&self) -> Vec<BlockAddr> {
809 match self {
810 #[cfg(feature = "fst-index")]
811 BlockIndex::Fst(idx) => idx.all_addrs(),
812 BlockIndex::Mmap(idx) => idx.all_addrs(),
813 }
814 }
815}
816
817fn common_prefix_len(a: &[u8], b: &[u8]) -> usize {
822 a.iter().zip(b.iter()).take_while(|(x, y)| x == y).count()
823}
824
825struct BitWriter<'a> {
827 output: &'a mut Vec<u8>,
828 buffer: u64,
829 bits_in_buffer: u8,
830}
831
832impl<'a> BitWriter<'a> {
833 fn new(output: &'a mut Vec<u8>) -> Self {
834 Self {
835 output,
836 buffer: 0,
837 bits_in_buffer: 0,
838 }
839 }
840
841 fn write(&mut self, value: u64, num_bits: u8) -> io::Result<()> {
842 debug_assert!(num_bits <= 64);
843
844 self.buffer |= value << self.bits_in_buffer;
845 self.bits_in_buffer += num_bits;
846
847 while self.bits_in_buffer >= 8 {
848 self.output.push(self.buffer as u8);
849 self.buffer >>= 8;
850 self.bits_in_buffer -= 8;
851 }
852
853 Ok(())
854 }
855
856 fn flush(&mut self) -> io::Result<()> {
857 if self.bits_in_buffer > 0 {
858 self.output.push(self.buffer as u8);
859 self.buffer = 0;
860 self.bits_in_buffer = 0;
861 }
862 Ok(())
863 }
864}
865
866struct BitReader<'a> {
868 data: &'a [u8],
869 byte_pos: usize,
870 bit_pos: u8,
871}
872
873impl<'a> BitReader<'a> {
874 fn new(data: &'a [u8]) -> Self {
875 Self {
876 data,
877 byte_pos: 0,
878 bit_pos: 0,
879 }
880 }
881
882 fn read(&mut self, num_bits: u8) -> io::Result<u64> {
883 if num_bits == 0 {
884 return Ok(0);
885 }
886
887 let mut result: u64 = 0;
888 let mut bits_read: u8 = 0;
889
890 while bits_read < num_bits {
891 if self.byte_pos >= self.data.len() {
892 return Err(io::Error::new(
893 io::ErrorKind::UnexpectedEof,
894 "Not enough bits",
895 ));
896 }
897
898 let bits_available = 8 - self.bit_pos;
899 let bits_to_read = (num_bits - bits_read).min(bits_available);
900 let mask = if bits_to_read >= 8 {
902 0xFF
903 } else {
904 (1u8 << bits_to_read) - 1
905 };
906 let bits = (self.data[self.byte_pos] >> self.bit_pos) & mask;
907
908 result |= (bits as u64) << bits_read;
909 bits_read += bits_to_read;
910 self.bit_pos += bits_to_read;
911
912 if self.bit_pos >= 8 {
913 self.byte_pos += 1;
914 self.bit_pos = 0;
915 }
916 }
917
918 Ok(result)
919 }
920}
921
922#[cfg(test)]
923mod tests {
924 use super::*;
925
926 #[test]
927 fn test_block_addr_store_roundtrip() {
928 let addrs = vec![
929 BlockAddr {
930 offset: 0,
931 length: 1000,
932 },
933 BlockAddr {
934 offset: 1000,
935 length: 1500,
936 },
937 BlockAddr {
938 offset: 2500,
939 length: 800,
940 },
941 BlockAddr {
942 offset: 3300,
943 length: 2000,
944 },
945 ];
946
947 let bytes = BlockAddrStore::build(&addrs).unwrap();
948 let store = BlockAddrStore::load(OwnedBytes::new(bytes)).unwrap();
949
950 assert_eq!(store.len(), 4);
951 for (i, expected) in addrs.iter().enumerate() {
952 let actual = store.get(i).unwrap();
953 assert_eq!(actual.offset, expected.offset, "offset mismatch at {}", i);
954 assert_eq!(actual.length, expected.length, "length mismatch at {}", i);
955 }
956 }
957
958 #[test]
959 fn test_block_addr_store_empty() {
960 let bytes = BlockAddrStore::build(&[]).unwrap();
961 let store = BlockAddrStore::load(OwnedBytes::new(bytes)).unwrap();
962 assert_eq!(store.len(), 0);
963 assert!(store.get(0).is_none());
964 }
965
966 #[test]
967 fn test_block_addr_store_rejects_truncated_packed_data() {
968 let bytes = vec![1, 0, 0, 0, 1, 1];
969 assert!(BlockAddrStore::load(OwnedBytes::new(bytes)).is_err());
970 }
971
972 #[test]
973 fn test_mmap_index_rejects_restart_table_underflow() {
974 let entries = vec![(
975 b"key".to_vec(),
976 BlockAddr {
977 offset: 0,
978 length: 1,
979 },
980 )];
981 let mut bytes = MmapBlockIndex::build(&entries).unwrap();
982 let footer = bytes.len() - 6;
983 bytes[footer..footer + 4].copy_from_slice(&u32::MAX.to_le_bytes());
984 assert!(MmapBlockIndex::load(OwnedBytes::new(bytes)).is_err());
985 }
986
987 #[test]
988 fn test_mmap_block_index_roundtrip() {
989 let entries = vec![
990 (
991 b"aaa".to_vec(),
992 BlockAddr {
993 offset: 0,
994 length: 100,
995 },
996 ),
997 (
998 b"bbb".to_vec(),
999 BlockAddr {
1000 offset: 100,
1001 length: 150,
1002 },
1003 ),
1004 (
1005 b"ccc".to_vec(),
1006 BlockAddr {
1007 offset: 250,
1008 length: 200,
1009 },
1010 ),
1011 ];
1012
1013 let bytes = MmapBlockIndex::build(&entries).unwrap();
1014 let index = MmapBlockIndex::load(OwnedBytes::new(bytes)).unwrap();
1015
1016 assert_eq!(index.len(), 3);
1017
1018 assert_eq!(index.locate(b"aaa"), Some(0));
1020 assert_eq!(index.locate(b"bbb"), Some(1));
1021 assert_eq!(index.locate(b"ccc"), Some(2));
1022 assert_eq!(index.locate(b"aab"), Some(0)); assert_eq!(index.locate(b"ddd"), Some(2)); assert_eq!(index.locate(b"000"), None); }
1026
1027 #[cfg(feature = "fst-index")]
1028 #[test]
1029 fn cached_empty_fst_preserves_canonical_bytes_and_empty_lookup() {
1030 let expected = FstBlockIndex::build_uncached(&[]).unwrap();
1031 assert!(expected.len() <= 128, "empty-index cache must remain tiny");
1032 let mut first = FstBlockIndex::build(&[]).unwrap();
1033 assert_eq!(first, expected);
1034 first.clear();
1035 let next = FstBlockIndex::build(&[]).unwrap();
1036 assert_eq!(next, expected, "callers cannot mutate the cached artifact");
1037 let index = FstBlockIndex::load(OwnedBytes::new(next)).unwrap();
1038 assert_eq!(index.len(), 0);
1039 assert_eq!(index.locate(b"anything"), None);
1040 }
1041
1042 #[cfg(feature = "fst-index")]
1043 #[test]
1044 fn test_fst_block_index_roundtrip() {
1045 let entries = vec![
1046 (
1047 b"aaa".to_vec(),
1048 BlockAddr {
1049 offset: 0,
1050 length: 100,
1051 },
1052 ),
1053 (
1054 b"bbb".to_vec(),
1055 BlockAddr {
1056 offset: 100,
1057 length: 150,
1058 },
1059 ),
1060 (
1061 b"ccc".to_vec(),
1062 BlockAddr {
1063 offset: 250,
1064 length: 200,
1065 },
1066 ),
1067 ];
1068
1069 let bytes = FstBlockIndex::build(&entries).unwrap();
1070 let index = FstBlockIndex::load(OwnedBytes::new(bytes)).unwrap();
1071
1072 assert_eq!(index.len(), 3);
1073
1074 assert_eq!(index.locate(b"aaa"), Some(0));
1076 assert_eq!(index.locate(b"bbb"), Some(1));
1077 assert_eq!(index.locate(b"ccc"), Some(2));
1078 assert_eq!(index.locate(b"aab"), Some(0)); assert_eq!(index.locate(b"ddd"), Some(2)); }
1081
1082 #[test]
1083 fn test_bit_writer_reader() {
1084 let mut buf = Vec::new();
1085 let mut writer = BitWriter::new(&mut buf);
1086
1087 writer.write(5, 3).unwrap(); writer.write(3, 2).unwrap(); writer.write(15, 4).unwrap(); writer.flush().unwrap();
1091
1092 let mut reader = BitReader::new(&buf);
1093 assert_eq!(reader.read(3).unwrap(), 5);
1094 assert_eq!(reader.read(2).unwrap(), 3);
1095 assert_eq!(reader.read(4).unwrap(), 15);
1096 }
1097}