anyreader_walker/
entry.rs1use crate::stack::AnyWalker;
2use crate::walkers::{ArchiveVisitor, FileWalker, TarWalker, ZipWalker};
3use anyreader::AnyFormat;
4use anyreader::FormatKind;
5use bytes::buf::Reader;
6use bytes::{Buf, Bytes};
7use std::fmt::{Debug, Display, Formatter};
8use std::fs::File;
9use std::io::{BufReader, Read};
10use std::path::{Path, PathBuf};
11
12#[derive(Debug, Clone, Eq, PartialEq)]
14pub struct EntryDetails {
15 pub path: PathBuf,
16 pub size: u64,
17}
18
19impl EntryDetails {
20 pub fn new(path: impl Into<PathBuf>, size: u64) -> Self {
21 Self {
22 path: path.into(),
23 size,
24 }
25 }
26}
27
28impl Display for EntryDetails {
29 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
30 write!(f, "{} ({} bytes)", self.path.display(), self.size)
31 }
32}
33
34pub struct FileEntry<T: Read> {
90 details: EntryDetails,
91 inner: AnyFormat<T>,
92}
93
94impl FileEntry<BufReader<File>> {
95 pub fn from_path(path: impl AsRef<Path>) -> std::io::Result<Self> {
96 let file = File::open(&path)?;
97 let size = file.metadata()?.len();
98 let format = AnyFormat::from_reader(BufReader::new(file))?;
99 Ok(Self::new(path.as_ref().to_path_buf(), size, format))
100 }
101}
102
103impl FileEntry<Reader<Bytes>> {
104 pub fn from_bytes(
105 path: impl AsRef<Path>,
106 data: impl Into<Bytes>,
107 ) -> std::io::Result<FileEntry<Reader<Bytes>>> {
108 let data = data.into();
109 let size = data.len() as u64;
110 let inner = AnyFormat::from_reader(data.reader())?;
111 Ok(FileEntry {
112 details: EntryDetails::new(path.as_ref(), size),
113 inner,
114 })
115 }
116}
117
118impl<T: Read> FileEntry<T> {
119 pub fn new(path: PathBuf, size: u64, format: AnyFormat<T>) -> Self {
120 Self {
121 details: EntryDetails::new(path, size),
122 inner: format,
123 }
124 }
125
126 pub fn from_reader(
127 path: impl Into<PathBuf>,
128 size: u64,
129 reader: T,
130 ) -> std::io::Result<FileEntry<T>> {
131 let inner = AnyFormat::from_reader(reader)?;
132 Ok(FileEntry {
133 details: EntryDetails::new(path, size),
134 inner,
135 })
136 }
137
138 pub fn into_components(self) -> (EntryDetails, AnyFormat<T>) {
139 (self.details, self.inner)
140 }
141
142 pub fn details(&self) -> &EntryDetails {
143 &self.details
144 }
145
146 pub fn path(&self) -> &Path {
147 &self.details.path
148 }
149
150 pub fn size(&self) -> u64 {
151 self.details.size
152 }
153
154 pub fn supports_recursion(&self) -> bool {
155 matches!(self.inner.kind, FormatKind::Tar | FormatKind::Zip)
156 }
157
158 pub fn format(&self) -> FormatKind {
159 self.inner.kind
160 }
161
162 pub fn get_ref(&self) -> &T {
163 self.inner.get_ref()
164 }
165}
166
167impl<'a, T: Read + 'a> ArchiveVisitor<'a> for FileEntry<T> {
168 type Item = T;
169
170 #[inline(always)]
171 fn visit<V: AnyWalker>(mut self, visitor: &mut V) -> std::io::Result<()> {
172 match self.format() {
173 FormatKind::Tar => TarWalker::new(&mut self as &mut dyn Read).visit(visitor),
174 FormatKind::Zip => ZipWalker::new(&mut self as &mut dyn Read).visit(visitor),
175 _ => FileWalker::new(self).visit(visitor),
176 }
177 }
178}
179
180impl<T: Read> Debug for FileEntry<T> {
181 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
182 f.debug_struct("ArchiveEntry")
183 .field("path", &self.details.path)
184 .field("size", &self.details.size)
185 .field("format", &self.inner)
186 .finish()
187 }
188}
189
190impl<T: Read> Read for FileEntry<T> {
191 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
192 self.inner.read(buf)
193 }
194}