use std::fs::File;
use std::io::{self, BufReader, Read};
use std::path::Path;
#[cfg(feature = "linux-direct-io")]
use super::direct_reader::DirectReader;
pub enum FileReader {
Buffered(BufReader<File>),
#[cfg(feature = "linux-direct-io")]
Direct(DirectReader),
}
impl FileReader {
pub fn buffered(path: &Path) -> io::Result<Self> {
let f = File::open(path)?;
#[cfg(all(target_os = "linux", any(feature = "linux-direct-io", feature = "linux-io-uring")))]
{
use std::os::unix::io::AsRawFd;
unsafe { libc::posix_fadvise(f.as_raw_fd(), 0, 0, libc::POSIX_FADV_SEQUENTIAL) };
}
Ok(Self::Buffered(BufReader::with_capacity(256 * 1024, f)))
}
#[cfg(feature = "linux-direct-io")]
pub fn direct(path: &Path) -> io::Result<Self> {
Ok(Self::Direct(DirectReader::open(path)?))
}
pub fn open(path: &Path, direct: bool) -> io::Result<Self> {
if direct {
#[cfg(feature = "linux-direct-io")]
{
return Self::direct(path);
}
#[cfg(not(feature = "linux-direct-io"))]
{
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"--direct-io requires the linux-direct-io feature",
));
}
}
Self::buffered(path)
}
}
impl FileReader {
pub(crate) fn skip(&mut self, n: u64) -> io::Result<()> {
if n == 0 {
return Ok(());
}
match self {
Self::Buffered(r) => {
#[allow(clippy::cast_possible_wrap)]
let signed = (n - 1) as i64;
r.seek_relative(signed)?;
let mut sentinel = [0u8; 1];
r.read_exact(&mut sentinel)
}
#[cfg(feature = "linux-direct-io")]
Self::Direct(r) => r.skip(n),
}
}
}
#[cfg(feature = "linux-direct-io")]
impl FileReader {
pub fn raw_fd(&self) -> std::os::unix::io::RawFd {
use std::os::unix::io::AsRawFd;
match self {
Self::Buffered(r) => r.get_ref().as_raw_fd(),
Self::Direct(r) => r.raw_fd(),
}
}
}
impl Read for FileReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Self::Buffered(r) => r.read(buf),
#[cfg(feature = "linux-direct-io")]
Self::Direct(r) => r.read(buf),
}
}
}