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 use fst::MapBuilder;
228
229 let mut fst_builder = MapBuilder::memory();
231 for (i, (key, _)) in entries.iter().enumerate() {
232 fst_builder
233 .insert(key, i as u64)
234 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
235 }
236 let fst_bytes = fst_builder
237 .into_inner()
238 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
239
240 let addrs: Vec<BlockAddr> = entries.iter().map(|(_, addr)| *addr).collect();
242 let addr_bytes = BlockAddrStore::build(&addrs)?;
243
244 let mut result = Vec::with_capacity(4 + fst_bytes.len() + addr_bytes.len());
246 result.write_u32::<LittleEndian>(fst_bytes.len() as u32)?;
247 result.extend_from_slice(&fst_bytes);
248 result.extend_from_slice(&addr_bytes);
249
250 Ok(result)
251 }
252
253 pub fn load(data: OwnedBytes) -> io::Result<Self> {
255 if data.len() < 4 {
256 return Err(io::Error::new(
257 io::ErrorKind::InvalidData,
258 "FstBlockIndex data too short",
259 ));
260 }
261
262 let fst_len = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
263
264 let fst_end = 4usize.checked_add(fst_len).ok_or_else(|| {
265 io::Error::new(io::ErrorKind::InvalidData, "FstBlockIndex length overflow")
266 })?;
267 if data.len() < fst_end {
268 return Err(io::Error::new(
269 io::ErrorKind::InvalidData,
270 "FstBlockIndex FST data truncated",
271 ));
272 }
273
274 let fst_data = data.slice(4..fst_end);
275 let addr_data = data.slice(fst_end..data.len());
276
277 let fst =
278 fst::Map::new(fst_data).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
279 let block_addrs = BlockAddrStore::load(addr_data)?;
280
281 if fst.len() != block_addrs.len() {
282 return Err(io::Error::new(
283 io::ErrorKind::InvalidData,
284 "FST key count does not match block address count",
285 ));
286 }
287 use fst::Streamer;
288 let mut entries = fst.stream();
289 let mut expected_ordinal = 0u64;
290 while let Some((_key, ordinal)) = entries.next() {
291 if ordinal != expected_ordinal {
292 return Err(io::Error::new(
293 io::ErrorKind::InvalidData,
294 "FST block ordinals are not contiguous",
295 ));
296 }
297 expected_ordinal += 1;
298 }
299
300 Ok(Self { fst, block_addrs })
301 }
302
303 pub fn locate(&self, key: &[u8]) -> Option<usize> {
307 if let Some(ordinal) = self.fst.get(key) {
309 return Some(ordinal as usize);
310 }
311
312 use fst::{IntoStreamer, Streamer};
314 let mut stream = self.fst.range().gt(key).into_stream();
315 match stream.next() {
316 Some((_, ordinal)) if ordinal > 0 => Some(ordinal as usize - 1),
317 Some(_) => None, None => {
319 let len = self.fst.len();
321 if len > 0 { Some(len - 1) } else { None }
322 }
323 }
324 }
325
326 pub fn get_addr(&self, ordinal: usize) -> Option<BlockAddr> {
328 self.block_addrs.get(ordinal)
329 }
330
331 pub fn len(&self) -> usize {
333 self.block_addrs.len()
334 }
335
336 pub fn is_empty(&self) -> bool {
338 self.block_addrs.is_empty()
339 }
340
341 pub fn all_addrs(&self) -> Vec<BlockAddr> {
343 self.block_addrs.all()
344 }
345}
346
347pub struct MmapBlockIndex {
353 data: OwnedBytes,
354 num_blocks: u32,
355 block_addrs: BlockAddrStore,
356 keys_offset: usize,
358 keys_end: usize,
360 restart_array_offset: usize,
362 restart_count: usize,
364 restart_interval: usize,
366}
367
368const RESTART_INTERVAL: usize = 16;
370
371impl MmapBlockIndex {
372 pub fn build(entries: &[(Vec<u8>, BlockAddr)]) -> io::Result<Vec<u8>> {
377 if entries.is_empty() {
378 let mut buf = Vec::with_capacity(16);
379 buf.write_u32::<LittleEndian>(0)?; buf.extend_from_slice(&BlockAddrStore::build(&[])?);
381 buf.write_u32::<LittleEndian>(0)?; buf.write_u16::<LittleEndian>(RESTART_INTERVAL as u16)?;
384 return Ok(buf);
385 }
386
387 let addrs: Vec<BlockAddr> = entries.iter().map(|(_, addr)| *addr).collect();
389 let addr_bytes = BlockAddrStore::build(&addrs)?;
390
391 let mut keys_buf = Vec::new();
393 let mut prev_key: Vec<u8> = Vec::new();
394 let mut restart_offsets: Vec<u32> = Vec::new();
395
396 for (i, (key, _)) in entries.iter().enumerate() {
397 let is_restart = i % RESTART_INTERVAL == 0;
398
399 if is_restart {
400 restart_offsets.push(keys_buf.len() as u32);
401 write_vint(&mut keys_buf, 0)?;
403 write_vint(&mut keys_buf, key.len() as u64)?;
404 keys_buf.extend_from_slice(key);
405 } else {
406 let prefix_len = common_prefix_len(&prev_key, key);
407 let suffix = &key[prefix_len..];
408 write_vint(&mut keys_buf, prefix_len as u64)?;
409 write_vint(&mut keys_buf, suffix.len() as u64)?;
410 keys_buf.extend_from_slice(suffix);
411 }
412
413 prev_key.clear();
414 prev_key.extend_from_slice(key);
415 }
416
417 let restart_count = restart_offsets.len();
419 let mut result =
420 Vec::with_capacity(4 + addr_bytes.len() + keys_buf.len() + restart_count * 4 + 6);
421 result.write_u32::<LittleEndian>(entries.len() as u32)?;
422 result.extend_from_slice(&addr_bytes);
423 result.extend_from_slice(&keys_buf);
424
425 for &off in &restart_offsets {
427 result.write_u32::<LittleEndian>(off)?;
428 }
429
430 result.write_u32::<LittleEndian>(restart_count as u32)?;
432 result.write_u16::<LittleEndian>(RESTART_INTERVAL as u16)?;
433
434 Ok(result)
435 }
436
437 pub fn load(data: OwnedBytes) -> io::Result<Self> {
439 if data.len() < 16 {
440 return Err(io::Error::new(
441 io::ErrorKind::InvalidData,
442 "MmapBlockIndex data too short",
443 ));
444 }
445
446 let num_blocks = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
447
448 let addr_data_start = 4;
450 let remaining = data.slice(addr_data_start..data.len());
451 let block_addrs = BlockAddrStore::load(remaining.clone())?;
452
453 if block_addrs.len() != num_blocks as usize {
454 return Err(io::Error::new(
455 io::ErrorKind::InvalidData,
456 "block address count does not match key count",
457 ));
458 }
459
460 let bits_per_entry = block_addrs.offset_bits as usize + block_addrs.length_bits as usize;
462 let total_bits = bits_per_entry
463 .checked_mul(num_blocks as usize)
464 .ok_or_else(|| {
465 io::Error::new(io::ErrorKind::InvalidData, "block index size overflow")
466 })?;
467 let addr_packed_size = total_bits.checked_add(7).ok_or_else(|| {
468 io::Error::new(io::ErrorKind::InvalidData, "block index size overflow")
469 })? / 8;
470 let keys_offset = addr_data_start
471 .checked_add(6)
472 .and_then(|v| v.checked_add(addr_packed_size))
473 .ok_or_else(|| {
474 io::Error::new(io::ErrorKind::InvalidData, "block index offset overflow")
475 })?; if data.len() < keys_offset + 6 {
479 return Err(io::Error::new(
480 io::ErrorKind::InvalidData,
481 "MmapBlockIndex missing restart footer",
482 ));
483 }
484 let footer_start = data.len() - 6;
485 let restart_count = u32::from_le_bytes([
486 data[footer_start],
487 data[footer_start + 1],
488 data[footer_start + 2],
489 data[footer_start + 3],
490 ]) as usize;
491 let restart_interval =
492 u16::from_le_bytes([data[footer_start + 4], data[footer_start + 5]]) as usize;
493
494 if restart_interval == 0 {
495 return Err(io::Error::new(
496 io::ErrorKind::InvalidData,
497 "block index restart interval is zero",
498 ));
499 }
500
501 let expected_restart_count = (num_blocks as usize).div_ceil(restart_interval);
502 if restart_count != expected_restart_count {
503 return Err(io::Error::new(
504 io::ErrorKind::InvalidData,
505 "block index restart count is inconsistent",
506 ));
507 }
508
509 let restart_bytes = restart_count.checked_mul(4).ok_or_else(|| {
511 io::Error::new(io::ErrorKind::InvalidData, "restart table size overflow")
512 })?;
513 let restart_array_offset = footer_start.checked_sub(restart_bytes).ok_or_else(|| {
514 io::Error::new(io::ErrorKind::InvalidData, "restart table out of bounds")
515 })?;
516 if restart_array_offset < keys_offset {
517 return Err(io::Error::new(
518 io::ErrorKind::InvalidData,
519 "restart table overlaps block keys",
520 ));
521 }
522
523 let keys_end = restart_array_offset;
525
526 let keys_data = &data.as_slice()[keys_offset..keys_end];
530 let mut reader = keys_data;
531 let mut current_key = Vec::new();
532 let mut previous_key: Option<Vec<u8>> = None;
533 for ordinal in 0..num_blocks as usize {
534 let entry_offset = keys_data.len() - reader.len();
535 if ordinal % restart_interval == 0 {
536 let restart_idx = ordinal / restart_interval;
537 let pos = restart_array_offset + restart_idx * 4;
538 let recorded =
539 u32::from_le_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]])
540 as usize;
541 if recorded != entry_offset {
542 return Err(io::Error::new(
543 io::ErrorKind::InvalidData,
544 "block index restart offset is inconsistent",
545 ));
546 }
547 }
548
549 let prefix_len = usize::try_from(read_vint(&mut reader)?).map_err(|_| {
550 io::Error::new(io::ErrorKind::InvalidData, "block key prefix is too large")
551 })?;
552 let suffix_len = usize::try_from(read_vint(&mut reader)?).map_err(|_| {
553 io::Error::new(io::ErrorKind::InvalidData, "block key suffix is too large")
554 })?;
555 if ordinal % restart_interval == 0 && prefix_len != 0 {
556 return Err(io::Error::new(
557 io::ErrorKind::InvalidData,
558 "block index restart key uses a prefix",
559 ));
560 }
561 if prefix_len > current_key.len() || suffix_len > reader.len() {
562 return Err(io::Error::new(
563 io::ErrorKind::UnexpectedEof,
564 "block index key is truncated",
565 ));
566 }
567 current_key.truncate(prefix_len);
568 current_key.extend_from_slice(&reader[..suffix_len]);
569 reader = &reader[suffix_len..];
570
571 if previous_key
572 .as_ref()
573 .is_some_and(|previous| previous.as_slice() >= current_key.as_slice())
574 {
575 return Err(io::Error::new(
576 io::ErrorKind::InvalidData,
577 "block index keys are not strictly increasing",
578 ));
579 }
580 previous_key = Some(current_key.clone());
581 }
582 if !reader.is_empty() {
583 return Err(io::Error::new(
584 io::ErrorKind::InvalidData,
585 "block index contains trailing key data",
586 ));
587 }
588
589 Ok(Self {
590 data,
591 num_blocks,
592 block_addrs,
593 keys_offset,
594 keys_end,
595 restart_array_offset,
596 restart_count,
597 restart_interval,
598 })
599 }
600
601 #[inline]
603 fn restart_offset(&self, idx: usize) -> u32 {
604 let pos = self.restart_array_offset + idx * 4;
605 u32::from_le_bytes([
606 self.data[pos],
607 self.data[pos + 1],
608 self.data[pos + 2],
609 self.data[pos + 3],
610 ])
611 }
612
613 fn decode_restart_key<'a>(&self, keys_data: &'a [u8], restart_idx: usize) -> &'a [u8] {
615 let offset = self.restart_offset(restart_idx) as usize;
616 let mut reader = &keys_data[offset..];
617
618 let prefix_len = read_vint(&mut reader).unwrap_or(0) as usize;
619 debug_assert_eq!(prefix_len, 0, "restart point should have prefix_len=0");
620 let suffix_len = read_vint(&mut reader).unwrap_or(0) as usize;
621
622 &reader[..suffix_len]
624 }
625
626 pub fn locate(&self, target: &[u8]) -> Option<usize> {
629 if self.num_blocks == 0 {
630 return None;
631 }
632
633 let keys_data = &self.data.as_slice()[self.keys_offset..self.keys_end];
634
635 let mut lo = 0usize;
637 let mut hi = self.restart_count;
638
639 while lo < hi {
640 let mid = lo + (hi - lo) / 2;
641 let key = self.decode_restart_key(keys_data, mid);
642 match key.cmp(target) {
643 std::cmp::Ordering::Equal => {
644 return Some(mid * self.restart_interval);
645 }
646 std::cmp::Ordering::Less => lo = mid + 1,
647 std::cmp::Ordering::Greater => hi = mid,
648 }
649 }
650
651 if lo == 0 {
654 }
657
658 let restart_idx = if lo > 0 { lo - 1 } else { 0 };
659 let start_ordinal = restart_idx * self.restart_interval;
660 let end_ordinal = if restart_idx + 1 < self.restart_count {
661 (restart_idx + 1) * self.restart_interval
662 } else {
663 self.num_blocks as usize
664 };
665
666 let scan_offset = self.restart_offset(restart_idx) as usize;
668 let mut reader = &keys_data[scan_offset..];
669 let mut current_key = Vec::new();
670 let mut last_le_block: Option<usize> = None;
671
672 for i in start_ordinal..end_ordinal {
673 let prefix_len = match read_vint(&mut reader) {
674 Ok(v) => v as usize,
675 Err(_) => break,
676 };
677 let suffix_len = match read_vint(&mut reader) {
678 Ok(v) => v as usize,
679 Err(_) => break,
680 };
681
682 current_key.truncate(prefix_len);
683 if suffix_len > reader.len() {
684 break;
685 }
686 current_key.extend_from_slice(&reader[..suffix_len]);
687 reader = &reader[suffix_len..];
688
689 match current_key.as_slice().cmp(target) {
690 std::cmp::Ordering::Equal => return Some(i),
691 std::cmp::Ordering::Less => last_le_block = Some(i),
692 std::cmp::Ordering::Greater => return last_le_block,
693 }
694 }
695
696 last_le_block
697 }
698
699 pub fn get_addr(&self, ordinal: usize) -> Option<BlockAddr> {
701 self.block_addrs.get(ordinal)
702 }
703
704 pub fn len(&self) -> usize {
706 self.num_blocks as usize
707 }
708
709 pub fn is_empty(&self) -> bool {
711 self.num_blocks == 0
712 }
713
714 pub fn all_addrs(&self) -> Vec<BlockAddr> {
716 self.block_addrs.all()
717 }
718
719 pub fn all_keys(&self) -> Vec<Vec<u8>> {
721 let mut result = Vec::with_capacity(self.num_blocks as usize);
722 let keys_data = &self.data.as_slice()[self.keys_offset..self.keys_end];
723 let mut reader = keys_data;
724 let mut current_key = Vec::new();
725
726 for _ in 0..self.num_blocks {
727 let prefix_len = match read_vint(&mut reader) {
728 Ok(v) => v as usize,
729 Err(_) => break,
730 };
731 let suffix_len = match read_vint(&mut reader) {
732 Ok(v) => v as usize,
733 Err(_) => break,
734 };
735
736 current_key.truncate(prefix_len);
737 if suffix_len > reader.len() {
738 break;
739 }
740 current_key.extend_from_slice(&reader[..suffix_len]);
741 reader = &reader[suffix_len..];
742
743 result.push(current_key.clone());
744 }
745
746 result
747 }
748}
749
750pub enum BlockIndex {
752 #[cfg(feature = "fst-index")]
753 Fst(FstBlockIndex),
754 Mmap(MmapBlockIndex),
755}
756
757impl BlockIndex {
758 pub fn locate(&self, key: &[u8]) -> Option<usize> {
760 match self {
761 #[cfg(feature = "fst-index")]
762 BlockIndex::Fst(idx) => idx.locate(key),
763 BlockIndex::Mmap(idx) => idx.locate(key),
764 }
765 }
766
767 pub fn get_addr(&self, ordinal: usize) -> Option<BlockAddr> {
769 match self {
770 #[cfg(feature = "fst-index")]
771 BlockIndex::Fst(idx) => idx.get_addr(ordinal),
772 BlockIndex::Mmap(idx) => idx.get_addr(ordinal),
773 }
774 }
775
776 pub fn len(&self) -> usize {
778 match self {
779 #[cfg(feature = "fst-index")]
780 BlockIndex::Fst(idx) => idx.len(),
781 BlockIndex::Mmap(idx) => idx.len(),
782 }
783 }
784
785 pub fn is_empty(&self) -> bool {
787 self.len() == 0
788 }
789
790 pub fn all_addrs(&self) -> Vec<BlockAddr> {
792 match self {
793 #[cfg(feature = "fst-index")]
794 BlockIndex::Fst(idx) => idx.all_addrs(),
795 BlockIndex::Mmap(idx) => idx.all_addrs(),
796 }
797 }
798}
799
800fn common_prefix_len(a: &[u8], b: &[u8]) -> usize {
805 a.iter().zip(b.iter()).take_while(|(x, y)| x == y).count()
806}
807
808struct BitWriter<'a> {
810 output: &'a mut Vec<u8>,
811 buffer: u64,
812 bits_in_buffer: u8,
813}
814
815impl<'a> BitWriter<'a> {
816 fn new(output: &'a mut Vec<u8>) -> Self {
817 Self {
818 output,
819 buffer: 0,
820 bits_in_buffer: 0,
821 }
822 }
823
824 fn write(&mut self, value: u64, num_bits: u8) -> io::Result<()> {
825 debug_assert!(num_bits <= 64);
826
827 self.buffer |= value << self.bits_in_buffer;
828 self.bits_in_buffer += num_bits;
829
830 while self.bits_in_buffer >= 8 {
831 self.output.push(self.buffer as u8);
832 self.buffer >>= 8;
833 self.bits_in_buffer -= 8;
834 }
835
836 Ok(())
837 }
838
839 fn flush(&mut self) -> io::Result<()> {
840 if self.bits_in_buffer > 0 {
841 self.output.push(self.buffer as u8);
842 self.buffer = 0;
843 self.bits_in_buffer = 0;
844 }
845 Ok(())
846 }
847}
848
849struct BitReader<'a> {
851 data: &'a [u8],
852 byte_pos: usize,
853 bit_pos: u8,
854}
855
856impl<'a> BitReader<'a> {
857 fn new(data: &'a [u8]) -> Self {
858 Self {
859 data,
860 byte_pos: 0,
861 bit_pos: 0,
862 }
863 }
864
865 fn read(&mut self, num_bits: u8) -> io::Result<u64> {
866 if num_bits == 0 {
867 return Ok(0);
868 }
869
870 let mut result: u64 = 0;
871 let mut bits_read: u8 = 0;
872
873 while bits_read < num_bits {
874 if self.byte_pos >= self.data.len() {
875 return Err(io::Error::new(
876 io::ErrorKind::UnexpectedEof,
877 "Not enough bits",
878 ));
879 }
880
881 let bits_available = 8 - self.bit_pos;
882 let bits_to_read = (num_bits - bits_read).min(bits_available);
883 let mask = if bits_to_read >= 8 {
885 0xFF
886 } else {
887 (1u8 << bits_to_read) - 1
888 };
889 let bits = (self.data[self.byte_pos] >> self.bit_pos) & mask;
890
891 result |= (bits as u64) << bits_read;
892 bits_read += bits_to_read;
893 self.bit_pos += bits_to_read;
894
895 if self.bit_pos >= 8 {
896 self.byte_pos += 1;
897 self.bit_pos = 0;
898 }
899 }
900
901 Ok(result)
902 }
903}
904
905#[cfg(test)]
906mod tests {
907 use super::*;
908
909 #[test]
910 fn test_block_addr_store_roundtrip() {
911 let addrs = vec![
912 BlockAddr {
913 offset: 0,
914 length: 1000,
915 },
916 BlockAddr {
917 offset: 1000,
918 length: 1500,
919 },
920 BlockAddr {
921 offset: 2500,
922 length: 800,
923 },
924 BlockAddr {
925 offset: 3300,
926 length: 2000,
927 },
928 ];
929
930 let bytes = BlockAddrStore::build(&addrs).unwrap();
931 let store = BlockAddrStore::load(OwnedBytes::new(bytes)).unwrap();
932
933 assert_eq!(store.len(), 4);
934 for (i, expected) in addrs.iter().enumerate() {
935 let actual = store.get(i).unwrap();
936 assert_eq!(actual.offset, expected.offset, "offset mismatch at {}", i);
937 assert_eq!(actual.length, expected.length, "length mismatch at {}", i);
938 }
939 }
940
941 #[test]
942 fn test_block_addr_store_empty() {
943 let bytes = BlockAddrStore::build(&[]).unwrap();
944 let store = BlockAddrStore::load(OwnedBytes::new(bytes)).unwrap();
945 assert_eq!(store.len(), 0);
946 assert!(store.get(0).is_none());
947 }
948
949 #[test]
950 fn test_block_addr_store_rejects_truncated_packed_data() {
951 let bytes = vec![1, 0, 0, 0, 1, 1];
952 assert!(BlockAddrStore::load(OwnedBytes::new(bytes)).is_err());
953 }
954
955 #[test]
956 fn test_mmap_index_rejects_restart_table_underflow() {
957 let entries = vec![(
958 b"key".to_vec(),
959 BlockAddr {
960 offset: 0,
961 length: 1,
962 },
963 )];
964 let mut bytes = MmapBlockIndex::build(&entries).unwrap();
965 let footer = bytes.len() - 6;
966 bytes[footer..footer + 4].copy_from_slice(&u32::MAX.to_le_bytes());
967 assert!(MmapBlockIndex::load(OwnedBytes::new(bytes)).is_err());
968 }
969
970 #[test]
971 fn test_mmap_block_index_roundtrip() {
972 let entries = vec![
973 (
974 b"aaa".to_vec(),
975 BlockAddr {
976 offset: 0,
977 length: 100,
978 },
979 ),
980 (
981 b"bbb".to_vec(),
982 BlockAddr {
983 offset: 100,
984 length: 150,
985 },
986 ),
987 (
988 b"ccc".to_vec(),
989 BlockAddr {
990 offset: 250,
991 length: 200,
992 },
993 ),
994 ];
995
996 let bytes = MmapBlockIndex::build(&entries).unwrap();
997 let index = MmapBlockIndex::load(OwnedBytes::new(bytes)).unwrap();
998
999 assert_eq!(index.len(), 3);
1000
1001 assert_eq!(index.locate(b"aaa"), Some(0));
1003 assert_eq!(index.locate(b"bbb"), Some(1));
1004 assert_eq!(index.locate(b"ccc"), Some(2));
1005 assert_eq!(index.locate(b"aab"), Some(0)); assert_eq!(index.locate(b"ddd"), Some(2)); assert_eq!(index.locate(b"000"), None); }
1009
1010 #[cfg(feature = "fst-index")]
1011 #[test]
1012 fn test_fst_block_index_roundtrip() {
1013 let entries = vec![
1014 (
1015 b"aaa".to_vec(),
1016 BlockAddr {
1017 offset: 0,
1018 length: 100,
1019 },
1020 ),
1021 (
1022 b"bbb".to_vec(),
1023 BlockAddr {
1024 offset: 100,
1025 length: 150,
1026 },
1027 ),
1028 (
1029 b"ccc".to_vec(),
1030 BlockAddr {
1031 offset: 250,
1032 length: 200,
1033 },
1034 ),
1035 ];
1036
1037 let bytes = FstBlockIndex::build(&entries).unwrap();
1038 let index = FstBlockIndex::load(OwnedBytes::new(bytes)).unwrap();
1039
1040 assert_eq!(index.len(), 3);
1041
1042 assert_eq!(index.locate(b"aaa"), Some(0));
1044 assert_eq!(index.locate(b"bbb"), Some(1));
1045 assert_eq!(index.locate(b"ccc"), Some(2));
1046 assert_eq!(index.locate(b"aab"), Some(0)); assert_eq!(index.locate(b"ddd"), Some(2)); }
1049
1050 #[test]
1051 fn test_bit_writer_reader() {
1052 let mut buf = Vec::new();
1053 let mut writer = BitWriter::new(&mut buf);
1054
1055 writer.write(5, 3).unwrap(); writer.write(3, 2).unwrap(); writer.write(15, 4).unwrap(); writer.flush().unwrap();
1059
1060 let mut reader = BitReader::new(&buf);
1061 assert_eq!(reader.read(3).unwrap(), 5);
1062 assert_eq!(reader.read(2).unwrap(), 3);
1063 assert_eq!(reader.read(4).unwrap(), 15);
1064 }
1065}