Skip to content

Commit

Permalink
⚡ Avoid dynamic dispatch (#232)
Browse files Browse the repository at this point in the history
* ⚡ Add DcryptReader

* ⚡ Add DecompressReader

* use DecryptReader

* use DecompressReader

* Remove mutex

* Rename

* 🚚 Rename EntryDataReader to EntryReder

* ⚡ Introduce EntryDataReader
  • Loading branch information
ChanTsune authored Aug 13, 2023
1 parent 162d5de commit 14f5864
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 49 deletions.
64 changes: 37 additions & 27 deletions lib/src/archive/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use crate::{
chunk_data_split, chunk_to_bytes, ChunkExt, ChunkReader, ChunkType, RawChunk,
MIN_CHUNK_BYTES_SIZE,
},
cipher::{DecryptCbcAes256Reader, DecryptCbcCamellia256Reader},
cipher::{DecryptCbcAes256Reader, DecryptCbcCamellia256Reader, DecryptReader},
compress::DecompressReader,
hash::verify_password,
};
use std::{
Expand All @@ -37,10 +38,9 @@ pub trait Entry: SealedIntoChunks {

/// Readable archive entry.
pub trait ReadEntry: Entry {
type Reader: Read + Sync + Send;
fn header(&self) -> &EntryHeader;
fn metadata(&self) -> &Metadata;
fn into_reader(self, option: ReadOption) -> io::Result<Self::Reader>;
fn into_reader(self, option: ReadOption) -> io::Result<EntryDataReader>;
}

/// Solid mode entries block.
Expand Down Expand Up @@ -70,15 +70,23 @@ impl Entry for ChunkEntry {
}
}

/// [`Read`]
pub struct EntryDataReader(Box<dyn Read + Sync + Send>);
/// Reader for Entry data. this struct impl [`Read`] trait.
pub struct EntryDataReader(EntryReader<io::Cursor<Vec<u8>>>);

impl Read for EntryDataReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}

pub(crate) struct EntryReader<R: Read>(DecompressReader<'static, DecryptReader<R>>);

impl<R: Read> Read for EntryReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub(crate) enum ReadEntryContainer {
Solid(SolidReadEntry),
Expand All @@ -100,11 +108,11 @@ impl TryFrom<ChunkEntry> for ReadEntryContainer {
}
}

struct EntryIterator<'a> {
entry: Box<dyn Read + Sync + Send + 'a>,
struct EntryIterator<R: Read> {
entry: EntryReader<R>,
}

impl<'a> Iterator for EntryIterator<'a> {
impl<R: Read> Iterator for EntryIterator<R> {
type Item = io::Result<NonSolidReadEntry>;

fn next(&mut self) -> Option<Self::Item> {
Expand Down Expand Up @@ -150,7 +158,9 @@ impl SolidReadEntry {
)?;
let reader = decompress_reader(reader, self.header.compression)?;

Ok(EntryIterator { entry: reader })
Ok(EntryIterator {
entry: EntryReader(reader),
})
}
}

Expand Down Expand Up @@ -342,8 +352,6 @@ impl Entry for NonSolidReadEntry {
}

impl ReadEntry for NonSolidReadEntry {
type Reader = EntryDataReader;

#[inline]
fn header(&self) -> &EntryHeader {
&self.header
Expand All @@ -355,7 +363,7 @@ impl ReadEntry for NonSolidReadEntry {
}

#[inline]
fn into_reader(self, option: ReadOption) -> io::Result<Self::Reader> {
fn into_reader(self, option: ReadOption) -> io::Result<EntryDataReader> {
self.reader(option.password.as_deref())
}
}
Expand All @@ -371,20 +379,20 @@ impl NonSolidReadEntry {
password,
)?;
let reader = decompress_reader(decrypt_reader, self.header.compression)?;
Ok(EntryDataReader(reader))
Ok(EntryDataReader(EntryReader(reader)))
}
}

/// Decrypt reader according to encryption type.
fn decrypt_reader<'r, R: Read + Sync + Send + 'r>(
fn decrypt_reader<R: Read>(
reader: R,
encryption: Encryption,
cipher_mode: CipherMode,
phsf: Option<&str>,
password: Option<&str>,
) -> io::Result<Box<dyn Read + Sync + Send + 'r>> {
) -> io::Result<DecryptReader<R>> {
Ok(match encryption {
Encryption::No => Box::new(reader),
Encryption::No => DecryptReader::No(reader),
encryption @ Encryption::Aes | encryption @ Encryption::Camellia => {
let s = phsf.ok_or_else(|| {
io::Error::new(
Expand All @@ -409,30 +417,32 @@ fn decrypt_reader<'r, R: Read + Sync + Send + 'r>(
})?;
match (encryption, cipher_mode) {
(Encryption::Aes, CipherMode::CBC) => {
Box::new(DecryptCbcAes256Reader::new(reader, hash.as_bytes())?)
DecryptReader::CbcAes(DecryptCbcAes256Reader::new(reader, hash.as_bytes())?)
}
(Encryption::Aes, CipherMode::CTR) => {
Box::new(aes_ctr_cipher_reader(reader, hash.as_bytes())?)
DecryptReader::CtrAes(aes_ctr_cipher_reader(reader, hash.as_bytes())?)
}
(Encryption::Camellia, CipherMode::CBC) => {
Box::new(DecryptCbcCamellia256Reader::new(reader, hash.as_bytes())?)
(Encryption::Camellia, CipherMode::CBC) => DecryptReader::CbcCamellia(
DecryptCbcCamellia256Reader::new(reader, hash.as_bytes())?,
),
_ => {
DecryptReader::CtrCamellia(camellia_ctr_cipher_reader(reader, hash.as_bytes())?)
}
_ => Box::new(camellia_ctr_cipher_reader(reader, hash.as_bytes())?),
}
}
})
}

/// Decompress reader according to compression type.
fn decompress_reader<'r, R: Read + Sync + Send + 'r>(
fn decompress_reader<'r, R: Read>(
reader: R,
compression: Compression,
) -> io::Result<Box<dyn Read + Sync + Send + 'r>> {
) -> io::Result<DecompressReader<'r, R>> {
Ok(match compression {
Compression::No => Box::new(reader),
Compression::Deflate => Box::new(flate2::read::ZlibDecoder::new(reader)),
Compression::ZStandard => Box::new(MutexRead::new(zstd::Decoder::new(reader)?)),
Compression::XZ => Box::new(xz2::read::XzDecoder::new(reader)),
Compression::No => DecompressReader::No(reader),
Compression::Deflate => DecompressReader::Deflate(flate2::read::ZlibDecoder::new(reader)),
Compression::ZStandard => DecompressReader::ZStd(zstd::Decoder::new(reader)?),
Compression::XZ => DecompressReader::Xz(xz2::read::XzDecoder::new(reader)),
})
}

Expand Down
17 changes: 0 additions & 17 deletions lib/src/archive/entry/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,6 @@ use camellia::Camellia256;
use crypto_common::BlockSizeUser;
use std::io;
use std::io::Read;
use std::sync::Mutex;

// NOTE: zstd crate not support Sync + Send trait
pub(super) struct MutexRead<R: Read>(Mutex<R>);

impl<R: Read> MutexRead<R> {
pub(super) fn new(reader: R) -> Self {
Self(Mutex::new(reader))
}
}

impl<R: Read> Read for MutexRead<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let reader = self.0.get_mut().unwrap();
reader.read(buf)
}
}

pub(super) fn aes_ctr_cipher_reader<R: Read>(
mut reader: R,
Expand Down
22 changes: 21 additions & 1 deletion lib/src/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use aes::Aes256;
use camellia::Camellia256;
use cipher::block_padding::Pkcs7;
use ctr::{flavors::Ctr128BE, CtrCore};
use std::io::{self, Write};
use std::io::{self, Read, Write};

type CtrReader<R, C, F> = stream::StreamCipherReader<R, CtrCore<C, F>>;
type CtrWriter<W, C, F> = stream::StreamCipherWriter<W, CtrCore<C, F>>;
Expand Down Expand Up @@ -64,6 +64,26 @@ impl<W: Write> TryIntoInner<W> for CipherWriter<W> {

impl<W: Write> TryIntoInnerWrite<W> for CipherWriter<W> {}

pub(crate) enum DecryptReader<R: Read> {
No(R),
CbcAes(DecryptCbcAes256Reader<R>),
CbcCamellia(DecryptCbcCamellia256Reader<R>),
CtrAes(Ctr128BEReader<R, Aes256>),
CtrCamellia(Ctr128BEReader<R, Camellia256>),
}

impl<R: Read> Read for DecryptReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
DecryptReader::No(r) => r.read(buf),
DecryptReader::CbcAes(r) => r.read(buf),
DecryptReader::CbcCamellia(r) => r.read(buf),
DecryptReader::CtrAes(r) => r.read(buf),
DecryptReader::CtrCamellia(r) => r.read(buf),
}
}
}

#[cfg(test)]
mod tests {
use aes::Aes256;
Expand Down
26 changes: 22 additions & 4 deletions lib/src/compress.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::io::{TryIntoInner, TryIntoInnerWrite};
use flate2::write::ZlibEncoder;
use std::io::{Result, Write};
use xz2::write::XzEncoder;
use zstd::stream::write::Encoder as ZstdEncoder;
use flate2::{read::ZlibDecoder, write::ZlibEncoder};
use std::io::{BufReader, Read, Result, Write};
use xz2::{read::XzDecoder, write::XzEncoder};
use zstd::stream::{read::Decoder as ZStdDecoder, write::Encoder as ZstdEncoder};

mod deflate;
mod xz;
Expand Down Expand Up @@ -47,3 +47,21 @@ impl<'w, W: Write> TryIntoInner<W> for CompressionWriter<'w, W> {
}

impl<'w, W: Write> TryIntoInnerWrite<W> for CompressionWriter<'w, W> {}

pub(crate) enum DecompressReader<'r, R: Read> {
No(R),
Deflate(ZlibDecoder<R>),
ZStd(ZStdDecoder<'r, BufReader<R>>),
Xz(XzDecoder<R>),
}

impl<'r, R: Read> Read for DecompressReader<'r, R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
match self {
DecompressReader::No(r) => r.read(buf),
DecompressReader::Deflate(r) => r.read(buf),
DecompressReader::ZStd(r) => r.read(buf),
DecompressReader::Xz(r) => r.read(buf),
}
}
}

0 comments on commit 14f5864

Please sign in to comment.