add seek trait for block reader
This commit is contained in:
parent
02c232f6cb
commit
492879e483
@ -22,6 +22,8 @@ pub enum Error {
|
|||||||
WrongBlockHead(u32),
|
WrongBlockHead(u32),
|
||||||
#[error("wrong block tail value {0:#X}. it must be equal to head given value {1:#X}")]
|
#[error("wrong block tail value {0:#X}. it must be equal to head given value {1:#X}")]
|
||||||
WrongBlockTail(u32, u32),
|
WrongBlockTail(u32, u32),
|
||||||
|
#[error("expected magic words \"$&%#\" is not found at block tail")]
|
||||||
|
NoMagicWords,
|
||||||
}
|
}
|
||||||
type Result<T> = std::result::Result<T, Error>;
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
@ -59,6 +61,13 @@ impl HspiceBlock {
|
|||||||
block_len,
|
block_len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn absolute_offset(&self, relative_offset: u32) -> u64 {
|
||||||
|
if relative_offset >= self.block_len {
|
||||||
|
panic!("relative offset is out of range")
|
||||||
|
} else {
|
||||||
|
self.block_offset + u64::from(relative_offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct HspiceBlocks {
|
struct HspiceBlocks {
|
||||||
@ -101,6 +110,13 @@ where
|
|||||||
{
|
{
|
||||||
reader: T,
|
reader: T,
|
||||||
blocks: &'a [HspiceBlock],
|
blocks: &'a [HspiceBlock],
|
||||||
|
|
||||||
|
/// The full size of this reader
|
||||||
|
total_len: u64,
|
||||||
|
/// The table stored the offset relative to this reader.
|
||||||
|
/// It is convenient for Seek implement.
|
||||||
|
offset_table: Vec<u64>,
|
||||||
|
|
||||||
/// The cursor of block index.
|
/// The cursor of block index.
|
||||||
block_cursor: usize,
|
block_cursor: usize,
|
||||||
/// The cursor inside block.
|
/// The cursor inside block.
|
||||||
@ -111,9 +127,22 @@ where
|
|||||||
T: Read + Seek,
|
T: Read + Seek,
|
||||||
{
|
{
|
||||||
pub fn new(reader: T, blocks: &'a [HspiceBlock]) -> Self {
|
pub fn new(reader: T, blocks: &'a [HspiceBlock]) -> Self {
|
||||||
|
// Build total length and offset table.
|
||||||
|
let mut total_len: u64 = 0;
|
||||||
|
let mut offset_table: Vec<u64> = Vec::with_capacity(blocks.len());
|
||||||
|
for block in blocks {
|
||||||
|
offset_table.push(total_len);
|
||||||
|
total_len += u64::from(block.block_len);
|
||||||
|
}
|
||||||
|
// NOTE: This tail is essential for Seek impl.
|
||||||
|
// otherwise Seek impl will panic when SeekFrom::Current.
|
||||||
|
offset_table.push(total_len);
|
||||||
|
|
||||||
HspiceBlocksReader {
|
HspiceBlocksReader {
|
||||||
reader,
|
reader,
|
||||||
blocks,
|
blocks,
|
||||||
|
total_len,
|
||||||
|
offset_table,
|
||||||
block_cursor: 0,
|
block_cursor: 0,
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
}
|
}
|
||||||
@ -145,6 +174,7 @@ where
|
|||||||
// Check whether we need to switch to next block.
|
// Check whether we need to switch to next block.
|
||||||
if self.cursor >= self.blocks[self.block_cursor].block_len {
|
if self.cursor >= self.blocks[self.block_cursor].block_len {
|
||||||
self.block_cursor += 1;
|
self.block_cursor += 1;
|
||||||
|
self.cursor = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,15 +182,16 @@ where
|
|||||||
let remain = self.blocks[self.block_cursor].block_len - self.cursor;
|
let remain = self.blocks[self.block_cursor].block_len - self.cursor;
|
||||||
let read_count = std::cmp::min(usize::try_from(remain).unwrap(), buf.len());
|
let read_count = std::cmp::min(usize::try_from(remain).unwrap(), buf.len());
|
||||||
// Read data
|
// Read data
|
||||||
let offset = self.blocks[self.block_cursor].block_offset + u64::from(self.cursor);
|
let offset = self.blocks[self.block_cursor].absolute_offset(self.cursor);
|
||||||
if let Err(e) = self.reader.seek(SeekFrom::Start(offset)) {
|
if let Err(e) = self.reader.seek(SeekFrom::Start(offset)) {
|
||||||
break Err(e);
|
break Err(e);
|
||||||
}
|
}
|
||||||
if let Err(e) = self.read_exact(&mut buf[..read_count]) {
|
if let Err(e) = self.read_exact(&mut buf[..read_count]) {
|
||||||
break Err(e);
|
break Err(e);
|
||||||
}
|
}
|
||||||
// Shift buffer.
|
// Shift buffer and cursor.
|
||||||
buf = &mut buf[read_count..];
|
buf = &mut buf[read_count..];
|
||||||
|
self.cursor += u32::try_from(read_count).unwrap();
|
||||||
// Add count into total counter
|
// Add count into total counter
|
||||||
total_read_count += read_count;
|
total_read_count += read_count;
|
||||||
};
|
};
|
||||||
@ -175,6 +206,61 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'a, T> Seek for HspiceBlocksReader<'a, T>
|
||||||
|
where
|
||||||
|
T: Read + Seek,
|
||||||
|
{
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
|
||||||
|
use std::io::{Error, ErrorKind};
|
||||||
|
|
||||||
|
let err_instance = Error::new(ErrorKind::UnexpectedEof, "offset is out of range");
|
||||||
|
let reader_cursor = match pos {
|
||||||
|
SeekFrom::Start(v) => {
|
||||||
|
if v > self.total_len {
|
||||||
|
return Err(err_instance)
|
||||||
|
} else {
|
||||||
|
v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SeekFrom::End(v) => {
|
||||||
|
if v > 0 {
|
||||||
|
return Err(err_instance)
|
||||||
|
} else {
|
||||||
|
match self.total_len.checked_add_signed(v) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Err(err_instance),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SeekFrom::Current(v) => {
|
||||||
|
let current = self.offset_table[self.block_cursor] + u64::from(self.cursor);
|
||||||
|
match current.checked_add_signed(v) {
|
||||||
|
Some(v) => {
|
||||||
|
if v > self.total_len {
|
||||||
|
return Err(err_instance)
|
||||||
|
} else {
|
||||||
|
v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => return Err(err_instance),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let block_cursor = match self.offset_table.binary_search(&reader_cursor) {
|
||||||
|
Ok(v) => v,
|
||||||
|
// This unwrap should be safe.
|
||||||
|
// Because there is no possible that every items are greater than given value,
|
||||||
|
// due to that the first item of table must be zero.
|
||||||
|
Err(v) => v.checked_sub(1).unwrap(),
|
||||||
|
};
|
||||||
|
let cursor = reader_cursor - self.offset_table[block_cursor];
|
||||||
|
|
||||||
|
self.block_cursor = block_cursor;
|
||||||
|
self.cursor = u32::try_from(cursor).unwrap();
|
||||||
|
Ok(reader_cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Guess whether given reader is a legal HSPICE signal file.
|
/// Guess whether given reader is a legal HSPICE signal file.
|
||||||
///
|
///
|
||||||
@ -268,9 +354,14 @@ where
|
|||||||
// We can continue analyze next blocks safely.
|
// We can continue analyze next blocks safely.
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// Analyze header block count
|
// Analyze header block count
|
||||||
|
// for block in &blocks {
|
||||||
|
// let relative_offset = block.block_len.sa
|
||||||
|
// let offset = block.absolute_offset(block.block_len - (SIGNAL_NAME_LEN as u32));
|
||||||
|
// }
|
||||||
|
|
||||||
// Build result and return.
|
// Build result and return.
|
||||||
Ok(HspiceBlocks::new(sim_source, blocks, 0))
|
Ok(HspiceBlocks::new(sim_source, blocks, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SIGNAL_NAME_LEN: usize = 8;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user