shellexpand/
path.rs

1//! Expansion of [`Path`] values
2//!
3//! These functions are the same as the ones in the crate toplevel,
4//! except that they take [`Path`]s as input and return `Cow<Path>`.
5//!
6//! (Note that the individual doc comments and examples still refer to
7//! `str` and `String` and so on - please refer to the actual types.
8//! The semantics are as described.)
9
10use std::ffi::OsString;
11use std::path::Path;
12
13use bstr::ByteSlice as _;
14
15#[path="wtraits.rs"]
16pub(crate) mod wtraits;
17use wtraits::*;
18
19#[path="funcs.rs"]
20pub(crate) mod funcs;
21pub use funcs::*;
22
23use os_str_bytes::RawOsStr;
24
25type Xstr = std::path::Path;
26
27pub(crate) type WInput<'x> = Cow<'x, RawOsStr>;
28
29pub(crate) type Wstr = RawOsStr;
30
31pub(crate) type OString = OsString;
32
33impl XstrRequirements for Path {
34}
35
36impl<P: AsRef<Path> + ?Sized> AsRefXstrExt for P {
37    fn into_winput(&self) -> Cow<'_, RawOsStr> { RawOsStr::new(self.as_ref().as_os_str()) }
38    fn into_ocow(&self) -> Cow<'_, Path> { self.as_ref().into() }
39}
40
41impl WstrExt for RawOsStr {
42    fn as_str(&self) -> Option<&str> { self.to_str() }
43    fn len(&self) -> usize { self.raw_len() }
44    fn to_ostring(&self) -> OsString { self.to_os_str().into_owned() }
45    fn strip_prefix(&self, c: char) -> Option<&Self> { self.strip_prefix(c) }
46}
47
48impl<'s> WstrRefExt for &'s RawOsStr {
49    type Chars = bstr::Chars<'s>;
50
51    /// This is quite approximate, really.
52    ///
53    /// os_str_bytes says the encoding is "compatible with" UTF-8, and that splitting on UTF-8
54    /// characters yields valid substrings.
55    ///
56    /// We assume, without justification, that the characters we care about handling correctly
57    /// in un-{} $var expansions, are represented closely enough that this works.
58    ///
59    /// On Unix-using-UTF-8 this will be true because it's all, in fact, Unicode.
60    /// On other Unix, at least ASCII will work right.
61    /// On Windows things that use surrogates will possibly go wrong?
62    /// On platforms where this is some mutant form of EBCDIC or something, this will be hopeless.
63    fn chars_approx(self) -> bstr::Chars<'s> {
64        self.as_raw_bytes().chars()
65    }
66
67}
68
69impl CharsExt for bstr::Chars<'_> {
70    fn wstr_len(&self) -> usize {
71        self.as_bytes().len()
72    }
73}
74
75impl OStringExt for OsString {
76    fn push_str(&mut self, x: &str) { self.push(x) }
77    fn push_wstr(&mut self, x: &RawOsStr) { self.push(x.to_os_str()) }
78    fn push_xstr(&mut self, x: &Path) { self.push(x.as_os_str()) }
79    fn into_ocow(self) -> Cow<'static, Path> { PathBuf::from(self).into() }
80
81    fn display_possibly_lossy(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        f.write_str(&self.to_string_lossy())
83    }
84}
85
86impl PathBufExt for PathBuf {
87    fn try_into_xstring(self) -> Option<PathBuf> { Some(self) }
88}