Skip to main content

nodedb_codec/fastlanes/
iterator.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Sequential block-at-a-time decoding without header re-scans.
4
5use crate::error::CodecError;
6
7use super::block::decode_block;
8use super::header::{GLOBAL_HEADER_SIZE, expected_block_count, parse_header, validate_frame};
9
10/// Iterator that decodes one 1024-row block at a time, tracking byte
11/// offsets internally. Avoids re-scanning headers for sequential access.
12pub struct BlockIterator<'a> {
13    data: &'a [u8],
14    offset: usize,
15    total_count: usize,
16    blocks_remaining: usize,
17    current_block: usize,
18}
19
20impl<'a> BlockIterator<'a> {
21    /// Create a block iterator over encoded FastLanes data.
22    pub fn new(data: &'a [u8]) -> Result<Self, CodecError> {
23        if data.len() < GLOBAL_HEADER_SIZE {
24            return Err(CodecError::Truncated {
25                expected: GLOBAL_HEADER_SIZE,
26                actual: data.len(),
27            });
28        }
29        let (total_count, num_blocks) = parse_header(data)?;
30        validate_frame(data, total_count, num_blocks)?;
31        Ok(Self {
32            data,
33            offset: GLOBAL_HEADER_SIZE,
34            total_count,
35            blocks_remaining: num_blocks,
36            current_block: 0,
37        })
38    }
39
40    /// Skip the next block without decoding it.
41    pub fn skip_block(&mut self) -> Result<(), CodecError> {
42        if self.blocks_remaining == 0 {
43            return Ok(());
44        }
45        self.offset = super::block::skip_block(
46            self.data,
47            self.offset,
48            self.current_block,
49            expected_block_count(self.total_count, self.current_block)?,
50        )?;
51        self.current_block += 1;
52        self.blocks_remaining -= 1;
53        Ok(())
54    }
55}
56
57impl Iterator for BlockIterator<'_> {
58    type Item = Result<Vec<i64>, CodecError>;
59
60    fn next(&mut self) -> Option<Self::Item> {
61        if self.blocks_remaining == 0 {
62            return None;
63        }
64        let expected_count = match expected_block_count(self.total_count, self.current_block) {
65            Ok(count) => count,
66            Err(error) => return Some(Err(error)),
67        };
68        let mut values = Vec::with_capacity(expected_count);
69        match decode_block(
70            self.data,
71            self.offset,
72            &mut values,
73            self.current_block,
74            expected_count,
75        ) {
76            Ok(new_offset) => {
77                self.offset = new_offset;
78                self.current_block += 1;
79                self.blocks_remaining -= 1;
80                Some(Ok(values))
81            }
82            Err(error) => {
83                self.blocks_remaining = 0;
84                Some(Err(error))
85            }
86        }
87    }
88
89    fn size_hint(&self) -> (usize, Option<usize>) {
90        (self.blocks_remaining, Some(self.blocks_remaining))
91    }
92}