Factor shared code out into default GenericPath methods.

This commit is contained in:
Lindsey Kuper 2013-08-31 23:51:07 -04:00
parent d285ea7910
commit 8651011b6f

View File

@ -57,42 +57,97 @@ pub fn PosixPath(s: &str) -> PosixPath {
GenericPath::from_str(s)
}
pub trait GenericPath {
pub trait GenericPath : Clone + Eq + ToStr {
/// Converts a string to a Path
fn from_str(&str) -> Self;
/// Returns the directory component of `self`, as a string
fn dirname(&self) -> ~str;
fn dirname(&self) -> ~str {
let s = self.dir_path().to_str();
match s.len() {
0 => ~".",
_ => s,
}
}
/// Returns the file component of `self`, as a string option.
/// Returns None if `self` names a directory.
fn filename<'a>(&'a self) -> Option<&'a str>;
fn filename<'a>(&'a self) -> Option<&'a str> {
match self.components().len() {
0 => None,
n => Some(self.components()[n - 1].as_slice()),
}
}
/// Returns the stem of the file component of `self`, as a string option.
/// The stem is the slice of a filename starting at 0 and ending just before
/// the last '.' in the name.
/// Returns None if `self` names a directory.
fn filestem<'a>(&'a self) -> Option<&'a str>;
fn filestem<'a>(&'a self) -> Option<&'a str> {
match self.filename() {
None => None,
Some(ref f) => {
match f.rfind('.') {
Some(p) => Some(f.slice_to(p)),
None => Some((*f)),
}
}
}
}
/// Returns the type of the file component of `self`, as a string option.
/// The file type is the slice of a filename starting just after the last
/// '.' in the name and ending at the last index in the filename.
/// Returns None if `self` names a directory.
fn filetype<'a>(&'a self) -> Option<&'a str>;
fn filetype<'a>(&'a self) -> Option<&'a str> {
match self.filename() {
None => None,
Some(ref f) => {
match f.rfind('.') {
Some(p) if p < f.len() => Some(f.slice_from(p)),
_ => None,
}
}
}
}
/// Returns a new path consisting of `self` with the parent directory component replaced
/// with the given string.
fn with_dirname(&self, (&str)) -> Self;
/// Returns a new path consisting of `self` with the file component replaced
/// with the given string.
fn with_filename(&self, (&str)) -> Self;
/// Returns a new path consisting of `self` with the file stem replaced
/// with the given string.
fn with_filestem(&self, (&str)) -> Self;
fn with_filestem(&self, s: &str) -> Self {
match self.filetype() {
None => self.with_filename(s),
Some(ref t) => self.with_filename(s.to_owned() + *t),
}
}
/// Returns a new path consisting of `self` with the file type replaced
/// with the given string.
fn with_filetype(&self, (&str)) -> Self;
fn with_filetype(&self, t: &str) -> Self {
match (t.len(), self.filestem()) {
(0, None) => (*self).clone(),
(0, Some(ref s)) => self.with_filename(*s),
(_, None) => self.with_filename(fmt!(".%s", t)),
(_, Some(ref s)) => self.with_filename(fmt!("%s.%s", *s, t)),
}
}
/// Returns the directory component of `self`, as a new path.
/// If `self` has no parent, returns `self`.
fn dir_path(&self) -> Self;
fn dir_path(&self) -> Self {
match self.components().len() {
0 => (*self).clone(),
_ => self.pop(),
}
}
/// Returns the file component of `self`, as a new path.
/// If `self` names a directory, returns the empty path.
fn file_path(&self) -> Self;
@ -100,11 +155,17 @@ pub trait GenericPath {
/// Returns a new Path whose parent directory is `self` and whose
/// file component is the given string.
fn push(&self, (&str)) -> Self;
/// Returns a new Path consisting of the given path, made relative to `self`.
fn push_rel(&self, (&Self)) -> Self;
fn push_rel(&self, other: &Self) -> Self {
assert!(!other.is_absolute());
self.push_many(other.components())
}
/// Returns a new Path consisting of the path given by the given vector
/// of strings, relative to `self`.
fn push_many<S: Str>(&self, (&[S])) -> Self;
/// Identical to `dir_path` except in the case where `self` has only one
/// component. In this case, `pop` returns the empty path.
fn pop(&self) -> Self;
@ -112,6 +173,7 @@ pub trait GenericPath {
/// The same as `push_rel`, except that the directory argument must not
/// contain directory separators in any of its components.
fn unsafe_join(&self, (&Self)) -> Self;
/// On Unix, always returns false. On Windows, returns true iff `self`'s
/// file stem is one of: `con` `aux` `com1` `com2` `com3` `com4`
/// `lpt1` `lpt2` `lpt3` `prn` `nul`
@ -126,7 +188,14 @@ pub trait GenericPath {
fn is_absolute(&self) -> bool;
/// True if `self` is an ancestor of `other`. See `test_is_ancestor_of` for examples
fn is_ancestor_of(&self, (&Self)) -> bool;
fn is_ancestor_of(&self, other: &Self) -> bool {
debug!("%s / %s %? %?", self.to_str(), other.to_str(), self.is_absolute(),
self.components().len());
self == other ||
(!other.components().is_empty() &&
!(self.components().is_empty() && !self.is_absolute()) &&
self.is_ancestor_of(&other.pop()))
}
/// Find the relative path from one file to another
fn get_relative_to(&self, abs2: (&Self)) -> Self {
@ -578,8 +647,6 @@ impl ToCStr for PosixPath {
}
}
// FIXME (#3227): when default methods in traits are working, de-duplicate
// PosixPath and WindowsPath, most of their methods are common.
impl GenericPath for PosixPath {
fn from_str(s: &str) -> PosixPath {
let components = s.split_iter('/')
@ -592,45 +659,6 @@ impl GenericPath for PosixPath {
}
}
fn dirname(&self) -> ~str {
let s = self.dir_path().to_str();
match s.len() {
0 => ~".",
_ => s,
}
}
fn filename<'a>(&'a self) -> Option<&'a str> {
match self.components.len() {
0 => None,
n => Some(self.components[n - 1].as_slice()),
}
}
fn filestem<'a>(&'a self) -> Option<&'a str> {
match self.filename() {
None => None,
Some(ref f) => {
match f.rfind('.') {
Some(p) => Some(f.slice_to(p)),
None => Some((*f)),
}
}
}
}
fn filetype<'a>(&'a self) -> Option<&'a str> {
match self.filename() {
None => None,
Some(ref f) => {
match f.rfind('.') {
Some(p) if p < f.len() => Some(f.slice_from(p)),
_ => None,
}
}
}
}
fn with_dirname(&self, d: &str) -> PosixPath {
let dpath = PosixPath(d);
match self.filename() {
@ -644,29 +672,6 @@ impl GenericPath for PosixPath {
self.dir_path().push(f)
}
fn with_filestem(&self, s: &str) -> PosixPath {
match self.filetype() {
None => self.with_filename(s),
Some(ref t) => self.with_filename(s.to_owned() + *t),
}
}
fn with_filetype(&self, t: &str) -> PosixPath {
match (t.len(), self.filestem()) {
(0, None) => (*self).clone(),
(0, Some(ref s)) => self.with_filename(*s),
(_, None) => self.with_filename(fmt!(".%s", t)),
(_, Some(ref s)) => self.with_filename(fmt!("%s.%s", *s, t)),
}
}
fn dir_path(&self) -> PosixPath {
match self.components.len() {
0 => (*self).clone(),
_ => self.pop(),
}
}
fn file_path(&self) -> PosixPath {
let cs = match self.filename() {
None => ~[],
@ -678,24 +683,17 @@ impl GenericPath for PosixPath {
}
}
fn push_rel(&self, other: &PosixPath) -> PosixPath {
assert!(!other.is_absolute);
self.push_many(other.components)
}
fn unsafe_join(&self, other: &PosixPath) -> PosixPath {
if other.is_absolute {
PosixPath {
is_absolute: true,
components: other.components.clone(),
fn push(&self, s: &str) -> PosixPath {
let mut v = self.components.clone();
for s in s.split_iter(posix::is_sep) {
if !s.is_empty() {
v.push(s.to_owned())
}
} else {
self.push_rel(other)
}
}
fn is_restricted(&self) -> bool {
false
PosixPath {
components: v,
..(*self).clone()
}
}
fn push_many<S: Str>(&self, cs: &[S]) -> PosixPath {
@ -713,19 +711,6 @@ impl GenericPath for PosixPath {
}
}
fn push(&self, s: &str) -> PosixPath {
let mut v = self.components.clone();
for s in s.split_iter(posix::is_sep) {
if !s.is_empty() {
v.push(s.to_owned())
}
}
PosixPath {
components: v,
..(*self).clone()
}
}
fn pop(&self) -> PosixPath {
let mut cs = self.components.clone();
if cs.len() != 0 {
@ -737,6 +722,21 @@ impl GenericPath for PosixPath {
} //..self }
}
fn unsafe_join(&self, other: &PosixPath) -> PosixPath {
if other.is_absolute {
PosixPath {
is_absolute: true,
components: other.components.clone(),
}
} else {
self.push_rel(other)
}
}
fn is_restricted(&self) -> bool {
false
}
fn normalize(&self) -> PosixPath {
PosixPath {
is_absolute: self.is_absolute,
@ -748,15 +748,8 @@ impl GenericPath for PosixPath {
self.is_absolute
}
fn is_ancestor_of(&self, other: &PosixPath) -> bool {
debug!("%s / %s %? %?", self.to_str(), other.to_str(), self.is_absolute,
self.components.len());
self == other ||
(!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) &&
self.is_ancestor_of(&other.pop()))
}
fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() }
fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() }
}
@ -834,45 +827,6 @@ impl GenericPath for WindowsPath {
}
}
fn dirname(&self) -> ~str {
let s = self.dir_path().to_str();
match s.len() {
0 => ~".",
_ => s,
}
}
fn filename<'a>(&'a self) -> Option<&'a str> {
match self.components.len() {
0 => None,
n => Some(self.components[n - 1].as_slice()),
}
}
fn filestem<'a>(&'a self) -> Option<&'a str> {
match self.filename() {
None => None,
Some(ref f) => {
match f.rfind('.') {
Some(p) => Some(f.slice_to(p)),
None => Some((*f)),
}
}
}
}
fn filetype<'a>(&'a self) -> Option<&'a str> {
match self.filename() {
None => None,
Some(ref f) => {
match f.rfind('.') {
Some(p) if p < f.len() => Some(f.slice_from(p)),
_ => None,
}
}
}
}
fn with_dirname(&self, d: &str) -> WindowsPath {
let dpath = WindowsPath(d);
match self.filename() {
@ -886,29 +840,6 @@ impl GenericPath for WindowsPath {
self.dir_path().push(f)
}
fn with_filestem(&self, s: &str) -> WindowsPath {
match self.filetype() {
None => self.with_filename(s),
Some(ref t) => self.with_filename(s.to_owned() + *t),
}
}
fn with_filetype(&self, t: &str) -> WindowsPath {
match (t.len(), self.filestem()) {
(0, None) => (*self).clone(),
(0, Some(ref s)) => self.with_filename(*s),
(_, None) => self.with_filename(fmt!(".%s", t)),
(_, Some(ref s)) => self.with_filename(fmt!("%s.%s", *s, t)),
}
}
fn dir_path(&self) -> WindowsPath {
match self.components.len() {
0 => (*self).clone(),
_ => self.pop(),
}
}
fn file_path(&self) -> WindowsPath {
WindowsPath {
host: None,
@ -921,9 +852,45 @@ impl GenericPath for WindowsPath {
}
}
fn push_rel(&self, other: &WindowsPath) -> WindowsPath {
assert!(!other.is_absolute);
self.push_many(other.components)
fn push(&self, s: &str) -> WindowsPath {
let mut v = self.components.clone();
for s in s.split_iter(windows::is_sep) {
if !s.is_empty() {
v.push(s.to_owned())
}
}
WindowsPath { components: v, ..(*self).clone() }
}
fn push_many<S: Str>(&self, cs: &[S]) -> WindowsPath {
let mut v = self.components.clone();
for e in cs.iter() {
for s in e.as_slice().split_iter(windows::is_sep) {
if !s.is_empty() {
v.push(s.to_owned())
}
}
}
// tedious, but as-is, we can't use ..self
WindowsPath {
host: self.host.clone(),
device: self.device.clone(),
is_absolute: self.is_absolute,
components: v
}
}
fn pop(&self) -> WindowsPath {
let mut cs = self.components.clone();
if cs.len() != 0 {
cs.pop();
}
WindowsPath {
host: self.host.clone(),
device: self.device.clone(),
is_absolute: self.is_absolute,
components: cs,
}
}
fn unsafe_join(&self, other: &WindowsPath) -> WindowsPath {
@ -983,47 +950,6 @@ impl GenericPath for WindowsPath {
}
}
fn push_many<S: Str>(&self, cs: &[S]) -> WindowsPath {
let mut v = self.components.clone();
for e in cs.iter() {
for s in e.as_slice().split_iter(windows::is_sep) {
if !s.is_empty() {
v.push(s.to_owned())
}
}
}
// tedious, but as-is, we can't use ..self
WindowsPath {
host: self.host.clone(),
device: self.device.clone(),
is_absolute: self.is_absolute,
components: v
}
}
fn push(&self, s: &str) -> WindowsPath {
let mut v = self.components.clone();
for s in s.split_iter(windows::is_sep) {
if !s.is_empty() {
v.push(s.to_owned())
}
}
WindowsPath { components: v, ..(*self).clone() }
}
fn pop(&self) -> WindowsPath {
let mut cs = self.components.clone();
if cs.len() != 0 {
cs.pop();
}
WindowsPath {
host: self.host.clone(),
device: self.device.clone(),
is_absolute: self.is_absolute,
components: cs,
}
}
fn normalize(&self) -> WindowsPath {
WindowsPath {
host: self.host.clone(),
@ -1043,13 +969,8 @@ impl GenericPath for WindowsPath {
self.is_absolute
}
fn is_ancestor_of(&self, other: &WindowsPath) -> bool {
self == other ||
(!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) &&
self.is_ancestor_of(&other.pop()))
}
fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() }
fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() }
}
pub fn normalize(components: &[~str]) -> ~[~str] {