Skip to content

Commit

Permalink
🐎 Add private method write_in for reduce copy
Browse files Browse the repository at this point in the history
  • Loading branch information
ChanTsune committed Feb 19, 2024
1 parent 49a18f2 commit de1baed
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 9 deletions.
95 changes: 93 additions & 2 deletions lib/src/archive/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ use crate::{
};
use std::{
collections::VecDeque,
io::{self, Read},
io::{self, Read, Write},
time::Duration,
};

mod private {
use super::*;
pub trait SealedEntryExt {
fn into_chunks(self) -> Vec<RawChunk>;
fn write_in<W: Write>(&self, writer: &mut W) -> io::Result<usize>;
}
}

Expand All @@ -45,6 +46,13 @@ impl SealedEntryExt for EntryContainer {
Self::Solid(s) => s.into_chunks(),
}
}

fn write_in<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
match self {
EntryContainer::Regular(r) => r.write_in(writer),
EntryContainer::Solid(s) => s.write_in(writer),
}
}
}

impl Entry for EntryContainer {
Expand Down Expand Up @@ -74,6 +82,14 @@ impl SealedEntryExt for ChunkEntry {
fn into_chunks(self) -> Vec<RawChunk> {
self.0
}

fn write_in<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
let mut total = 0;
for chunk in self.0.iter() {
total += chunk.write_in(writer)?;
}
Ok(total)
}
}

impl Entry for ChunkEntry {
Expand Down Expand Up @@ -199,6 +215,20 @@ impl SealedEntryExt for SolidReadEntry {
chunks.push(RawChunk::from_data(ChunkType::SEND, Vec::new()));
chunks
}

fn write_in<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
let mut total = 0;
total += (ChunkType::SHED, self.header.to_bytes().as_slice()).write_in(writer)?;

if let Some(phsf) = &self.phsf {
total += (ChunkType::PHSF, phsf.as_bytes()).write_in(writer)?;
}
for data in &self.data {
total += (ChunkType::SDAT, data.as_slice()).write_in(writer)?;
}
total += (ChunkType::SEND, [].as_slice()).write_in(writer)?;
Ok(total)
}
}

#[allow(deprecated)]
Expand Down Expand Up @@ -431,14 +461,67 @@ impl SealedEntryExt for RegularEntry {
vec.push(RawChunk::from_data(
ChunkType::aTIM,
a.as_secs().to_be_bytes(),
))
));
}
if let Some(p) = permission {
vec.push(RawChunk::from_data(ChunkType::fPRM, p.to_bytes()));
}
vec.push(RawChunk::from_data(ChunkType::FEND, Vec::new()));
vec
}

fn write_in<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
let mut total = 0;

let Metadata {
raw_file_size,
compressed_size: _,
created,
modified,
accessed,
permission,
} = &self.metadata;

total += (ChunkType::FHED, self.header.to_bytes()).write_in(writer)?;

if let Some(raw_file_size) = raw_file_size {
total += (
ChunkType::fSIZ,
raw_file_size
.to_be_bytes()
.into_iter()
.skip_while(|i| *i == 0)
.collect::<Vec<_>>(),
)
.write_in(writer)?;
}

if let Some(p) = &self.phsf {
total += (ChunkType::PHSF, p.as_bytes()).write_in(writer)?;
}
for ex in &self.extra {
total += ex.write_in(writer)?;
}
for data_chunk in &self.data {
for data_unit in data_chunk.chunks(u32::MAX as usize) {
total += (ChunkType::FDAT, data_unit).write_in(writer)?;
}
}
if let Some(c) = created {
total += (ChunkType::cTIM, c.as_secs().to_be_bytes().as_slice()).write_in(writer)?;
}
if let Some(d) = modified {
total += (ChunkType::mTIM, d.as_secs().to_be_bytes().as_slice()).write_in(writer)?;
}
if let Some(a) = accessed {
total += (ChunkType::aTIM, a.as_secs().to_be_bytes().as_slice()).write_in(writer)?;
}
if let Some(p) = permission {
total += (ChunkType::fPRM, p.to_bytes()).write_in(writer)?;
}
total += (ChunkType::FEND, [].as_slice()).write_in(writer)?;
Ok(total)
}
}

impl Entry for RegularEntry {
Expand Down Expand Up @@ -627,6 +710,14 @@ impl SealedEntryExt for ChunkSolidEntries {
fn into_chunks(self) -> Vec<RawChunk> {
self.0
}

fn write_in<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
let mut total = 0;
for chunk in self.0.iter() {
total += chunk.write_in(writer)?;
}
Ok(total)
}
}

fn timestamp(bytes: &[u8]) -> io::Result<Duration> {
Expand Down
8 changes: 5 additions & 3 deletions lib/src/archive/entry/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
archive::entry::{
writer_and_hash, DataKind, Entry, EntryContainer, EntryHeader, EntryName, EntryReference,
Metadata, Permission, RegularEntry, SolidHeader, SolidReadEntry, WriteOption,
private::SealedEntryExt, writer_and_hash, DataKind, Entry, EntryContainer, EntryHeader,
EntryName, EntryReference, Metadata, Permission, RegularEntry, SolidHeader, SolidReadEntry,
WriteOption,
},
cipher::CipherWriter,
compress::CompressionWriter,
Expand Down Expand Up @@ -349,7 +350,8 @@ impl SolidEntryBuilder {
/// # }
/// ```
pub fn add_entry(&mut self, entry: RegularEntry) -> io::Result<()> {
self.data.write_all(&entry.into_bytes())
entry.write_in(&mut self.data)?;
Ok(())
}

fn build_as_entry(self) -> io::Result<SolidReadEntry> {
Expand Down
4 changes: 1 addition & 3 deletions lib/src/archive/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,7 @@ impl<W: Write> Archive<W> {
/// }
/// ```
pub fn add_entry(&mut self, entry: impl Entry) -> io::Result<usize> {
let bytes = entry.into_bytes();
self.inner.write_all(&bytes)?;
Ok(bytes.len())
entry.write_in(&mut self.inner)
}

/// Adds a part of an entry to the archive.
Expand Down
14 changes: 13 additions & 1 deletion lib/src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ mod write;
use self::crc::Crc32;
pub(crate) use self::{read::ChunkReader, write::ChunkWriter};
pub use self::{traits::*, types::*};
use std::{mem, ops::Deref};
use std::{
io::{self, Write},
mem,
ops::Deref,
};

/// Minimum required size of bytes to represent [`Chunk`].
pub const MIN_CHUNK_BYTES_SIZE: usize = 12;
Expand All @@ -22,6 +26,14 @@ pub(crate) trait ChunkExt: Chunk {
fn is_stream_chunk(&self) -> bool {
self.ty() == ChunkType::FDAT || self.ty() == ChunkType::SDAT
}

fn write_in<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
writer.write_all(&self.length().to_be_bytes())?;
writer.write_all(&self.ty().0)?;
writer.write_all(self.data())?;
writer.write_all(&self.crc().to_be_bytes())?;
Ok(self.bytes_len())
}
}

impl<T> ChunkExt for T where T: Chunk {}
Expand Down

0 comments on commit de1baed

Please sign in to comment.