use codec::Decode;
use corevm_host::fs::{BlockRef, Dir, Error, MainBlock, NodeKind, NodeReader, ReadBlock};
use jam_types::{Hash, ServiceId};
use std::collections::VecDeque;
pub struct PreimageParams {
pub service_id: ServiceId,
pub hash: Hash,
pub length: Option<u32>,
}
pub struct PreimageIter<R: ReadBlock> {
queue: VecDeque<BlockRef>,
preimages: VecDeque<PreimageParams>,
reader: R,
}
impl<R: ReadBlock> PreimageIter<R> {
pub fn new(main_block_ref: BlockRef, reader: R) -> Self {
let mut queue = VecDeque::new();
queue.push_back(main_block_ref);
Self { queue, preimages: VecDeque::new(), reader }
}
}
impl<R: ReadBlock> Iterator for PreimageIter<R> {
type Item = Result<PreimageParams, Error>;
fn next(&mut self) -> Option<Self::Item> {
macro_rules! check {
($body: expr) => {
match $body {
Ok(ret) => ret,
Err(e) => return Some(Err(e)),
}
};
}
if let Some(preimage) = self.preimages.pop_front() {
return Some(Ok(preimage));
}
let block_ref = self.queue.pop_front()?;
let block = check!(self.reader.read_block(&block_ref).map_err(|_| Error::Io));
let block_len = block.len();
let main_block = check!(MainBlock::decode(block).map_err(|_| Error::Io));
for block_ref in main_block.block_refs() {
self.preimages.push_back(PreimageParams {
service_id: block_ref.service_id,
hash: block_ref.hash.0,
length: None,
});
}
if matches!(main_block.kind(), NodeKind::Dir) {
let mut file = NodeReader::from_main_block(main_block, &mut self.reader);
let dir = check!(Dir::decode(&mut file).map_err(|_| Error::Io));
for (_name, block_ref) in dir.0.into_iter() {
self.queue.push_back(block_ref);
}
}
Some(Ok(PreimageParams {
service_id: block_ref.service_id,
hash: block_ref.hash.0,
length: Some(block_len as u32),
}))
}
}