use super::{EntryBuilderCore, data_writer};
use crate::{
Metadata, NormalEntry, WriteOptions,
chunk::RawChunk,
cipher::CipherWriter,
compress::CompressionWriter,
entry::{EntryHeader, EntryName, WriteOption},
io::{FlattenWriter, TryIntoInner},
};
#[cfg(feature = "unstable-async")]
use futures_io::AsyncWrite;
use std::{
io::{self, Write},
num::NonZeroU32,
};
#[cfg(feature = "unstable-async")]
use std::{
pin::Pin,
task::{Context, Poll},
};
pub struct FileEntryBuilder {
core: EntryBuilderCore,
data: CompressionWriter<CipherWriter<FlattenWriter>>,
store_file_size: bool,
file_size: u128,
}
impl FileEntryBuilder {
#[inline]
pub fn new(name: EntryName) -> io::Result<Self> {
Self::new_with_options(name, WriteOptions::store())
}
#[inline]
pub fn new_with_options(name: EntryName, option: impl WriteOption) -> io::Result<Self> {
let header = EntryHeader::for_file(
option.compression(),
option.encryption(),
option.cipher_mode(),
name,
);
let (writer, iv, phsf) = data_writer(option)?;
let mut core = EntryBuilderCore::new(header);
core.set_cipher(iv, phsf);
Ok(Self {
core,
data: writer,
store_file_size: true,
file_size: 0,
})
}
#[inline]
pub fn metadata(&mut self, metadata: Metadata) -> &mut Self {
self.core.metadata(metadata);
self
}
#[inline]
pub fn add_extra_chunk<T: Into<RawChunk>>(&mut self, chunk: T) -> &mut Self {
self.core.add_extra_chunk(chunk);
self
}
#[inline]
pub fn max_chunk_size(&mut self, size: NonZeroU32) -> &mut Self {
self.data
.get_mut()
.get_mut()
.set_max_chunk_size(size.get() as usize);
self
}
#[inline]
pub fn store_file_size(&mut self, store: bool) -> &mut Self {
self.store_file_size = store;
self
}
#[inline]
#[must_use = "building an entry without using it is wasteful"]
pub fn build(self) -> io::Result<NormalEntry> {
let data = self.data.try_into_inner()?.try_into_inner()?.inner;
let raw_file_size = self.store_file_size.then_some(self.file_size);
Ok(self.core.build(data, raw_file_size))
}
}
impl Write for FileEntryBuilder {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.data
.write(buf)
.inspect(|len| self.file_size += *len as u128)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.data.flush()
}
}
#[cfg(feature = "unstable-async")]
impl AsyncWrite for FileEntryBuilder {
#[inline]
fn poll_write(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(self.get_mut().write(buf))
}
#[inline]
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(self.get_mut().flush())
}
#[inline]
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}