#![forbid(unsafe_code)]
#![warn(clippy::dbg_macro, clippy::print_stdout)]
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
pub trait PathExt {
fn to_slash(&self) -> Option<String>;
fn to_slash_lossy(&self) -> String;
}
impl PathExt for Path {
#[cfg(not(target_os = "windows"))]
fn to_slash_lossy(&self) -> String {
self.to_string_lossy().to_string()
}
#[cfg(target_os = "windows")]
fn to_slash_lossy(&self) -> String {
use std::path;
let mut buf = String::new();
let mut has_trailing_slash = false;
for c in self.components() {
match c {
path::Component::RootDir => { }
path::Component::CurDir => buf.push('.'),
path::Component::ParentDir => buf.push_str(".."),
path::Component::Prefix(ref prefix) => {
let s = prefix.as_os_str();
match s.to_str() {
Some(ref s) => buf.push_str(s),
None => buf.push_str(&s.to_string_lossy()),
}
continue;
}
path::Component::Normal(ref s) => match s.to_str() {
Some(ref s) => buf.push_str(s),
None => buf.push_str(&s.to_string_lossy()),
},
}
buf.push('/');
has_trailing_slash = true;
}
if buf != "/" && has_trailing_slash {
buf.pop(); }
buf
}
#[cfg(not(target_os = "windows"))]
fn to_slash(&self) -> Option<String> {
self.to_str().map(str::to_string)
}
#[cfg(target_os = "windows")]
fn to_slash(&self) -> Option<String> {
use std::path;
let mut buf = String::new();
let mut has_trailing_slash = false;
for c in self.components() {
match c {
path::Component::RootDir => { }
path::Component::CurDir => buf.push('.'),
path::Component::ParentDir => buf.push_str(".."),
path::Component::Prefix(ref prefix) => {
if let Some(s) = prefix.as_os_str().to_str() {
buf.push_str(s);
continue;
} else {
return None;
}
}
path::Component::Normal(ref s) => {
if let Some(s) = s.to_str() {
buf.push_str(s);
} else {
return None;
}
}
}
buf.push('/');
has_trailing_slash = true;
}
if buf != "/" && has_trailing_slash {
buf.pop(); }
Some(buf)
}
}
pub trait PathBufExt {
fn from_slash<S: AsRef<str>>(s: S) -> Self;
fn from_slash_lossy<S: AsRef<OsStr>>(s: S) -> Self;
fn to_slash(&self) -> Option<String>;
fn to_slash_lossy(&self) -> String;
}
impl PathBufExt for PathBuf {
#[cfg(not(target_os = "windows"))]
fn from_slash<S: AsRef<str>>(s: S) -> Self {
PathBuf::from(s.as_ref())
}
#[cfg(target_os = "windows")]
fn from_slash<S: AsRef<str>>(s: S) -> Self {
use std::path;
let s = s
.as_ref()
.chars()
.map(|c| match c {
'/' => path::MAIN_SEPARATOR,
c => c,
})
.collect::<String>();
PathBuf::from(s)
}
#[cfg(not(target_os = "windows"))]
fn from_slash_lossy<S: AsRef<OsStr>>(s: S) -> Self {
PathBuf::from(s.as_ref())
}
#[cfg(target_os = "windows")]
fn from_slash_lossy<S: AsRef<OsStr>>(s: S) -> Self {
Self::from_slash(s.as_ref().to_string_lossy().chars().as_str())
}
fn to_slash_lossy(&self) -> String {
self.as_path().to_slash_lossy()
}
fn to_slash(&self) -> Option<String> {
self.as_path().to_slash()
}
}
#[cfg(test)]
#[macro_use]
extern crate lazy_static;
#[cfg(test)]
mod test;