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