use std::borrow::Cow;
#[cfg(any(feature = "parallel", feature = "index"))]
use std::ops::Range;
use crate::{Block, ChainError};
use super::common::{ChainMeta, is_blank, parse_block, parse_header_with_default_id, read_line};
pub(crate) fn parse_chains_sequential(
bytes: &[u8],
) -> Result<(Vec<ChainMeta>, Vec<Block>), ChainError> {
let mut chains = Vec::new();
let mut blocks = Vec::new();
let mut pos = 0usize;
let len = bytes.len();
let mut next_id = 1u64;
while pos < len {
let line_start = pos;
let (next_pos, line) = read_line(bytes, pos);
pos = next_pos;
if is_blank(line) {
continue;
}
let (mut meta, has_explicit_id) = parse_header_with_default_id(line, line_start, next_id)?;
if !has_explicit_id {
next_id = next_id.checked_add(1).ok_or(ChainError::Format {
offset: line_start,
msg: Cow::Borrowed("generated chain id overflows u64"),
})?;
}
let block_start = blocks.len();
loop {
if pos >= len {
break;
}
let block_line_start = pos;
let (next, line) = read_line(bytes, pos);
pos = next;
if is_blank(line) {
break;
}
let block = parse_block(line, block_line_start)?;
blocks.push(block);
}
let block_end = blocks.len();
if block_end == block_start {
return Err(ChainError::Format {
offset: line_start,
msg: Cow::Borrowed("chain without any alignment blocks"),
});
}
meta.blocks = block_start..block_end;
chains.push(meta);
}
Ok((chains, blocks))
}
#[cfg(any(feature = "parallel", feature = "index"))]
pub(crate) fn locate_chain_ranges(bytes: &[u8]) -> Result<Vec<Range<usize>>, ChainError> {
let mut ranges = Vec::new();
let mut pos = 0usize;
let len = bytes.len();
while pos < len {
let chain_start = pos;
let (next_pos, line) = read_line(bytes, pos);
pos = next_pos;
if is_blank(line) {
continue;
}
if !line.starts_with(b"chain ") {
return Err(ChainError::Format {
offset: chain_start,
msg: Cow::Borrowed("expected chain header starting with 'chain '"),
});
}
while pos < len {
let (next, line) = read_line(bytes, pos);
pos = next;
if is_blank(line) {
break;
}
}
ranges.push(chain_start..pos);
}
Ok(ranges)
}