use crate::MAGIC; use { crate::{Error, Node}, std::{ io::{ErrorKind, Read}, iter::Iterator, }, }; #[cfg(feature = "parallel")] use { rayon::{iter::ParallelBridge, prelude::ParallelIterator}, std::{ops::DerefMut, sync::mpsc::Sender}, }; /// An iterator over a series of archive `Node`'s. This struct is generic over any /// type which implements `Read`, such as a file or a network stream. #[derive(Debug)] pub struct Stream { reader: R, } impl Iterator for Stream { type Item = Result; fn next(&mut self) -> Option { match Node::read(&mut self.reader) { Err(Error::Io(e)) if e.kind() == ErrorKind::UnexpectedEof => None, Ok(f) => match f.filetype { crate::FileType::Eof => None, _ => Some(Ok(f)), }, x => Some(x), } } } #[cfg(feature = "parallel")] #[derive(Debug)] pub enum Message { FileExtracted { name: String, size: u64 }, LinkCreated { name: String, target: String }, DirectoryCreated { name: String }, DeviceCreated { name: String }, Err(Error), Eof, } impl Stream { pub fn new(mut reader: R) -> Result { let mut buf = [0; 7]; reader.read_exact(&mut buf)?; if buf == MAGIC { Ok(Self { reader }) } else { Err(Error::InvalidMagic) } } pub fn extract(&mut self, prefix: Option<&str>) -> Result<(), Error> { for node in self { node?.extract(prefix)?; } Ok(()) } #[cfg(feature = "parallel")] pub fn par_extract( &mut self, prefix: Option<&str>, sender: &Sender, ) -> Result<(), Error> { let s = sender.clone(); self.into_iter().par_bridge().try_for_each_with(s, |s, n| { n?.extract(prefix)?; Ok::<(), Error>(()) })?; Ok(()) } }