use crate::record::segment::SegmentManager;
use crate::{Error, MultiSignalReader, Result, Sample, SegmentInfo};
use std::path::PathBuf;
pub struct SegmentReader {
segment_manager: SegmentManager,
current_reader: Option<MultiSignalReader>,
samples_read: u64,
}
impl SegmentReader {
pub(crate) fn new(base_path: PathBuf, segments: Vec<SegmentInfo>) -> Self {
let segment_manager = SegmentManager::new(base_path, segments);
Self {
segment_manager,
current_reader: None,
samples_read: 0,
}
}
pub fn read_frame(&mut self) -> Result<Option<Vec<Sample>>> {
loop {
if let Some(reader) = &mut self.current_reader {
let frame = reader.read_frame()?;
if !frame.is_empty() {
self.samples_read += 1;
return Ok(Some(frame));
}
}
if !self.advance_segment()? {
return Ok(None); }
}
}
pub fn read_frames(&mut self, count: usize) -> Result<Vec<Vec<Sample>>> {
let mut frames = Vec::with_capacity(count);
for _ in 0..count {
match self.read_frame()? {
Some(frame) => frames.push(frame),
None => break,
}
}
Ok(frames)
}
pub fn seek_to_sample(&mut self, sample: u64) -> Result<u64> {
let segment_index = self.find_segment_for_sample(sample)?;
let segment_start = if segment_index == 0 {
0
} else {
self.segment_manager
.segment_info(segment_index - 1)
.map_or(0, |s| s.num_samples)
};
let offset_in_segment = sample - segment_start;
self.switch_to_segment(segment_index)?;
if let Some(reader) = &mut self.current_reader {
reader.seek_to_frame(offset_in_segment)?;
}
self.samples_read = sample;
Ok(sample)
}
#[must_use]
pub const fn position(&self) -> u64 {
self.samples_read
}
#[must_use]
pub fn total_samples(&self) -> u64 {
self.segment_manager
.segment_info(self.segment_manager.num_segments() - 1)
.map_or(0, |s| s.num_samples)
}
#[must_use]
pub const fn current_segment(&self) -> usize {
self.segment_manager.current_index()
}
#[must_use]
pub const fn num_segments(&self) -> usize {
self.segment_manager.num_segments()
}
fn advance_segment(&mut self) -> Result<bool> {
let next_index = self.segment_manager.current_index() + 1;
if next_index >= self.segment_manager.num_segments() {
return Ok(false);
}
self.switch_to_segment(next_index)?;
Ok(true)
}
fn switch_to_segment(&mut self, index: usize) -> Result<()> {
self.segment_manager.load_segment(index)?;
let signals = self.segment_manager.current_signals()?.to_vec();
let base_path = self.segment_manager.current_base_path()?.to_path_buf();
let reader = MultiSignalReader::new(&base_path, &signals)?;
self.current_reader = Some(reader);
Ok(())
}
fn find_segment_for_sample(&self, sample: u64) -> Result<usize> {
let mut cumulative = 0u64;
for i in 0..self.segment_manager.num_segments() {
let segment_info = self
.segment_manager
.segment_info(i)
.ok_or_else(|| Error::InvalidHeader("Segment not found".to_string()))?;
if sample < cumulative + segment_info.num_samples {
return Ok(i);
}
cumulative += segment_info.num_samples;
}
Err(Error::InvalidHeader(format!(
"Sample {sample} is beyond the end of the record"
)))
}
}