nodedb_codec/fastlanes/
range.rs1use std::mem::size_of;
6
7use crate::bounds::{checked_add, checked_capacity, checked_mul, decoded_len};
8use crate::error::CodecError;
9
10use super::block::{decode_block, skip_block};
11use super::header::{GLOBAL_HEADER_SIZE, expected_block_count, parse_header, validate_frame};
12
13pub fn block_byte_offsets(data: &[u8]) -> Result<Vec<usize>, CodecError> {
18 if data.len() < GLOBAL_HEADER_SIZE {
19 return Err(CodecError::Truncated {
20 expected: GLOBAL_HEADER_SIZE,
21 actual: data.len(),
22 });
23 }
24 let (total_count, num_blocks) = parse_header(data)?;
25 let offset_capacity = checked_capacity(num_blocks, size_of::<usize>(), "FastLanes offsets")?;
26 let mut offsets = Vec::with_capacity(offset_capacity);
27 let mut pos = GLOBAL_HEADER_SIZE;
28 for i in 0..num_blocks {
29 offsets.push(pos);
30 pos = skip_block(data, pos, i, expected_block_count(total_count, i)?)?;
31 }
32 if pos != data.len() {
33 return Err(CodecError::Corrupt {
34 detail: "trailing bytes after FastLanes frame".into(),
35 });
36 }
37 Ok(offsets)
38}
39
40pub fn decode_block_range(
45 data: &[u8],
46 start_block: usize,
47 end_block: usize,
48) -> Result<Vec<i64>, CodecError> {
49 if data.len() < GLOBAL_HEADER_SIZE {
50 return Err(CodecError::Truncated {
51 expected: GLOBAL_HEADER_SIZE,
52 actual: data.len(),
53 });
54 }
55 let (total_count, num_blocks) = parse_header(data)?;
56 validate_frame(data, total_count, num_blocks)?;
57 if start_block >= num_blocks || end_block > num_blocks || start_block >= end_block {
58 return Ok(Vec::new());
59 }
60
61 let mut offset = GLOBAL_HEADER_SIZE;
63 for i in 0..start_block {
64 offset = skip_block(data, offset, i, expected_block_count(total_count, i)?)?;
65 }
66
67 let selected_count = (start_block..end_block).try_fold(0usize, |count, index| {
68 checked_add(
69 count,
70 expected_block_count(total_count, index)?,
71 "FastLanes range count",
72 )
73 })?;
74 let selected_bytes = checked_mul(selected_count, size_of::<i64>(), "FastLanes range bytes")?;
75 decoded_len(selected_bytes, "FastLanes range")?;
76 let selected_capacity = checked_capacity(selected_count, size_of::<i64>(), "FastLanes range")?;
77 let mut values = Vec::with_capacity(selected_capacity);
78 for i in start_block..end_block {
79 offset = decode_block(
80 data,
81 offset,
82 &mut values,
83 i,
84 expected_block_count(total_count, i)?,
85 )?;
86 }
87 Ok(values)
88}
89
90pub fn block_count(data: &[u8]) -> Result<usize, CodecError> {
92 if data.len() < GLOBAL_HEADER_SIZE {
93 return Err(CodecError::Truncated {
94 expected: GLOBAL_HEADER_SIZE,
95 actual: data.len(),
96 });
97 }
98 Ok(parse_header(data)?.1)
99}
100
101pub fn decode_single_block(data: &[u8], block_idx: usize) -> Result<Vec<i64>, CodecError> {
108 if data.len() < GLOBAL_HEADER_SIZE {
109 return Err(CodecError::Truncated {
110 expected: GLOBAL_HEADER_SIZE,
111 actual: data.len(),
112 });
113 }
114 let (total_count, num_blocks) = parse_header(data)?;
115 validate_frame(data, total_count, num_blocks)?;
116 if block_idx >= num_blocks {
117 return Err(CodecError::Corrupt {
118 detail: format!("block_idx {block_idx} >= block_count {num_blocks}"),
119 });
120 }
121
122 let mut offset = GLOBAL_HEADER_SIZE;
124 for i in 0..block_idx {
125 offset = skip_block(data, offset, i, expected_block_count(total_count, i)?)?;
126 }
127
128 let expected_count = expected_block_count(total_count, block_idx)?;
129 let value_capacity = checked_capacity(expected_count, size_of::<i64>(), "FastLanes block")?;
130 let mut values = Vec::with_capacity(value_capacity);
131 decode_block(data, offset, &mut values, block_idx, expected_count)?;
132 Ok(values)
133}