anyreader/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::io;
4use std::io::Read;
5use std::path::{Path, PathBuf};
6
7mod container;
8mod peekable;
9mod stream;
10
11pub use crate::container::{ArchiveKind, Container, ContainerKind, Items};
12pub use crate::stream::CompressionKind;
13pub use crate::stream::StreamKind;
14
15#[derive(Debug, strum::EnumIs)]
16pub enum FileKind {
17    File,
18    Directory,
19    Other,
20}
21
22#[derive(Debug)]
23pub struct FileItem<T: Read> {
24    pub path: PathBuf,
25    pub reader: T,
26    pub kind: FileKind,
27}
28
29pub fn recursive_read<F>(path: &Path, mut reader: impl Read, callback: &mut F) -> io::Result<()>
30where
31    F: FnMut(FileItem<&mut dyn Read>) -> io::Result<()>,
32{
33    read_recursive_inner(path, FileKind::File, &mut reader as &mut dyn Read, callback)?;
34    Ok(())
35}
36
37fn handle_container<F>(path: &Path, mut archive: impl Container, callback: &mut F) -> io::Result<()>
38where
39    F: FnMut(FileItem<&mut dyn Read>) -> io::Result<()>,
40{
41    let mut items = archive.items()?;
42    while let Some(x) = items.next_item() {
43        let mut x = x?;
44        let reader = &mut x.reader as &mut dyn Read;
45        read_recursive_inner(path.join(x.path).as_path(), x.kind, reader, callback)?;
46    }
47    Ok(())
48}
49
50fn read_recursive_inner<F>(
51    path: &Path,
52    kind: FileKind,
53    reader: &mut dyn Read,
54    callback: &mut F,
55) -> io::Result<()>
56where
57    F: FnMut(FileItem<&mut dyn Read>) -> io::Result<()>,
58{
59    let container = ContainerKind::from_reader(reader)?;
60    match container {
61        ContainerKind::Stream(StreamKind::Raw(mut r)) => callback(FileItem {
62            path: path.to_path_buf(),
63            reader: &mut r as &mut dyn Read,
64            kind,
65        }),
66        ContainerKind::Stream(StreamKind::Compressed(mut c)) => {
67            read_recursive_inner(path, kind, &mut c as &mut dyn Read, callback)
68        }
69        ContainerKind::Archive(ArchiveKind::Tar(r)) => handle_container(path, r, callback),
70        ContainerKind::Archive(ArchiveKind::Zip(r)) => handle_container(path, r, callback),
71    }
72}