use std::borrow::{Cow, ToOwned};
use std::cmp::Ordering;
use std::ffi::{OsStr, OsString};
use std::rc::Rc;
use std::sync::Arc;
use crate::fs;
use crate::io;
use crate::path::{Ancestors, Components, Display, Iter, PathBuf, StripPrefixError};
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Path {
inner: std::path::Path,
}
impl Path {
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
unsafe { &*(std::path::Path::new(s) as *const std::path::Path as *const Path) }
}
pub fn as_os_str(&self) -> &OsStr {
self.inner.as_os_str()
}
pub fn to_str(&self) -> Option<&str> {
self.inner.to_str()
}
pub fn to_string_lossy(&self) -> Cow<'_, str> {
self.inner.to_string_lossy()
}
pub fn to_path_buf(&self) -> PathBuf {
PathBuf::from(self.inner.to_path_buf())
}
pub fn is_absolute(&self) -> bool {
self.inner.is_absolute()
}
pub fn is_relative(&self) -> bool {
self.inner.is_relative()
}
pub fn has_root(&self) -> bool {
self.inner.has_root()
}
pub fn parent(&self) -> Option<&Path> {
self.inner.parent().map(|p| p.into())
}
pub fn ancestors(&self) -> Ancestors<'_> {
Ancestors { next: Some(&self) }
}
pub fn file_name(&self) -> Option<&OsStr> {
self.inner.file_name()
}
pub fn strip_prefix<P>(&self, base: P) -> Result<&Path, StripPrefixError>
where
P: AsRef<Path>,
{
Ok(self.inner.strip_prefix(base.as_ref())?.into())
}
pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
self.inner.starts_with(base.as_ref())
}
pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
self.inner.ends_with(child.as_ref())
}
pub fn file_stem(&self) -> Option<&OsStr> {
self.inner.file_stem()
}
pub fn extension(&self) -> Option<&OsStr> {
self.inner.extension()
}
pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
self.inner.join(path.as_ref()).into()
}
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
self.inner.with_file_name(file_name).into()
}
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
self.inner.with_extension(extension).into()
}
pub fn components(&self) -> Components<'_> {
Components {
inner: self.inner.components(),
}
}
pub fn iter(&self) -> Iter<'_> {
Iter {
inner: self.components(),
}
}
pub fn display(&self) -> Display<'_> {
self.inner.display()
}
pub async fn metadata(&self) -> io::Result<fs::Metadata> {
fs::metadata(self).await
}
pub async fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
fs::symlink_metadata(self).await
}
pub async fn canonicalize(&self) -> io::Result<PathBuf> {
fs::canonicalize(self).await
}
pub async fn read_link(&self) -> io::Result<PathBuf> {
fs::read_link(self).await
}
pub async fn read_dir(&self) -> io::Result<fs::ReadDir> {
fs::read_dir(self).await
}
pub async fn exists(&self) -> bool {
fs::metadata(self).await.is_ok()
}
pub async fn is_file(&self) -> bool {
fs::metadata(self)
.await
.map(|m| m.is_file())
.unwrap_or(false)
}
pub async fn is_dir(&self) -> bool {
fs::metadata(self)
.await
.map(|m| m.is_dir())
.unwrap_or(false)
}
pub fn into_path_buf(self: Box<Path>) -> PathBuf {
let rw = Box::into_raw(self) as *mut std::path::Path;
let inner = unsafe { Box::from_raw(rw) };
inner.into_path_buf().into()
}
}
impl From<&Path> for Box<Path> {
fn from(path: &Path) -> Box<Path> {
let boxed: Box<std::path::Path> = path.inner.into();
let rw = Box::into_raw(boxed) as *mut Path;
unsafe { Box::from_raw(rw) }
}
}
impl From<&Path> for Arc<Path> {
#[inline]
fn from(s: &Path) -> Arc<Path> {
let arc: Arc<OsStr> = Arc::from(s.as_os_str());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
}
}
impl From<&Path> for Rc<Path> {
#[inline]
fn from(s: &Path) -> Rc<Path> {
let rc: Rc<OsStr> = Rc::from(s.as_os_str());
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
}
}
impl ToOwned for Path {
type Owned = PathBuf;
fn to_owned(&self) -> PathBuf {
self.to_path_buf()
}
}
impl AsRef<OsStr> for Path {
fn as_ref(&self) -> &OsStr {
self.inner.as_ref()
}
}
impl AsRef<Path> for Path {
fn as_ref(&self) -> &Path {
self
}
}
impl AsRef<Path> for OsStr {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl<'a> From<&'a Path> for Cow<'a, Path> {
#[inline]
fn from(s: &'a Path) -> Cow<'a, Path> {
Cow::Borrowed(s)
}
}
impl AsRef<Path> for Cow<'_, OsStr> {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for OsString {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for str {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for String {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for PathBuf {
fn as_ref(&self) -> &Path {
self
}
}
impl<'a> IntoIterator for &'a PathBuf {
type Item = &'a OsStr;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
impl<'a> IntoIterator for &'a Path {
type Item = &'a OsStr;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
macro_rules! impl_cmp {
($lhs:ty, $rhs: ty) => {
impl<'a, 'b> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
<Path as PartialEq>::eq(self, other)
}
}
impl<'a, 'b> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
<Path as PartialEq>::eq(self, other)
}
}
impl<'a, 'b> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
<Path as PartialOrd>::partial_cmp(self, other)
}
}
impl<'a, 'b> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
<Path as PartialOrd>::partial_cmp(self, other)
}
}
};
}
impl_cmp!(PathBuf, Path);
impl_cmp!(PathBuf, &'a Path);
impl_cmp!(Cow<'a, Path>, Path);
impl_cmp!(Cow<'a, Path>, &'b Path);
impl_cmp!(Cow<'a, Path>, PathBuf);
macro_rules! impl_cmp_os_str {
($lhs:ty, $rhs: ty) => {
impl<'a, 'b> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
<Path as PartialEq>::eq(self, other.as_ref())
}
}
impl<'a, 'b> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
<Path as PartialEq>::eq(self.as_ref(), other)
}
}
impl<'a, 'b> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
<Path as PartialOrd>::partial_cmp(self, other.as_ref())
}
}
impl<'a, 'b> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
<Path as PartialOrd>::partial_cmp(self.as_ref(), other)
}
}
};
}
impl_cmp_os_str!(PathBuf, OsStr);
impl_cmp_os_str!(PathBuf, &'a OsStr);
impl_cmp_os_str!(PathBuf, Cow<'a, OsStr>);
impl_cmp_os_str!(PathBuf, OsString);
impl_cmp_os_str!(Path, OsStr);
impl_cmp_os_str!(Path, &'a OsStr);
impl_cmp_os_str!(Path, Cow<'a, OsStr>);
impl_cmp_os_str!(Path, OsString);
impl_cmp_os_str!(&'a Path, OsStr);
impl_cmp_os_str!(&'a Path, Cow<'b, OsStr>);
impl_cmp_os_str!(&'a Path, OsString);
impl<'a> From<&'a std::path::Path> for &'a Path {
fn from(path: &'a std::path::Path) -> &'a Path {
&Path::new(path.as_os_str())
}
}
impl<'a> Into<&'a std::path::Path> for &'a Path {
fn into(self) -> &'a std::path::Path {
std::path::Path::new(&self.inner)
}
}
impl AsRef<std::path::Path> for Path {
fn as_ref(&self) -> &std::path::Path {
self.into()
}
}
impl AsRef<Path> for std::path::Path {
fn as_ref(&self) -> &Path {
self.into()
}
}
impl AsRef<Path> for std::path::PathBuf {
fn as_ref(&self) -> &Path {
let p: &std::path::Path = self.as_ref();
p.into()
}
}