Skip to content

Commit

Permalink
Separate entries from reader
Browse files Browse the repository at this point in the history
  • Loading branch information
szeweq committed Jul 10, 2024
1 parent c4dd2ac commit f9e1d3b
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 48 deletions.
90 changes: 44 additions & 46 deletions lib-core/src/entry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,33 @@ pub trait EntryReader {
/// Reads entries, checks if they are not blacklisted and sends them via `tx`.
fn read_entries(
mut self,
mut tx: impl FnMut(EntryType) -> crate::Result_<()>,
mut tx: impl FnMut(NamedEntry) -> crate::Result_<()>,
blacklist: &TypeBlacklist
) -> crate::Result_<()> where Self: Sized {
tx(EntryType::Count(self.read_len()))?;
for re in self.read_iter() {
let (is_dir, name) = re.meta();
let fop = FileOp::by_name(&name, blacklist);
let et = match is_dir {
Some(true) => {
EntryType::dir(name)
}
Some(false) => {
if let FileOp::Ignore(_) = fop {
continue;
}
EntryType::file(name, re.data()?, fop)
}
None => {
continue;
}
};
tx(et)?;
let Some(ne) = read_entry::<Self>(re, blacklist)? else { continue };
tx(ne)?;
}
Ok(())
}
}

/// Reads an entry from an [`EntryReader`].
pub fn read_entry<R: EntryReader>(re: R::RE<'_>, blacklist: &TypeBlacklist) -> crate::Result_<Option<NamedEntry>> {
let (is_dir, name) = re.meta();
let Some(is_dir) = is_dir else { return Ok(None) };
let et = if is_dir {
NamedEntry::dir(name)
} else {
let fop = FileOp::by_name(&name, blacklist);
if let FileOp::Ignore(_) = fop {
return Ok(None);
}
NamedEntry::file(name, re.data()?, fop)
};
Ok(Some(et))
}

/// An iterator for reading entries from an entry reader.
#[repr(transparent)]
pub struct ReadEntryIter<'a, R: EntryReader>(&'a mut R);
Expand Down Expand Up @@ -86,44 +86,41 @@ pub trait EntrySaver {
/// Errors are collected with entry names.
fn save_entries(
mut self,
rx: impl IntoIterator<Item = EntryType>,
rx: impl IntoIterator<Item = NamedEntry>,
ev: &mut ErrorCollector,
cfgmap: &cfg::ConfigMap,
mut ps: impl FnMut(ProgressState) -> crate::Result_<()>,
) -> crate::Result_<()> where Self: Sized {
let mut cv = Vec::new();
let mut n = 0;
for et in rx {
for NamedEntry(name, et) in rx {
match et {
EntryType::Count(u) => {
ps(ProgressState::Start(u))?;
}
EntryType::Directory(dir) => {
self.save(&dir, SavingEntry::Directory)?;
EntryType::Directory => {
self.save(&name, SavingEntry::Directory)?;
}
EntryType::File(fname, buf, fop) => {
ps(ProgressState::Push(n, fname.clone()))?;
EntryType::File(buf, fop) => {
ps(ProgressState::Push(n, name.clone()))?;
n += 1;
match fop {
FileOp::Ignore(e) => {
ev.collect(fname.clone(), e.into());
ev.collect(name.clone(), e.into());
}
FileOp::Minify(m) => {
let buf: &[u8] = match m.minify(cfgmap, &buf, &mut cv) {
Ok(()) => &cv,
Err(e) => {
ev.collect(fname.clone(), e);
ev.collect(name.clone(), e);
&buf
}
};
self.save(&fname, SavingEntry::File(buf, m.compress_min()))?;
self.save(&name, SavingEntry::File(buf, m.compress_min()))?;
cv.clear();
}
FileOp::Recompress(x) => {
self.save(&fname, SavingEntry::File(&buf, x as u16))?;
self.save(&name, SavingEntry::File(&buf, x as u16))?;
}
FileOp::Pass => {
self.save(&fname, SavingEntry::File(&buf, 24))?;
self.save(&name, SavingEntry::File(&buf, 24))?;
}
}
}
Expand All @@ -133,30 +130,31 @@ pub trait EntrySaver {
}
}

/// An entry type based on extracted data from an archive
#[derive(Clone)]
pub enum EntryType {
/// Number of files stored in an archive
Count(usize),
/// A directory with its path
Directory(Arc<str>),
/// A file with its path, data and file operation
File(Arc<str>, Bytes, FileOp)
}
impl EntryType {
/// An entry with its name and type.
pub struct NamedEntry(pub Arc<str>, pub EntryType);
impl NamedEntry {
/// A shorthand function for creating a directory entry
#[inline]
pub fn dir(name: impl Into<Arc<str>>) -> Self {
Self::Directory(name.into())
Self(name.into(), EntryType::Directory)
}

/// A shorthand function for creating a file entry
#[inline]
pub fn file(name: impl Into<Arc<str>>, data: impl Into<Bytes>, fop: FileOp) -> Self {
Self::File(name.into(), data.into(), fop)
Self(name.into(), EntryType::File(data.into(), fop))
}
}

/// An entry type based on extracted data from an archive
#[derive(Clone)]
pub enum EntryType {
/// A directory with its path
Directory,
/// A file with its path, data and file operation
File(Bytes, FileOp)
}

/// A type for saving entries.
pub enum SavingEntry<'a> {
/// A directory
Expand Down
18 changes: 16 additions & 2 deletions src/bin/mc-repack/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use cli_args::{Cmd, FilesArgs, JarsArgs, RepackOpts};
use crossbeam_channel::Sender;
use indicatif::{ProgressBar, ProgressStyle, MultiProgress};

use mc_repack_core::{cfg, entry::{self, EntryReader, EntrySaver}, errors::ErrorCollector, fop::TypeBlacklist, ProgressState};
use mc_repack_core::{cfg, entry::{self, read_entry, EntryReader, EntrySaver}, errors::ErrorCollector, fop::TypeBlacklist, ProgressState};

mod cli_args;
mod config;
Expand Down Expand Up @@ -208,12 +208,26 @@ pub fn optimize_with<R: EntryReader + Send + 'static, S: EntrySaver + Send + 'st
blacklist: Arc<TypeBlacklist>
) -> crate::Result_<()> {
let (tx, rx) = crossbeam_channel::unbounded();
wrap_send(ps, ProgressState::Start(reader.read_len()))?;
let mut r1 = anyhow::Ok(());
let mut r2 = anyhow::Ok(());
rayon::scope_fifo(|s| {
let r1 = &mut r1;
let r2 = &mut r2;
s.spawn_fifo(move |_| *r1 = reader.read_entries(|e| wrap_send(&tx, e), &blacklist));
s.spawn_fifo(move |_| {
let mut reader = reader;
for re in reader.read_iter() {
let r = match read_entry::<R>(re, &blacklist) {
Ok(Some(ne)) => wrap_send(&tx, ne),
Ok(None) => Ok(()),
Err(e) => Err(e),
};
if let Err(e) = r {
*r1 = Err(e);
break;
}
}
});
s.spawn_fifo(move |_| *r2 = saver.save_entries(rx, errors, cfgmap, |p| wrap_send(ps, p)));
});
match (r1, r2) {
Expand Down

0 comments on commit f9e1d3b

Please sign in to comment.