use crate::fs::{open_unchecked, OpenOptions};
use maybe_owned::MaybeOwned;
use std::ops::Deref;
use std::path::Component;
use std::{fmt, fs, io, mem};
#[cfg(racy_asserts)]
use {crate::fs::file_path, std::path::PathBuf};
pub(super) struct MaybeOwnedFile<'borrow> {
inner: MaybeOwned<'borrow, fs::File>,
#[cfg(racy_asserts)]
path: Option<PathBuf>,
}
impl<'borrow> MaybeOwnedFile<'borrow> {
pub(super) fn borrowed(file: &'borrow fs::File) -> Self {
#[cfg(racy_asserts)]
let path = file_path(file);
Self {
inner: MaybeOwned::Borrowed(file),
#[cfg(racy_asserts)]
path,
}
}
pub(super) fn owned(file: fs::File) -> Self {
#[cfg(racy_asserts)]
let path = file_path(&file);
Self {
inner: MaybeOwned::Owned(file),
#[cfg(racy_asserts)]
path,
}
}
#[allow(dead_code)]
pub(super) const fn borrowed_noassert(file: &'borrow fs::File) -> Self {
Self {
inner: MaybeOwned::Borrowed(file),
#[cfg(racy_asserts)]
path: None,
}
}
#[allow(dead_code)]
pub(super) const fn owned_noassert(file: fs::File) -> Self {
Self {
inner: MaybeOwned::Owned(file),
#[cfg(racy_asserts)]
path: None,
}
}
pub(super) fn descend_to(&mut self, to: MaybeOwnedFile<'borrow>) -> Self {
#[cfg(racy_asserts)]
let path = self.path.clone();
#[cfg(racy_asserts)]
if let Some(to_path) = file_path(&to) {
if let Some(current_path) = &self.path {
assert!(
to_path.starts_with(current_path),
"attempted to descend from {:?} to {:?}",
to_path.display(),
current_path.display()
);
}
self.path = Some(to_path);
}
Self {
inner: mem::replace(&mut self.inner, to.inner),
#[cfg(racy_asserts)]
path,
}
}
pub(super) fn into_file(self, options: &OpenOptions) -> io::Result<fs::File> {
match self.inner {
MaybeOwned::Owned(file) => Ok(file),
MaybeOwned::Borrowed(file) => {
open_unchecked(file, Component::CurDir.as_ref(), options).map_err(Into::into)
}
}
}
#[cfg_attr(windows, allow(dead_code))]
pub(super) fn unwrap_owned(self) -> fs::File {
match self.inner {
MaybeOwned::Owned(file) => file,
MaybeOwned::Borrowed(_) => panic!("expected owned file"),
}
}
}
impl<'borrow> Deref for MaybeOwnedFile<'borrow> {
type Target = fs::File;
#[inline]
fn deref(&self) -> &Self::Target {
self.inner.as_ref()
}
}
impl<'borrow> fmt::Debug for MaybeOwnedFile<'borrow> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.deref().fmt(f)
}
}