use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::collections::TryReserveError;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::borrow::Borrow;
use core::hash::{Hash, Hasher};
use core::iter::FusedIterator;
use core::ops::{self, Deref};
use core::str::FromStr;
use core::{cmp, fmt};
use crate::ffi::{OsStr, OsString};
use crate::sys_path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix};
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub enum Prefix<'a> {
Verbatim(&'a OsStr),
VerbatimUNC(&'a OsStr, &'a OsStr),
VerbatimDisk(u8),
DeviceNS(&'a OsStr),
UNC(&'a OsStr, &'a OsStr),
Disk(u8),
}
impl<'a> Prefix<'a> {
#[inline]
fn len(&self) -> usize {
use self::Prefix::*;
fn os_str_len(s: &OsStr) -> usize {
s.as_encoded_bytes().len()
}
match *self {
Verbatim(x) => 4 + os_str_len(x),
VerbatimUNC(x, y) => {
8 + os_str_len(x) + if os_str_len(y) > 0 { 1 + os_str_len(y) } else { 0 }
}
VerbatimDisk(_) => 6,
UNC(x, y) => {
2 + os_str_len(x) + if os_str_len(y) > 0 { 1 + os_str_len(y) } else { 0 }
}
DeviceNS(x) => 4 + os_str_len(x),
Disk(_) => 2,
}
}
#[inline]
#[must_use]
pub fn is_verbatim(&self) -> bool {
use self::Prefix::*;
matches!(*self, Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..))
}
#[inline]
fn is_drive(&self) -> bool {
matches!(*self, Prefix::Disk(_))
}
#[inline]
fn has_implicit_root(&self) -> bool {
!self.is_drive()
}
}
#[must_use]
pub fn is_separator(c: char) -> bool {
c.is_ascii() && is_sep_byte(c as u8)
}
pub const MAIN_SEPARATOR: char = crate::sys_path::MAIN_SEP;
pub const MAIN_SEPARATOR_STR: &str = crate::sys_path::MAIN_SEP_STR;
fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
where
I: Iterator<Item = Component<'a>> + Clone,
J: Iterator<Item = Component<'b>>,
{
loop {
let mut iter_next = iter.clone();
match (iter_next.next(), prefix.next()) {
(Some(ref x), Some(ref y)) if x == y => (),
(Some(_), Some(_)) => return None,
(Some(_), None) => return Some(iter),
(None, None) => return Some(iter),
(None, Some(_)) => return None,
}
iter = iter_next;
}
}
fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool {
let path = if let Some(p) = prefix { &s[p.len()..] } else { s };
!path.is_empty() && is_sep_byte(path[0])
}
fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
if file.as_encoded_bytes() == b".." {
return (Some(file), None);
}
let mut iter = file.as_encoded_bytes().rsplitn(2, |b| *b == b'.');
let after = iter.next();
let before = iter.next();
if before == Some(b"") {
(Some(file), None)
} else {
unsafe {
(
before.map(|s| OsStr::from_encoded_bytes_unchecked(s)),
after.map(|s| OsStr::from_encoded_bytes_unchecked(s)),
)
}
}
}
fn validate_extension(extension: &OsStr) {
for &b in extension.as_encoded_bytes() {
if is_sep_byte(b) {
panic!("extension cannot contain path separators: {extension:?}");
}
}
}
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
enum State {
Prefix = 0, StartDir = 1, Body = 2, Done = 3,
}
#[derive(Copy, Clone, Eq, Debug)]
pub struct PrefixComponent<'a> {
raw: &'a OsStr,
parsed: Prefix<'a>,
}
impl<'a> PrefixComponent<'a> {
#[must_use]
#[inline]
pub fn kind(&self) -> Prefix<'a> {
self.parsed
}
#[must_use]
#[inline]
pub fn as_os_str(&self) -> &'a OsStr {
self.raw
}
}
impl<'a> PartialEq for PrefixComponent<'a> {
#[inline]
fn eq(&self, other: &PrefixComponent<'a>) -> bool {
self.parsed == other.parsed
}
}
impl<'a> PartialOrd for PrefixComponent<'a> {
#[inline]
fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PrefixComponent<'_> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
Ord::cmp(&self.parsed, &other.parsed)
}
}
impl Hash for PrefixComponent<'_> {
fn hash<H: Hasher>(&self, h: &mut H) {
self.parsed.hash(h);
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Component<'a> {
Prefix(PrefixComponent<'a>),
RootDir,
CurDir,
ParentDir,
Normal(&'a OsStr),
}
impl<'a> Component<'a> {
#[must_use = "`self` will be dropped if the result is not used"]
pub fn as_os_str(self) -> &'a OsStr {
match self {
Component::Prefix(p) => p.as_os_str(),
Component::RootDir => OsStr::new(MAIN_SEP_STR),
Component::CurDir => OsStr::new("."),
Component::ParentDir => OsStr::new(".."),
Component::Normal(path) => path,
}
}
}
impl AsRef<OsStr> for Component<'_> {
#[inline]
fn as_ref(&self) -> &OsStr {
self.as_os_str()
}
}
impl AsRef<Path> for Component<'_> {
#[inline]
fn as_ref(&self) -> &Path {
self.as_os_str().as_ref()
}
}
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Components<'a> {
path: &'a [u8],
prefix: Option<Prefix<'a>>,
has_physical_root: bool,
front: State,
back: State,
}
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a> {
inner: Components<'a>,
}
impl fmt::Debug for Components<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct DebugHelper<'a>(&'a Path);
impl fmt::Debug for DebugHelper<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.components()).finish()
}
}
f.debug_tuple("Components").field(&DebugHelper(self.as_path())).finish()
}
}
impl<'a> Components<'a> {
#[inline]
fn prefix_len(&self) -> usize {
if !HAS_PREFIXES {
return 0;
}
self.prefix.as_ref().map(Prefix::len).unwrap_or(0)
}
#[inline]
fn prefix_verbatim(&self) -> bool {
if !HAS_PREFIXES {
return false;
}
self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false)
}
#[inline]
fn prefix_remaining(&self) -> usize {
if !HAS_PREFIXES {
return 0;
}
if self.front == State::Prefix { self.prefix_len() } else { 0 }
}
#[inline]
fn len_before_body(&self) -> usize {
let root = if self.front <= State::StartDir && self.has_physical_root { 1 } else { 0 };
let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() { 1 } else { 0 };
self.prefix_remaining() + root + cur_dir
}
#[inline]
fn finished(&self) -> bool {
self.front == State::Done || self.back == State::Done || self.front > self.back
}
#[inline]
fn is_sep_byte(&self, b: u8) -> bool {
if self.prefix_verbatim() { is_verbatim_sep(b) } else { is_sep_byte(b) }
}
#[must_use]
pub fn as_path(&self) -> &'a Path {
let mut comps = self.clone();
if comps.front == State::Body {
comps.trim_left();
}
if comps.back == State::Body {
comps.trim_right();
}
unsafe { Path::from_u8_slice(comps.path) }
}
fn has_root(&self) -> bool {
if self.has_physical_root {
return true;
}
if HAS_PREFIXES && let Some(p) = self.prefix
&& p.has_implicit_root()
{
return true;
}
false
}
fn include_cur_dir(&self) -> bool {
if self.has_root() {
return false;
}
let slice = &self.path[self.prefix_remaining()..];
match slice {
[b'.'] => true,
[b'.', b, ..] => self.is_sep_byte(*b),
_ => false,
}
}
unsafe fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> {
match comp {
b"." if HAS_PREFIXES && self.prefix_verbatim() => Some(Component::CurDir),
b"." => None, b".." => Some(Component::ParentDir),
b"" => None,
_ => Some(Component::Normal(unsafe { OsStr::from_encoded_bytes_unchecked(comp) })),
}
}
fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
debug_assert!(self.front == State::Body);
let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) {
None => (0, self.path),
Some(i) => (1, &self.path[..i]),
};
(comp.len() + extra, unsafe { self.parse_single_component(comp) })
}
fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
debug_assert!(self.back == State::Body);
let start = self.len_before_body();
let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) {
None => (0, &self.path[start..]),
Some(i) => (1, &self.path[start + i + 1..]),
};
(comp.len() + extra, unsafe { self.parse_single_component(comp) })
}
fn trim_left(&mut self) {
while !self.path.is_empty() {
let (size, comp) = self.parse_next_component();
if comp.is_some() {
return;
} else {
self.path = &self.path[size..];
}
}
}
fn trim_right(&mut self) {
while self.path.len() > self.len_before_body() {
let (size, comp) = self.parse_next_component_back();
if comp.is_some() {
return;
} else {
self.path = &self.path[..self.path.len() - size];
}
}
}
}
impl AsRef<Path> for Components<'_> {
#[inline]
fn as_ref(&self) -> &Path {
self.as_path()
}
}
impl AsRef<OsStr> for Components<'_> {
#[inline]
fn as_ref(&self) -> &OsStr {
self.as_path().as_os_str()
}
}
impl fmt::Debug for Iter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct DebugHelper<'a>(&'a Path);
impl fmt::Debug for DebugHelper<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.iter()).finish()
}
}
f.debug_tuple("Iter").field(&DebugHelper(self.as_path())).finish()
}
}
impl<'a> Iter<'a> {
#[must_use]
#[inline]
pub fn as_path(&self) -> &'a Path {
self.inner.as_path()
}
}
impl AsRef<Path> for Iter<'_> {
#[inline]
fn as_ref(&self) -> &Path {
self.as_path()
}
}
impl AsRef<OsStr> for Iter<'_> {
#[inline]
fn as_ref(&self) -> &OsStr {
self.as_path().as_os_str()
}
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a OsStr;
#[inline]
fn next(&mut self) -> Option<&'a OsStr> {
self.inner.next().map(Component::as_os_str)
}
}
impl<'a> DoubleEndedIterator for Iter<'a> {
#[inline]
fn next_back(&mut self) -> Option<&'a OsStr> {
self.inner.next_back().map(Component::as_os_str)
}
}
impl FusedIterator for Iter<'_> {}
impl<'a> Iterator for Components<'a> {
type Item = Component<'a>;
fn next(&mut self) -> Option<Component<'a>> {
while !self.finished() {
match self.front {
State::Body if !self.path.is_empty() => {
let (size, comp) = self.parse_next_component();
self.path = &self.path[size..];
if comp.is_some() {
return comp;
}
}
State::Body => {
self.front = State::Done;
}
State::StartDir => {
self.front = State::Body;
if self.has_physical_root {
debug_assert!(!self.path.is_empty());
self.path = &self.path[1..];
return Some(Component::RootDir);
} else if HAS_PREFIXES && let Some(p) = self.prefix {
if p.has_implicit_root() && !p.is_verbatim() {
return Some(Component::RootDir);
}
} else if self.include_cur_dir() {
debug_assert!(!self.path.is_empty());
self.path = &self.path[1..];
return Some(Component::CurDir);
}
}
_ if !HAS_PREFIXES => unreachable!(),
State::Prefix if self.prefix_len() == 0 => {
self.front = State::StartDir;
}
State::Prefix => {
self.front = State::StartDir;
debug_assert!(self.prefix_len() <= self.path.len());
let raw = &self.path[..self.prefix_len()];
self.path = &self.path[self.prefix_len()..];
return Some(Component::Prefix(PrefixComponent {
raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) },
parsed: self.prefix.unwrap(),
}));
}
State::Done => unreachable!(),
}
}
None
}
}
impl<'a> DoubleEndedIterator for Components<'a> {
fn next_back(&mut self) -> Option<Component<'a>> {
while !self.finished() {
match self.back {
State::Body if self.path.len() > self.len_before_body() => {
let (size, comp) = self.parse_next_component_back();
self.path = &self.path[..self.path.len() - size];
if comp.is_some() {
return comp;
}
}
State::Body => {
self.back = State::StartDir;
}
State::StartDir => {
self.back = if HAS_PREFIXES { State::Prefix } else { State::Done };
if self.has_physical_root {
self.path = &self.path[..self.path.len() - 1];
return Some(Component::RootDir);
} else if HAS_PREFIXES && let Some(p) = self.prefix {
if p.has_implicit_root() && !p.is_verbatim() {
return Some(Component::RootDir);
}
} else if self.include_cur_dir() {
self.path = &self.path[..self.path.len() - 1];
return Some(Component::CurDir);
}
}
_ if !HAS_PREFIXES => unreachable!(),
State::Prefix if self.prefix_len() > 0 => {
self.back = State::Done;
return Some(Component::Prefix(PrefixComponent {
raw: unsafe { OsStr::from_encoded_bytes_unchecked(self.path) },
parsed: self.prefix.unwrap(),
}));
}
State::Prefix => {
self.back = State::Done;
return None;
}
State::Done => unreachable!(),
}
}
None
}
}
impl FusedIterator for Components<'_> {}
impl<'a> PartialEq for Components<'a> {
#[inline]
fn eq(&self, other: &Components<'a>) -> bool {
let Components { path: _, front: _, back: _, has_physical_root: _, prefix: _ } = self;
if self.path.len() == other.path.len()
&& self.front == other.front
&& self.back == State::Body
&& other.back == State::Body
&& self.prefix_verbatim() == other.prefix_verbatim()
&& self.path == other.path
{
return true;
}
Iterator::eq(self.clone().rev(), other.clone().rev())
}
}
impl Eq for Components<'_> {}
impl<'a> PartialOrd for Components<'a> {
#[inline]
fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Components<'_> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
compare_components(self.clone(), other.clone())
}
}
fn compare_components(mut left: Components<'_>, mut right: Components<'_>) -> cmp::Ordering {
if left.prefix.is_none() && right.prefix.is_none() && left.front == right.front {
let first_difference = match left.path.iter().zip(right.path).position(|(&a, &b)| a != b) {
None if left.path.len() == right.path.len() => return cmp::Ordering::Equal,
None => left.path.len().min(right.path.len()),
Some(diff) => diff,
};
if let Some(previous_sep) =
left.path[..first_difference].iter().rposition(|&b| left.is_sep_byte(b))
{
let mismatched_component_start = previous_sep + 1;
left.path = &left.path[mismatched_component_start..];
left.front = State::Body;
right.path = &right.path[mismatched_component_start..];
right.front = State::Body;
}
}
Iterator::cmp(left, right)
}
#[derive(Copy, Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Ancestors<'a> {
next: Option<&'a Path>,
}
impl<'a> Iterator for Ancestors<'a> {
type Item = &'a Path;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let next = self.next;
self.next = next.and_then(Path::parent);
next
}
}
impl FusedIterator for Ancestors<'_> {}
pub struct PathBuf {
inner: OsString,
}
impl PathBuf {
#[must_use]
#[inline]
pub const fn new() -> PathBuf {
PathBuf { inner: OsString::new() }
}
#[must_use]
#[inline]
pub fn with_capacity(capacity: usize) -> PathBuf {
PathBuf { inner: OsString::with_capacity(capacity) }
}
#[must_use]
#[inline]
pub fn as_path(&self) -> &Path {
self
}
pub fn push<P: AsRef<Path>>(&mut self, path: P) {
self._push(path.as_ref())
}
fn _push(&mut self, path: &Path) {
let buf = self.inner.as_encoded_bytes();
let mut need_sep = buf.last().map(|c| !is_sep_byte(*c)).unwrap_or(false);
let comps = self.components();
if comps.prefix_len() > 0
&& comps.prefix_len() == comps.path.len()
&& comps.prefix.unwrap().is_drive()
{
need_sep = false
}
if path.is_absolute() || path.prefix().is_some() {
self.inner.truncate(0);
} else if comps.prefix_verbatim() && !path.inner.is_empty() {
let mut buf: Vec<_> = comps.collect();
for c in path.components() {
match c {
Component::RootDir => {
buf.truncate(1);
buf.push(c);
}
Component::CurDir => (),
Component::ParentDir => {
if let Some(Component::Normal(_)) = buf.last() {
buf.pop();
}
}
_ => buf.push(c),
}
}
let mut res = OsString::new();
let mut need_sep = false;
for c in buf {
if need_sep && c != Component::RootDir {
res.push(MAIN_SEP_STR);
}
res.push(c.as_os_str());
need_sep = match c {
Component::RootDir => false,
Component::Prefix(prefix) => {
!prefix.parsed.is_drive() && prefix.parsed.len() > 0
}
_ => true,
}
}
self.inner = res;
return;
} else if path.has_root() {
let prefix_len = self.components().prefix_remaining();
self.inner.truncate(prefix_len);
} else if need_sep {
self.inner.push(MAIN_SEP_STR);
}
self.inner.push(path);
}
pub fn pop(&mut self) -> bool {
match self.parent().map(|p| p.as_u8_slice().len()) {
Some(len) => {
self.inner.truncate(len);
true
}
None => false,
}
}
pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
self._set_file_name(file_name.as_ref())
}
fn _set_file_name(&mut self, file_name: &OsStr) {
if self.file_name().is_some() {
let popped = self.pop();
debug_assert!(popped);
}
self.push(file_name);
}
pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
self._set_extension(extension.as_ref())
}
fn _set_extension(&mut self, extension: &OsStr) -> bool {
validate_extension(extension);
let file_stem = match self.file_stem() {
None => return false,
Some(f) => f.as_encoded_bytes(),
};
let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr();
let start = self.inner.as_encoded_bytes().as_ptr().addr();
self.inner.truncate(end_file_stem.wrapping_sub(start));
let new = extension.as_encoded_bytes();
if !new.is_empty() {
self.inner.reserve_exact(new.len() + 1);
self.inner.push(".");
unsafe { self.inner.extend_from_slice_unchecked(new) };
}
true
}
#[must_use]
#[inline]
pub fn as_mut_os_string(&mut self) -> &mut OsString {
&mut self.inner
}
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_os_string(self) -> OsString {
self.inner
}
#[inline]
pub(crate) fn from_os_string(s: OsString) -> PathBuf {
PathBuf { inner: s }
}
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_boxed_path(self) -> Box<Path> {
let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
unsafe { Box::from_raw(rw) }
}
#[must_use]
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
#[inline]
pub fn clear(&mut self) {
self.inner.clear()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)
}
#[inline]
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.inner.try_reserve(additional)
}
#[inline]
pub fn reserve_exact(&mut self, additional: usize) {
self.inner.reserve_exact(additional)
}
#[inline]
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.inner.try_reserve_exact(additional)
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.inner.shrink_to_fit()
}
#[inline]
pub fn shrink_to(&mut self, min_capacity: usize) {
self.inner.shrink_to(min_capacity)
}
}
impl Clone for PathBuf {
#[inline]
fn clone(&self) -> Self {
PathBuf { inner: self.inner.clone() }
}
#[inline]
fn clone_from(&mut self, source: &Self) {
self.inner.clone_from(&source.inner)
}
}
impl From<&Path> for Box<Path> {
fn from(path: &Path) -> Box<Path> {
let boxed: Box<OsStr> = path.inner.to_os_string().into_boxed_os_str();
let rw = Box::into_raw(boxed) as *mut Path;
unsafe { Box::from_raw(rw) }
}
}
impl From<&mut Path> for Box<Path> {
fn from(path: &mut Path) -> Box<Path> {
Self::from(&*path)
}
}
impl From<Cow<'_, Path>> for Box<Path> {
#[inline]
fn from(cow: Cow<'_, Path>) -> Box<Path> {
match cow {
Cow::Borrowed(path) => Box::from(path),
Cow::Owned(path) => Box::from(path),
}
}
}
impl From<Box<Path>> for PathBuf {
#[inline]
fn from(boxed: Box<Path>) -> PathBuf {
boxed.into_path_buf()
}
}
impl From<PathBuf> for Box<Path> {
#[inline]
fn from(p: PathBuf) -> Box<Path> {
p.into_boxed_path()
}
}
impl Clone for Box<Path> {
#[inline]
fn clone(&self) -> Self {
self.to_path_buf().into_boxed_path()
}
}
impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
#[inline]
fn from(s: &T) -> PathBuf {
PathBuf::from(s.as_ref().to_os_string())
}
}
impl From<String> for PathBuf {
#[inline]
fn from(s: String) -> PathBuf {
PathBuf::from(OsString::from(s))
}
}
impl FromStr for PathBuf {
type Err = core::convert::Infallible;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(PathBuf::from(s))
}
}
impl<P: AsRef<Path>> FromIterator<P> for PathBuf {
fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
let mut buf = PathBuf::new();
buf.extend(iter);
buf
}
}
impl<P: AsRef<Path>> Extend<P> for PathBuf {
fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
iter.into_iter().for_each(move |p| self.push(p.as_ref()));
}
}
impl fmt::Debug for PathBuf {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter)
}
}
impl ops::Deref for PathBuf {
type Target = Path;
#[inline]
fn deref(&self) -> &Path {
Path::new(&self.inner)
}
}
impl ops::DerefMut for PathBuf {
#[inline]
fn deref_mut(&mut self) -> &mut Path {
Path::from_inner_mut(&mut self.inner)
}
}
impl Borrow<Path> for PathBuf {
#[inline]
fn borrow(&self) -> &Path {
self.deref()
}
}
impl Default for PathBuf {
#[inline]
fn default() -> Self {
PathBuf::new()
}
}
impl<'a> From<&'a Path> for Cow<'a, Path> {
#[inline]
fn from(s: &'a Path) -> Cow<'a, Path> {
Cow::Borrowed(s)
}
}
impl<'a> From<PathBuf> for Cow<'a, Path> {
#[inline]
fn from(s: PathBuf) -> Cow<'a, Path> {
Cow::Owned(s)
}
}
impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
#[inline]
fn from(p: &'a PathBuf) -> Cow<'a, Path> {
Cow::Borrowed(p.as_path())
}
}
impl<'a> From<Cow<'a, Path>> for PathBuf {
#[inline]
fn from(p: Cow<'a, Path>) -> Self {
p.into_owned()
}
}
impl From<PathBuf> for Arc<Path> {
#[inline]
fn from(s: PathBuf) -> Arc<Path> {
let arc: Arc<OsStr> = Arc::from(s.into_os_string());
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
}
}
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<&mut Path> for Arc<Path> {
#[inline]
fn from(s: &mut Path) -> Arc<Path> {
Arc::from(&*s)
}
}
impl From<PathBuf> for Rc<Path> {
#[inline]
fn from(s: PathBuf) -> Rc<Path> {
let rc: Rc<OsStr> = Rc::from(s.into_os_string());
unsafe { Rc::from_raw(Rc::into_raw(rc) 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 From<&mut Path> for Rc<Path> {
#[inline]
fn from(s: &mut Path) -> Rc<Path> {
Rc::from(&*s)
}
}
impl ToOwned for Path {
type Owned = PathBuf;
#[inline]
fn to_owned(&self) -> PathBuf {
self.to_path_buf()
}
#[inline]
fn clone_into(&self, target: &mut PathBuf) {
self.inner.clone_into(&mut target.inner);
}
}
impl PartialEq for PathBuf {
#[inline]
fn eq(&self, other: &PathBuf) -> bool {
self.components() == other.components()
}
}
impl Hash for PathBuf {
fn hash<H: Hasher>(&self, h: &mut H) {
self.as_path().hash(h)
}
}
impl Eq for PathBuf {}
impl PartialOrd for PathBuf {
#[inline]
fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PathBuf {
#[inline]
fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
compare_components(self.components(), other.components())
}
}
impl AsRef<OsStr> for PathBuf {
#[inline]
fn as_ref(&self) -> &OsStr {
&self.inner[..]
}
}
#[repr(transparent)]
pub struct Path {
inner: OsStr,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StripPrefixError(());
impl Path {
unsafe fn from_u8_slice(s: &[u8]) -> &Path {
unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(s)) }
}
pub(crate) fn as_u8_slice(&self) -> &[u8] {
self.inner.as_encoded_bytes()
}
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
}
fn from_inner_mut(inner: &mut OsStr) -> &mut Path {
unsafe { &mut *(inner as *mut OsStr as *mut Path) }
}
#[must_use]
#[inline]
pub fn as_os_str(&self) -> &OsStr {
&self.inner
}
#[must_use]
#[inline]
pub fn as_mut_os_str(&mut self) -> &mut OsStr {
&mut self.inner
}
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn to_str(&self) -> Option<&str> {
self.inner.to_str()
}
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub fn to_string_lossy(&self) -> Cow<'_, str> {
self.inner.to_string_lossy()
}
#[must_use = "this returns the result of the operation, \
without modifying the original"]
pub fn to_path_buf(&self) -> PathBuf {
PathBuf::from(self.inner.to_os_string())
}
#[must_use]
pub fn is_absolute(&self) -> bool {
self.has_root()
}
#[must_use]
#[inline]
pub fn is_relative(&self) -> bool {
!self.is_absolute()
}
pub(crate) fn prefix(&self) -> Option<Prefix<'_>> {
self.components().prefix
}
#[must_use]
#[inline]
pub fn has_root(&self) -> bool {
self.components().has_root()
}
#[must_use]
pub fn parent(&self) -> Option<&Path> {
let mut comps = self.components();
let comp = comps.next_back();
comp.and_then(|p| match p {
Component::Normal(_) | Component::CurDir | Component::ParentDir => {
Some(comps.as_path())
}
_ => None,
})
}
#[inline]
pub fn ancestors(&self) -> Ancestors<'_> {
Ancestors { next: Some(self) }
}
#[must_use]
pub fn file_name(&self) -> Option<&OsStr> {
self.components().next_back().and_then(|p| match p {
Component::Normal(p) => Some(p),
_ => None,
})
}
pub fn strip_prefix<P>(&self, base: P) -> Result<&Path, StripPrefixError>
where
P: AsRef<Path>,
{
self._strip_prefix(base.as_ref())
}
fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> {
iter_after(self.components(), base.components())
.map(|c| c.as_path())
.ok_or(StripPrefixError(()))
}
#[must_use]
pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
self._starts_with(base.as_ref())
}
fn _starts_with(&self, base: &Path) -> bool {
iter_after(self.components(), base.components()).is_some()
}
#[must_use]
pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
self._ends_with(child.as_ref())
}
fn _ends_with(&self, child: &Path) -> bool {
iter_after(self.components().rev(), child.components().rev()).is_some()
}
#[must_use]
pub fn file_stem(&self) -> Option<&OsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after))
}
#[must_use]
pub fn extension(&self) -> Option<&OsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after))
}
#[must_use]
pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
self._join(path.as_ref())
}
fn _join(&self, path: &Path) -> PathBuf {
let mut buf = self.to_path_buf();
buf.push(path);
buf
}
#[must_use]
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
self._with_file_name(file_name.as_ref())
}
fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
let mut buf = self.to_path_buf();
buf.set_file_name(file_name);
buf
}
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
self._with_extension(extension.as_ref())
}
fn _with_extension(&self, extension: &OsStr) -> PathBuf {
let self_len = self.as_os_str().len();
let self_bytes = self.as_os_str().as_encoded_bytes();
let (new_capacity, slice_to_copy) = match self.extension() {
None => {
let capacity = self_len + extension.len() + 1;
let whole_path = self_bytes;
(capacity, whole_path)
}
Some(previous_extension) => {
let capacity = self_len + extension.len() - previous_extension.len();
let path_till_dot = &self_bytes[..self_len - previous_extension.len()];
(capacity, path_till_dot)
}
};
let mut new_path = PathBuf::with_capacity(new_capacity);
unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) };
new_path.set_extension(extension);
new_path
}
pub fn components(&self) -> Components<'_> {
let prefix = parse_prefix(self.as_os_str());
Components {
path: self.as_u8_slice(),
prefix,
has_physical_root: has_physical_root(self.as_u8_slice(), prefix),
front: if HAS_PREFIXES { State::Prefix } else { State::StartDir },
back: State::Body,
}
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter { inner: self.components() }
}
#[must_use = "this does not display the path, \
it returns an object that can be displayed"]
#[inline]
pub fn display(&self) -> Display<'_> {
Display { inner: self.inner.display() }
}
#[inline]
pub fn as_path(&self) -> &Path {
self
}
#[must_use = "`self` will be dropped if the result is not used"]
pub fn into_path_buf(self: Box<Self>) -> PathBuf {
let rw = Box::into_raw(self) as *mut OsStr;
let inner = unsafe { Box::from_raw(rw) };
PathBuf { inner: OsString::from(inner) }
}
}
impl AsRef<OsStr> for Path {
#[inline]
fn as_ref(&self) -> &OsStr {
&self.inner
}
}
impl fmt::Debug for Path {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.inner, formatter)
}
}
pub struct Display<'a> {
inner: crate::ffi::Display<'a>,
}
impl fmt::Debug for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.inner, f)
}
}
impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
impl PartialEq for Path {
#[inline]
fn eq(&self, other: &Path) -> bool {
self.components() == other.components()
}
}
impl Hash for Path {
fn hash<H: Hasher>(&self, h: &mut H) {
let bytes = self.as_u8_slice();
let (prefix_len, verbatim) = match parse_prefix(&self.inner) {
Some(prefix) => {
prefix.hash(h);
(prefix.len(), prefix.is_verbatim())
}
None => (0, false),
};
let bytes = &bytes[prefix_len..];
let mut component_start = 0;
let mut chunk_bits: usize = 0;
for i in 0..bytes.len() {
let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) };
if is_sep {
if i > component_start {
let to_hash = &bytes[component_start..i];
chunk_bits = chunk_bits.wrapping_add(to_hash.len());
chunk_bits = chunk_bits.rotate_right(2);
h.write(to_hash);
}
component_start = i + 1;
let tail = &bytes[component_start..];
if !verbatim {
component_start += match tail {
[b'.'] => 1,
[b'.', sep, ..] if is_sep_byte(*sep) => 1,
_ => 0,
};
}
}
}
if component_start < bytes.len() {
let to_hash = &bytes[component_start..];
chunk_bits = chunk_bits.wrapping_add(to_hash.len());
chunk_bits = chunk_bits.rotate_right(2);
h.write(to_hash);
}
h.write_usize(chunk_bits);
}
}
impl Eq for Path {}
impl PartialOrd for Path {
#[inline]
fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Path {
#[inline]
fn cmp(&self, other: &Path) -> cmp::Ordering {
compare_components(self.components(), other.components())
}
}
impl AsRef<Path> for Path {
#[inline]
fn as_ref(&self) -> &Path {
self
}
}
impl AsRef<Path> for Cow<'_, OsStr> {
#[inline]
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for str {
#[inline]
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for String {
#[inline]
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl AsRef<Path> for PathBuf {
#[inline]
fn as_ref(&self) -> &Path {
self
}
}
impl<'a> IntoIterator for &'a PathBuf {
type Item = &'a OsStr;
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
impl<'a> IntoIterator for &'a Path {
type Item = &'a OsStr;
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
macro_rules! impl_cmp {
(<$($life:lifetime),*> $lhs:ty, $rhs: ty) => {
impl<$($life),*> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
<Path as PartialEq>::eq(self, other)
}
}
impl<$($life),*> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
<Path as PartialEq>::eq(self, other)
}
}
impl<$($life),*> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self, other)
}
}
impl<$($life),*> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self, other)
}
}
};
}
impl_cmp!(<> PathBuf, Path);
impl_cmp!(<'a> PathBuf, &'a Path);
impl_cmp!(<'a> Cow<'a, Path>, Path);
impl_cmp!(<'a, 'b> Cow<'a, Path>, &'b Path);
impl_cmp!(<'a> Cow<'a, Path>, PathBuf);
macro_rules! impl_cmp_os_str {
(<$($life:lifetime),*> $lhs:ty, $rhs: ty) => {
impl<$($life),*> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
<Path as PartialEq>::eq(self, other.as_ref())
}
}
impl<$($life),*> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
<Path as PartialEq>::eq(self.as_ref(), other)
}
}
impl<$($life),*> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self, other.as_ref())
}
}
impl<$($life),*> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
<Path as PartialOrd>::partial_cmp(self.as_ref(), other)
}
}
};
}
impl_cmp_os_str!(<> PathBuf, OsStr);
impl_cmp_os_str!(<'a> PathBuf, &'a OsStr);
impl_cmp_os_str!(<'a> PathBuf, Cow<'a, OsStr>);
impl_cmp_os_str!(<> PathBuf, OsString);
impl_cmp_os_str!(<> Path, OsStr);
impl_cmp_os_str!(<'a> Path, &'a OsStr);
impl_cmp_os_str!(<'a> Path, Cow<'a, OsStr>);
impl_cmp_os_str!(<> Path, OsString);
impl_cmp_os_str!(<'a> &'a Path, OsStr);
impl_cmp_os_str!(<'a, 'b> &'a Path, Cow<'b, OsStr>);
impl_cmp_os_str!(<'a> &'a Path, OsString);
impl_cmp_os_str!(<'a> Cow<'a, Path>, OsStr);
impl_cmp_os_str!(<'a, 'b> Cow<'a, Path>, &'b OsStr);
impl_cmp_os_str!(<'a> Cow<'a, Path>, OsString);
impl fmt::Display for StripPrefixError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"prefix not found".fmt(f)
}
}