use std::{
fs::{File as StdFile, OpenOptions},
io::{self, BufReader, BufWriter, Read, Write},
path::Path,
};
use crate::MANIFEST_DELETIONS_REWRITE_THRESHOLD;
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FileOptions {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
read_buffer_size: Option<usize>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
write_buffer_size: Option<usize>,
}
impl Default for FileOptions {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl FileOptions {
#[inline]
pub const fn new() -> Self {
Self {
read_buffer_size: None,
write_buffer_size: None,
}
}
#[inline]
pub const fn read_buffer_size(mut self, size: usize) -> Self {
self.read_buffer_size = Some(size);
self
}
#[inline]
pub const fn write_buffer_size(mut self, size: usize) -> Self {
self.write_buffer_size = Some(size);
self
}
}
pub struct File {
reader: BufReader<StdFile>,
writer: BufWriter<StdFile>,
}
impl BackedFile for File {
type Options = FileOptions;
type Error = io::Error;
fn open<P: AsRef<Path>>(path: P, opts: Self::Options) -> Result<(bool, Self), Self::Error>
where
Self: Sized,
{
let path = path.as_ref();
let existing = path.exists();
OpenOptions::new()
.read(true)
.create(true)
.truncate(false)
.append(true)
.open(path)
.and_then(|f| {
Ok((
existing,
Self {
reader: BufReader::with_capacity(
opts
.read_buffer_size
.unwrap_or(MANIFEST_DELETIONS_REWRITE_THRESHOLD as usize),
f.try_clone()?,
),
writer: BufWriter::with_capacity(
opts
.write_buffer_size
.unwrap_or(MANIFEST_DELETIONS_REWRITE_THRESHOLD as usize),
f,
),
},
))
})
}
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
self.reader.read_exact(buf)
}
fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> {
self.writer.write_all(data)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.writer.get_ref().sync_data()
}
fn sync_all(&self) -> Result<(), Self::Error> {
self.writer.get_ref().sync_all()
}
fn truncate(&mut self, len: u64) -> Result<(), Self::Error> {
self.writer.get_ref().set_len(len)
}
fn size(&self) -> Result<u64, Self::Error> {
self
.reader
.get_ref()
.metadata()
.map(|m| m.len())
.map_err(Into::into)
}
}