use alloc::borrow::Cow;
use alloc::fmt;
use core::clone::CloneToUninit;
use crate::daemonic_path_buffer::DaemonicOsStr;
use super::*;
#[repr(transparent)]
pub struct DaemonicPath {
pub(crate) inner: DaemonicOsStr,
}
impl AsRef<DaemonicPath> for DaemonicPath {
fn as_ref(&self) -> &DaemonicPath {
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StripPrefixError(());
pub struct DaemonicOsStrDisplayOuter<'a> {
inner: DaemonicOsStrDisplayInner<'a>,
}
#[derive(Debug)]
pub struct DaemonicOsStrDisplayInner<'a> {
os_str: &'a DaemonicOsStr,
}
impl fmt::Display for DaemonicOsStrDisplayInner<'_>
where
DaemonicOsStr: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.os_str, f)
}
}
impl fmt::Debug for DaemonicOsStrDisplayOuter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.inner, f)
}
}
impl fmt::Display for DaemonicOsStrDisplayOuter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
impl DaemonicPath {
pub(crate) unsafe fn from_u8_slice(s: &[u8]) -> &DaemonicPath {
unsafe { DaemonicPath::new(DaemonicOsStr::from_encoded_bytes_unchecked(s)) }
}
pub(crate) fn as_u8_slice(&self) -> &[u8] {
self.inner.as_encoded_bytes()
}
pub fn new<S: AsRef<DaemonicOsStr> + ?Sized>(s: &S) -> &DaemonicPath {
unsafe { &*(s.as_ref() as *const DaemonicOsStr as *const DaemonicPath) }
}
pub(crate) fn from_inner_mut(inner: &mut DaemonicOsStr) -> &mut DaemonicPath {
unsafe { &mut *(inner as *mut DaemonicOsStr as *mut DaemonicPath) }
}
#[must_use]
#[inline]
pub fn as_os_str(&self) -> &DaemonicOsStr {
&self.inner
}
#[must_use]
#[inline]
pub fn as_mut_os_str(&mut self) -> &mut DaemonicOsStr {
&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()
}
#[rustc_conversion_suggestion]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
pub fn to_path_buf(&self) -> DaemonicPathBuf {
DaemonicPathBuf::from(DaemonicPathBuf { inner: self.inner.to_os_string() })
}
#[must_use]
#[allow(deprecated)]
pub fn is_absolute(&self) -> bool {
is_absolute(self)
}
#[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()
}
#[doc(alias = "dirname")]
#[must_use]
pub fn parent(&self) -> Option<&DaemonicPath> {
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) }
}
#[doc(alias = "basename")]
#[must_use]
pub fn file_name(&self) -> Option<&DaemonicOsStr> {
self.components().next_back().and_then(|p| match p {
Component::Normal(p) => Some(p),
_ => None,
})
}
pub fn strip_prefix<P>(&self, base: P) -> Result<&DaemonicPath, StripPrefixError>
where
P: AsRef<DaemonicPath>,
{
self._strip_prefix(base.as_ref())
}
fn _strip_prefix(&self, base: &DaemonicPath) -> Result<&DaemonicPath, StripPrefixError> {
iter_after(self.components(), base.components())
.map(|c| c.as_path())
.ok_or(StripPrefixError(()))
}
#[must_use]
pub fn starts_with<P: AsRef<DaemonicPath>>(&self, base: P) -> bool {
self._starts_with(base.as_ref())
}
fn _starts_with(&self, base: &DaemonicPath) -> bool {
iter_after(self.components(), base.components()).is_some()
}
#[must_use]
pub fn ends_with<P: AsRef<DaemonicPath>>(&self, child: P) -> bool {
self._ends_with(child.as_ref())
}
fn _ends_with(&self, child: &DaemonicPath) -> bool {
iter_after(self.components().rev(), child.components().rev()).is_some()
}
#[must_use]
pub fn file_stem(&self) -> Option<&DaemonicOsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after))
}
#[must_use]
pub fn file_prefix(&self) -> Option<&DaemonicOsStr> {
self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before))
}
#[must_use]
pub fn extension(&self) -> Option<&DaemonicOsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after))
}
#[must_use]
pub fn join<P: AsRef<DaemonicPath>>(&self, path: P) -> DaemonicPathBuf
where
DaemonicPathBuf: AsRef<DaemonicPathBuf>, DaemonicPath: AsRef<DaemonicPath>, {
self._join(path.as_ref())
}
fn _join(&self, path: &DaemonicPath) -> DaemonicPathBuf
where
DaemonicPathBuf: AsRef<DaemonicPathBuf>, DaemonicPath: AsRef<DaemonicPath>, {
let mut buf = self.to_path_buf();
buf.push(path);
buf
}
#[must_use]
pub fn with_file_name<S: AsRef<DaemonicOsStr>>(&self, file_name: S) -> DaemonicPathBuf
where
DaemonicOsStr: AsRef<DaemonicPath>,
{
self._with_file_name(file_name.as_ref())
}
fn _with_file_name(&self, file_name: &DaemonicOsStr) -> DaemonicPathBuf
where
DaemonicOsStr: AsRef<daemonic_path::DaemonicPath>,
{
let mut buf = self.to_path_buf();
buf.set_file_name(file_name);
buf
}
pub fn with_extension<S: AsRef<DaemonicOsStr>>(&self, extension: S) -> DaemonicPathBuf {
self._with_extension(extension.as_ref())
}
fn _with_extension(&self, extension: &DaemonicOsStr) -> DaemonicPathBuf {
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 = DaemonicPathBuf::with_capacity(new_capacity);
unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) };
new_path.set_extension(extension);
new_path
}
pub fn with_added_extension<S: AsRef<DaemonicOsStr>>(&self, extension: S) -> DaemonicPathBuf {
let mut new_path = self.to_path_buf();
new_path.add_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: State::Prefix,
back: State::Body,
}
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter { inner: self.components() }
}
#[must_use = "`self` will be dropped if the result is not used"]
pub fn into_path_buf(self: Box<DaemonicPath>) -> DaemonicPathBuf {
let rw = Box::into_raw(self) as *mut DaemonicOsStr;
let inner = unsafe { Box::from_raw(rw) };
DaemonicPathBuf { inner: DaemonicOsString::from(inner) }
}
}
unsafe impl CloneToUninit for DaemonicPath {
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
unsafe fn clone_to_uninit(&self, dst: *mut u8) {
unsafe { self.inner.clone_to_uninit(dst) }
}
}
impl AsRef<DaemonicOsStr> for DaemonicPath {
#[inline]
fn as_ref(&self) -> &DaemonicOsStr {
&self.inner
}
}
impl fmt::Debug for DaemonicPath {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.inner, formatter)
}
}