mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +00:00
auto merge of #11642 : erickt/rust/path, r=huonw
This pull request exposes a platform independent way to get the path separator. This is useful when building complicated paths by hand.
This commit is contained in:
commit
18061e85b7
@ -117,6 +117,20 @@ pub use StrComponents = self::windows::StrComponents;
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub use RevStrComponents = self::windows::RevStrComponents;
|
pub use RevStrComponents = self::windows::RevStrComponents;
|
||||||
|
|
||||||
|
/// Alias for the platform-native separator character.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub use SEP = self::posix::SEP;
|
||||||
|
/// Alias for the platform-native separator byte.
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub use SEP = self::windows::SEP;
|
||||||
|
|
||||||
|
/// Alias for the platform-native separator character.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub use SEP_BYTE = self::posix::SEP_BYTE;
|
||||||
|
/// Alias for the platform-native separator byte.
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub use SEP_BYTE = self::windows::SEP_BYTE;
|
||||||
|
|
||||||
/// Typedef for the platform-native separator char func
|
/// Typedef for the platform-native separator char func
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub use is_sep = self::posix::is_sep;
|
pub use is_sep = self::posix::is_sep;
|
||||||
|
@ -45,19 +45,21 @@ pub struct Path {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The standard path separator character
|
/// The standard path separator character
|
||||||
pub static sep: char = '/';
|
pub static SEP: char = '/';
|
||||||
static sep_byte: u8 = sep as u8;
|
|
||||||
|
/// The standard path separator byte
|
||||||
|
pub static SEP_BYTE: u8 = SEP as u8;
|
||||||
|
|
||||||
/// Returns whether the given byte is a path separator
|
/// Returns whether the given byte is a path separator
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sep_byte(u: &u8) -> bool {
|
pub fn is_sep_byte(u: &u8) -> bool {
|
||||||
*u as char == sep
|
*u as char == SEP
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given char is a path separator
|
/// Returns whether the given char is a path separator
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sep(c: char) -> bool {
|
pub fn is_sep(c: char) -> bool {
|
||||||
c == sep
|
c == SEP
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Path {
|
impl Eq for Path {
|
||||||
@ -115,7 +117,7 @@ impl GenericPathUnsafe for Path {
|
|||||||
unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
|
unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
|
||||||
let path = Path::normalize(path.container_as_bytes());
|
let path = Path::normalize(path.container_as_bytes());
|
||||||
assert!(!path.is_empty());
|
assert!(!path.is_empty());
|
||||||
let idx = path.rposition_elem(&sep_byte);
|
let idx = path.rposition_elem(&SEP_BYTE);
|
||||||
Path{ repr: path, sepidx: idx }
|
Path{ repr: path, sepidx: idx }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +127,7 @@ impl GenericPathUnsafe for Path {
|
|||||||
None if bytes!("..") == self.repr => {
|
None if bytes!("..") == self.repr => {
|
||||||
let mut v = vec::with_capacity(3 + filename.len());
|
let mut v = vec::with_capacity(3 + filename.len());
|
||||||
v.push_all(dot_dot_static);
|
v.push_all(dot_dot_static);
|
||||||
v.push(sep_byte);
|
v.push(SEP_BYTE);
|
||||||
v.push_all(filename);
|
v.push_all(filename);
|
||||||
self.repr = Path::normalize(v);
|
self.repr = Path::normalize(v);
|
||||||
}
|
}
|
||||||
@ -135,7 +137,7 @@ impl GenericPathUnsafe for Path {
|
|||||||
Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
|
Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
|
||||||
let mut v = vec::with_capacity(self.repr.len() + 1 + filename.len());
|
let mut v = vec::with_capacity(self.repr.len() + 1 + filename.len());
|
||||||
v.push_all(self.repr);
|
v.push_all(self.repr);
|
||||||
v.push(sep_byte);
|
v.push(SEP_BYTE);
|
||||||
v.push_all(filename);
|
v.push_all(filename);
|
||||||
self.repr = Path::normalize(v);
|
self.repr = Path::normalize(v);
|
||||||
}
|
}
|
||||||
@ -146,22 +148,22 @@ impl GenericPathUnsafe for Path {
|
|||||||
self.repr = Path::normalize(v);
|
self.repr = Path::normalize(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.sepidx = self.repr.rposition_elem(&sep_byte);
|
self.sepidx = self.repr.rposition_elem(&SEP_BYTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
|
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
|
||||||
let path = path.container_as_bytes();
|
let path = path.container_as_bytes();
|
||||||
if !path.is_empty() {
|
if !path.is_empty() {
|
||||||
if path[0] == sep_byte {
|
if path[0] == SEP_BYTE {
|
||||||
self.repr = Path::normalize(path);
|
self.repr = Path::normalize(path);
|
||||||
} else {
|
} else {
|
||||||
let mut v = vec::with_capacity(self.repr.len() + path.len() + 1);
|
let mut v = vec::with_capacity(self.repr.len() + path.len() + 1);
|
||||||
v.push_all(self.repr);
|
v.push_all(self.repr);
|
||||||
v.push(sep_byte);
|
v.push(SEP_BYTE);
|
||||||
v.push_all(path);
|
v.push_all(path);
|
||||||
self.repr = Path::normalize(v);
|
self.repr = Path::normalize(v);
|
||||||
}
|
}
|
||||||
self.sepidx = self.repr.rposition_elem(&sep_byte);
|
self.sepidx = self.repr.rposition_elem(&SEP_BYTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,7 +213,7 @@ impl GenericPath for Path {
|
|||||||
} else {
|
} else {
|
||||||
self.repr.truncate(idx);
|
self.repr.truncate(idx);
|
||||||
}
|
}
|
||||||
self.sepidx = self.repr.rposition_elem(&sep_byte);
|
self.sepidx = self.repr.rposition_elem(&SEP_BYTE);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,7 +229,7 @@ impl GenericPath for Path {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_absolute(&self) -> bool {
|
fn is_absolute(&self) -> bool {
|
||||||
self.repr[0] == sep_byte
|
self.repr[0] == SEP_BYTE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_ancestor_of(&self, other: &Path) -> bool {
|
fn is_ancestor_of(&self, other: &Path) -> bool {
|
||||||
@ -291,7 +293,7 @@ impl GenericPath for Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Path::new(comps.connect_vec(&sep_byte)))
|
Some(Path::new(comps.connect_vec(&SEP_BYTE)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,14 +335,14 @@ impl Path {
|
|||||||
fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
|
fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
|
||||||
// borrowck is being very picky
|
// borrowck is being very picky
|
||||||
let val = {
|
let val = {
|
||||||
let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == sep_byte;
|
let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
|
||||||
let v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
|
let v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
|
||||||
let comps = normalize_helper(v_, is_abs);
|
let comps = normalize_helper(v_, is_abs);
|
||||||
match comps {
|
match comps {
|
||||||
None => None,
|
None => None,
|
||||||
Some(comps) => {
|
Some(comps) => {
|
||||||
if is_abs && comps.is_empty() {
|
if is_abs && comps.is_empty() {
|
||||||
Some(~[sep_byte])
|
Some(~[SEP_BYTE])
|
||||||
} else {
|
} else {
|
||||||
let n = if is_abs { comps.len() } else { comps.len() - 1} +
|
let n = if is_abs { comps.len() } else { comps.len() - 1} +
|
||||||
comps.iter().map(|v| v.len()).sum();
|
comps.iter().map(|v| v.len()).sum();
|
||||||
@ -353,7 +355,7 @@ impl Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for comp in it {
|
for comp in it {
|
||||||
v.push(sep_byte);
|
v.push(SEP_BYTE);
|
||||||
v.push_all(comp);
|
v.push_all(comp);
|
||||||
}
|
}
|
||||||
Some(v)
|
Some(v)
|
||||||
@ -372,7 +374,7 @@ impl Path {
|
|||||||
/// /a/b/c and a/b/c yield the same set of components.
|
/// /a/b/c and a/b/c yield the same set of components.
|
||||||
/// A path of "/" yields no components. A path of "." yields one component.
|
/// A path of "/" yields no components. A path of "." yields one component.
|
||||||
pub fn components<'a>(&'a self) -> Components<'a> {
|
pub fn components<'a>(&'a self) -> Components<'a> {
|
||||||
let v = if self.repr[0] == sep_byte {
|
let v = if self.repr[0] == SEP_BYTE {
|
||||||
self.repr.slice_from(1)
|
self.repr.slice_from(1)
|
||||||
} else { self.repr.as_slice() };
|
} else { self.repr.as_slice() };
|
||||||
let mut ret = v.split(is_sep_byte);
|
let mut ret = v.split(is_sep_byte);
|
||||||
@ -386,7 +388,7 @@ impl Path {
|
|||||||
/// Returns an iterator that yields each component of the path in reverse.
|
/// Returns an iterator that yields each component of the path in reverse.
|
||||||
/// See components() for details.
|
/// See components() for details.
|
||||||
pub fn rev_components<'a>(&'a self) -> RevComponents<'a> {
|
pub fn rev_components<'a>(&'a self) -> RevComponents<'a> {
|
||||||
let v = if self.repr[0] == sep_byte {
|
let v = if self.repr[0] == SEP_BYTE {
|
||||||
self.repr.slice_from(1)
|
self.repr.slice_from(1)
|
||||||
} else { self.repr.as_slice() };
|
} else { self.repr.as_slice() };
|
||||||
let mut ret = v.rsplit(is_sep_byte);
|
let mut ret = v.rsplit(is_sep_byte);
|
||||||
|
@ -183,7 +183,7 @@ impl GenericPathUnsafe for Path {
|
|||||||
None if ".." == self.repr => {
|
None if ".." == self.repr => {
|
||||||
let mut s = str::with_capacity(3 + filename.len());
|
let mut s = str::with_capacity(3 + filename.len());
|
||||||
s.push_str("..");
|
s.push_str("..");
|
||||||
s.push_char(sep);
|
s.push_char(SEP);
|
||||||
s.push_str(filename);
|
s.push_str(filename);
|
||||||
self.update_normalized(s);
|
self.update_normalized(s);
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ impl GenericPathUnsafe for Path {
|
|||||||
Some((_,idxa,end)) if self.repr.slice(idxa,end) == ".." => {
|
Some((_,idxa,end)) if self.repr.slice(idxa,end) == ".." => {
|
||||||
let mut s = str::with_capacity(end + 1 + filename.len());
|
let mut s = str::with_capacity(end + 1 + filename.len());
|
||||||
s.push_str(self.repr.slice_to(end));
|
s.push_str(self.repr.slice_to(end));
|
||||||
s.push_char(sep);
|
s.push_char(SEP);
|
||||||
s.push_str(filename);
|
s.push_str(filename);
|
||||||
self.update_normalized(s);
|
self.update_normalized(s);
|
||||||
}
|
}
|
||||||
@ -206,7 +206,7 @@ impl GenericPathUnsafe for Path {
|
|||||||
Some((idxb,_,_)) => {
|
Some((idxb,_,_)) => {
|
||||||
let mut s = str::with_capacity(idxb + 1 + filename.len());
|
let mut s = str::with_capacity(idxb + 1 + filename.len());
|
||||||
s.push_str(self.repr.slice_to(idxb));
|
s.push_str(self.repr.slice_to(idxb));
|
||||||
s.push_char(sep);
|
s.push_char(SEP);
|
||||||
s.push_str(filename);
|
s.push_str(filename);
|
||||||
self.update_normalized(s);
|
self.update_normalized(s);
|
||||||
}
|
}
|
||||||
@ -264,8 +264,8 @@ impl GenericPathUnsafe for Path {
|
|||||||
// if me is "C:" we don't want to add a path separator
|
// if me is "C:" we don't want to add a path separator
|
||||||
match me.prefix {
|
match me.prefix {
|
||||||
Some(DiskPrefix) if me.repr.len() == plen => (),
|
Some(DiskPrefix) if me.repr.len() == plen => (),
|
||||||
_ if !(me.repr.len() > plen && me.repr[me.repr.len()-1] == sep as u8) => {
|
_ if !(me.repr.len() > plen && me.repr[me.repr.len()-1] == SEP_BYTE) => {
|
||||||
s.push_char(sep);
|
s.push_char(SEP);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
@ -460,7 +460,7 @@ impl GenericPath for Path {
|
|||||||
match self.prefix {
|
match self.prefix {
|
||||||
Some(DiskPrefix) => {
|
Some(DiskPrefix) => {
|
||||||
let rest = self.repr.slice_from(self.prefix_len());
|
let rest = self.repr.slice_from(self.prefix_len());
|
||||||
rest.len() > 0 && rest[0] == sep as u8
|
rest.len() > 0 && rest[0] == SEP_BYTE
|
||||||
}
|
}
|
||||||
Some(_) => true,
|
Some(_) => true,
|
||||||
None => false
|
None => false
|
||||||
@ -501,7 +501,7 @@ impl GenericPath for Path {
|
|||||||
|
|
||||||
fn path_relative_from(&self, base: &Path) -> Option<Path> {
|
fn path_relative_from(&self, base: &Path) -> Option<Path> {
|
||||||
fn comp_requires_verbatim(s: &str) -> bool {
|
fn comp_requires_verbatim(s: &str) -> bool {
|
||||||
s == "." || s == ".." || s.contains_char(sep2)
|
s == "." || s == ".." || s.contains_char(SEP2)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.equiv_prefix(base) {
|
if !self.equiv_prefix(base) {
|
||||||
@ -619,14 +619,14 @@ impl Path {
|
|||||||
let s = match self.prefix {
|
let s = match self.prefix {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
let plen = self.prefix_len();
|
let plen = self.prefix_len();
|
||||||
if self.repr.len() > plen && self.repr[plen] == sep as u8 {
|
if self.repr.len() > plen && self.repr[plen] == SEP_BYTE {
|
||||||
self.repr.slice_from(plen+1)
|
self.repr.slice_from(plen+1)
|
||||||
} else { self.repr.slice_from(plen) }
|
} else { self.repr.slice_from(plen) }
|
||||||
}
|
}
|
||||||
None if self.repr[0] == sep as u8 => self.repr.slice_from(1),
|
None if self.repr[0] == SEP_BYTE => self.repr.slice_from(1),
|
||||||
None => self.repr.as_slice()
|
None => self.repr.as_slice()
|
||||||
};
|
};
|
||||||
let ret = s.split_terminator(sep).map(Some);
|
let ret = s.split_terminator(SEP).map(Some);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,7 +703,7 @@ impl Path {
|
|||||||
Some(VerbatimUNCPrefix(x, 0)) if s.len() == 8 + x => {
|
Some(VerbatimUNCPrefix(x, 0)) if s.len() == 8 + x => {
|
||||||
// the server component has no trailing '\'
|
// the server component has no trailing '\'
|
||||||
let mut s = s.into_owned();
|
let mut s = s.into_owned();
|
||||||
s.push_char(sep);
|
s.push_char(SEP);
|
||||||
Some(s)
|
Some(s)
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
@ -739,7 +739,7 @@ impl Path {
|
|||||||
if is_abs {
|
if is_abs {
|
||||||
// normalize C:/ to C:\
|
// normalize C:/ to C:\
|
||||||
unsafe {
|
unsafe {
|
||||||
str::raw::as_owned_vec(&mut s)[2] = sep as u8;
|
str::raw::as_owned_vec(&mut s)[2] = SEP_BYTE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(s)
|
Some(s)
|
||||||
@ -761,7 +761,7 @@ impl Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if is_abs && comps.is_empty() {
|
} else if is_abs && comps.is_empty() {
|
||||||
Some(str::from_char(sep))
|
Some(str::from_char(SEP))
|
||||||
} else {
|
} else {
|
||||||
let prefix_ = s.slice_to(prefix_len(prefix));
|
let prefix_ = s.slice_to(prefix_len(prefix));
|
||||||
let n = prefix_.len() +
|
let n = prefix_.len() +
|
||||||
@ -781,7 +781,7 @@ impl Path {
|
|||||||
Some(UNCPrefix(a,b)) => {
|
Some(UNCPrefix(a,b)) => {
|
||||||
s.push_str("\\\\");
|
s.push_str("\\\\");
|
||||||
s.push_str(prefix_.slice(2, a+2));
|
s.push_str(prefix_.slice(2, a+2));
|
||||||
s.push_char(sep);
|
s.push_char(SEP);
|
||||||
s.push_str(prefix_.slice(3+a, 3+a+b));
|
s.push_str(prefix_.slice(3+a, 3+a+b));
|
||||||
}
|
}
|
||||||
Some(_) => s.push_str(prefix_),
|
Some(_) => s.push_str(prefix_),
|
||||||
@ -795,7 +795,7 @@ impl Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for comp in it {
|
for comp in it {
|
||||||
s.push_char(sep);
|
s.push_char(SEP);
|
||||||
s.push_str(comp);
|
s.push_str(comp);
|
||||||
}
|
}
|
||||||
Some(s)
|
Some(s)
|
||||||
@ -837,7 +837,7 @@ impl Path {
|
|||||||
|
|
||||||
fn has_nonsemantic_trailing_slash(&self) -> bool {
|
fn has_nonsemantic_trailing_slash(&self) -> bool {
|
||||||
is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
|
is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
|
||||||
self.repr[self.repr.len()-1] == sep as u8
|
self.repr[self.repr.len()-1] == SEP_BYTE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_normalized<S: Str>(&mut self, s: S) {
|
fn update_normalized<S: Str>(&mut self, s: S) {
|
||||||
@ -877,36 +877,41 @@ pub fn is_verbatim(path: &Path) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The standard path separator character
|
/// The standard path separator character
|
||||||
pub static sep: char = '\\';
|
pub static SEP: char = '\\';
|
||||||
|
/// The standard path separator byte
|
||||||
|
pub static SEP_BYTE: u8 = SEP as u8;
|
||||||
|
|
||||||
/// The alternative path separator character
|
/// The alternative path separator character
|
||||||
pub static sep2: char = '/';
|
pub static SEP2: char = '/';
|
||||||
|
/// The alternative path separator character
|
||||||
|
pub static SEP2_BYTE: u8 = SEP2 as u8;
|
||||||
|
|
||||||
/// Returns whether the given char is a path separator.
|
/// Returns whether the given char is a path separator.
|
||||||
/// Allows both the primary separator '\' and the alternative separator '/'.
|
/// Allows both the primary separator '\' and the alternative separator '/'.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sep(c: char) -> bool {
|
pub fn is_sep(c: char) -> bool {
|
||||||
c == sep || c == sep2
|
c == SEP || c == SEP2
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given char is a path separator.
|
/// Returns whether the given char is a path separator.
|
||||||
/// Only allows the primary separator '\'; use is_sep to allow '/'.
|
/// Only allows the primary separator '\'; use is_sep to allow '/'.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sep_verbatim(c: char) -> bool {
|
pub fn is_sep_verbatim(c: char) -> bool {
|
||||||
c == sep
|
c == SEP
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given byte is a path separator.
|
/// Returns whether the given byte is a path separator.
|
||||||
/// Allows both the primary separator '\' and the alternative separator '/'.
|
/// Allows both the primary separator '\' and the alternative separator '/'.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sep_byte(u: &u8) -> bool {
|
pub fn is_sep_byte(u: &u8) -> bool {
|
||||||
*u as char == sep || *u as char == sep2
|
*u == SEP_BYTE || *u == SEP2_BYTE
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given byte is a path separator.
|
/// Returns whether the given byte is a path separator.
|
||||||
/// Only allows the primary separator '\'; use is_sep_byte to allow '/'.
|
/// Only allows the primary separator '\'; use is_sep_byte to allow '/'.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sep_byte_verbatim(u: &u8) -> bool {
|
pub fn is_sep_byte_verbatim(u: &u8) -> bool {
|
||||||
*u as char == sep
|
*u == SEP_BYTE
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prefix types for Path
|
/// Prefix types for Path
|
||||||
|
Loading…
Reference in New Issue
Block a user