use std::fs;
use std::io::{self, Read, Seek, Write};
use std::path::{Path, PathBuf};
use crate::errors::{Error, ErrorKind};
#[derive(Debug)]
pub struct File {
file: fs::File,
path: PathBuf,
}
pub(crate) fn open(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
fs::File::open(path).map_err(|err| |path| Error::build(err, ErrorKind::OpenFile, path))
}
pub(crate) fn create(path: &Path) -> Result<std::fs::File, impl FnOnce(PathBuf) -> io::Error> {
fs::File::create(path).map_err(|err| |path| Error::build(err, ErrorKind::CreateFile, path))
}
impl File {
pub fn open<P>(path: P) -> Result<Self, io::Error>
where
P: Into<PathBuf>,
{
let path = path.into();
match open(&path) {
Ok(file) => Ok(File::from_parts(file, path)),
Err(err_gen) => Err(err_gen(path)),
}
}
pub fn create<P>(path: P) -> Result<Self, io::Error>
where
P: Into<PathBuf>,
{
let path = path.into();
match create(&path) {
Ok(file) => Ok(File::from_parts(file, path)),
Err(err_gen) => Err(err_gen(path)),
}
}
#[deprecated = "use fs_err::OpenOptions::open instead"]
pub fn from_options<P>(path: P, options: &fs::OpenOptions) -> Result<Self, io::Error>
where
P: Into<PathBuf>,
{
let path = path.into();
match options.open(&path) {
Ok(file) => Ok(File::from_parts(file, path)),
Err(source) => Err(Error::build(source, ErrorKind::OpenFile, path)),
}
}
pub fn sync_all(&self) -> Result<(), io::Error> {
self.file
.sync_all()
.map_err(|source| self.error(source, ErrorKind::SyncFile))
}
pub fn sync_data(&self) -> Result<(), io::Error> {
self.file
.sync_data()
.map_err(|source| self.error(source, ErrorKind::SyncFile))
}
pub fn set_len(&self, size: u64) -> Result<(), io::Error> {
self.file
.set_len(size)
.map_err(|source| self.error(source, ErrorKind::SetLen))
}
pub fn metadata(&self) -> Result<fs::Metadata, io::Error> {
self.file
.metadata()
.map_err(|source| self.error(source, ErrorKind::Metadata))
}
pub fn try_clone(&self) -> Result<Self, io::Error> {
self.file
.try_clone()
.map(|file| File {
file,
path: self.path.clone(),
})
.map_err(|source| self.error(source, ErrorKind::Clone))
}
pub fn set_permissions(&self, perm: fs::Permissions) -> Result<(), io::Error> {
self.file
.set_permissions(perm)
.map_err(|source| self.error(source, ErrorKind::SetPermissions))
}
}
impl File {
pub fn from_parts<P>(file: fs::File, path: P) -> Self
where
P: Into<PathBuf>,
{
File {
file,
path: path.into(),
}
}
pub fn into_parts(self) -> (fs::File, PathBuf) {
(self.file, self.path)
}
pub fn file(&self) -> &fs::File {
&self.file
}
pub fn file_mut(&mut self) -> &mut fs::File {
&mut self.file
}
pub fn path(&self) -> &Path {
&self.path
}
fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error {
Error::build(source, kind, &self.path)
}
}
impl Read for File {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.file
.read(buf)
.map_err(|source| self.error(source, ErrorKind::Read))
}
fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
self.file
.read_vectored(bufs)
.map_err(|source| self.error(source, ErrorKind::Read))
}
}
impl<'a> Read for &'a File {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
(&self.file)
.read(buf)
.map_err(|source| self.error(source, ErrorKind::Read))
}
fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
(&self.file)
.read_vectored(bufs)
.map_err(|source| self.error(source, ErrorKind::Read))
}
}
impl From<File> for fs::File {
fn from(file: File) -> Self {
file.into_parts().0
}
}
impl Seek for File {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.file
.seek(pos)
.map_err(|source| self.error(source, ErrorKind::Seek))
}
}
impl<'a> Seek for &'a File {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
(&self.file)
.seek(pos)
.map_err(|source| self.error(source, ErrorKind::Seek))
}
}
impl Write for File {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.file
.write(buf)
.map_err(|source| self.error(source, ErrorKind::Write))
}
fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
self.file
.write_vectored(bufs)
.map_err(|source| self.error(source, ErrorKind::Write))
}
fn flush(&mut self) -> std::io::Result<()> {
self.file
.flush()
.map_err(|source| self.error(source, ErrorKind::Flush))
}
}
impl<'a> Write for &'a File {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
(&self.file)
.write(buf)
.map_err(|source| self.error(source, ErrorKind::Write))
}
fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
(&self.file)
.write_vectored(bufs)
.map_err(|source| self.error(source, ErrorKind::Write))
}
fn flush(&mut self) -> std::io::Result<()> {
(&self.file)
.flush()
.map_err(|source| self.error(source, ErrorKind::Flush))
}
}
#[cfg(unix)]
mod unix {
use crate::os::unix::fs::FileExt;
use crate::ErrorKind;
use std::io;
use std::os::unix::fs::FileExt as _;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
impl AsRawFd for crate::File {
fn as_raw_fd(&self) -> RawFd {
self.file().as_raw_fd()
}
}
impl IntoRawFd for crate::File {
fn into_raw_fd(self) -> RawFd {
self.file.into_raw_fd()
}
}
impl FileExt for crate::File {
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.file()
.read_at(buf, offset)
.map_err(|err| self.error(err, ErrorKind::ReadAt))
}
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.file()
.write_at(buf, offset)
.map_err(|err| self.error(err, ErrorKind::WriteAt))
}
}
#[cfg(feature = "io_safety")]
mod io_safety {
use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
#[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl AsFd for crate::File {
fn as_fd(&self) -> BorrowedFd<'_> {
self.file().as_fd()
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl From<crate::File> for OwnedFd {
fn from(file: crate::File) -> Self {
file.into_parts().0.into()
}
}
}
}
#[cfg(windows)]
mod windows {
use crate::os::windows::fs::FileExt;
use crate::ErrorKind;
use std::io;
use std::os::windows::{
fs::FileExt as _,
io::{AsRawHandle, IntoRawHandle, RawHandle},
};
impl FileExt for crate::File {
fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.file()
.seek_read(buf, offset)
.map_err(|err| self.error(err, ErrorKind::SeekRead))
}
fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.file()
.seek_write(buf, offset)
.map_err(|err| self.error(err, ErrorKind::SeekWrite))
}
}
impl AsRawHandle for crate::File {
fn as_raw_handle(&self) -> RawHandle {
self.file().as_raw_handle()
}
}
impl IntoRawHandle for crate::File {
fn into_raw_handle(self) -> RawHandle {
self.file.into_raw_handle()
}
}
#[cfg(feature = "io_safety")]
mod io_safety {
use std::os::windows::io::{AsHandle, BorrowedHandle, OwnedHandle};
#[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl AsHandle for crate::File {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.file().as_handle()
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "io_safety")))]
impl From<crate::File> for OwnedHandle {
fn from(file: crate::File) -> Self {
file.into_parts().0.into()
}
}
}
}