Skip to content

Commit d202834

Browse files
committed
Initial sketching out of the new path module
Define the basic types, and the GenericPath trait. This module is currently called path2. It will be renamed later.
1 parent 1252ad4 commit d202834

File tree

2 files changed

+286
-0
lines changed

2 files changed

+286
-0
lines changed

src/libstd/path2.rs

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Cross-platform file path handling (re-write)
12+
13+
use c_str::{CString, ToCStr};
14+
use clone::Clone;
15+
use cmp::Eq;
16+
use from_str::FromStr;
17+
use option::{Option, None, Some};
18+
use str;
19+
use str::{OwnedStr, Str, StrSlice};
20+
use to_str::ToStr;
21+
22+
/// Typedef for the platform-native path type
23+
#[cfg(unix)]
24+
pub type Path = PosixPath;
25+
// /// Typedef for the platform-native path type
26+
//#[cfg(windows)]
27+
//pub type Path = WindowsPath;
28+
29+
/// Represents a POSIX file path
30+
#[deriving(Clone, DeepClone)]
31+
pub struct PosixPath {
32+
priv repr: ~str, // assumed to never be empty
33+
priv sepidx: Option<uint> // index of the final separator in repr
34+
}
35+
36+
impl Eq for PosixPath {
37+
fn eq(&self, other: &PosixPath) -> bool {
38+
self.repr == other.repr
39+
}
40+
}
41+
42+
impl FromStr for PosixPath {
43+
fn from_str(s: &str) -> Option<PosixPath> {
44+
Some(PosixPath::new(s))
45+
}
46+
}
47+
48+
/// A trait that represents the generic operations available on paths
49+
pub trait GenericPath: Clone {
50+
/// Creates a new Path from a string.
51+
/// The resulting path will always be normalized.
52+
fn from_str(path: &str) -> Self;
53+
54+
/// Returns the path as a string
55+
fn as_str<'a>(&'a self) -> &'a str;
56+
57+
/// Returns the directory component of `self`, as a string (with no trailing separator).
58+
/// If `self` has no directory component, returns ".".
59+
fn dirname<'a>(&'a self) -> &'a str;
60+
/// Returns the file component of `self`, as a string.
61+
/// If `self` represents the root of the file hierarchy, returns the empty string.
62+
/// If `self` is ".", returns the empty string.
63+
fn filename<'a>(&'a self) -> &'a str;
64+
/// Returns the stem of the filename of `self`, as a string.
65+
/// The stem is the portion of the filename just before the last '.'.
66+
/// If there is no '.', the entire filename is returned.
67+
fn filestem<'a>(&'a self) -> &'a str {
68+
let name = self.filename();
69+
match name.rfind('.') {
70+
None | Some(0) => name,
71+
Some(1) if name == ".." => name,
72+
Some(pos) => name.slice_to(pos)
73+
}
74+
}
75+
/// Returns the extension of the filename of `self`, as a string option.
76+
/// The extension is the portion of the filename just after the last '.'.
77+
/// If there is no extension, None is returned.
78+
/// If the filename ends in '.', the empty string is returned.
79+
fn extension<'a>(&'a self) -> Option<&'a str> {
80+
let name = self.filename();
81+
match name.rfind('.') {
82+
None | Some(0) => None,
83+
Some(1) if name == ".." => None,
84+
Some(pos) => Some(name.slice_from(pos+1))
85+
}
86+
}
87+
88+
/// Replaces the directory portion of the path with the given string.
89+
/// If `self` represents the root of the filesystem hierarchy, the last path component
90+
/// of the given string becomes the filename.
91+
fn set_dirname(&mut self, dirname: &str);
92+
/// Replaces the filename portion of the path with the given string.
93+
/// If the replacement name is "", this is equivalent to popping the path.
94+
fn set_filename(&mut self, filename: &str);
95+
/// Replaces the filestem with the given string.
96+
/// If there is no extension in `self` (or `self` has no filename), this is equivalent
97+
/// to `set_filename`. Otherwise, if the given string is "", the extension (including
98+
/// the preceding ".") becomes the new filename.
99+
fn set_filestem(&mut self, filestem: &str) {
100+
// borrowck is being a pain here
101+
let val = {
102+
let name = self.filename();
103+
if !name.is_empty() {
104+
match name.rfind('.') {
105+
None | Some(0) => None,
106+
Some(idx) => {
107+
let mut s = str::with_capacity(filestem.len() + name.len() - idx);
108+
s.push_str(filestem);
109+
s.push_str(name.slice_from(idx));
110+
Some(s)
111+
}
112+
}
113+
} else { None }
114+
};
115+
match val {
116+
None => self.set_filename(filestem),
117+
Some(s) => self.set_filename(s)
118+
}
119+
}
120+
/// Replaces the extension with the given string.
121+
/// If there is no extension in `self`, this adds one.
122+
/// If the given string is "", this removes the extension.
123+
/// If `self` has no filename, this is a no-op.
124+
fn set_extension(&mut self, extension: &str) {
125+
// borrowck causes problems here too
126+
let val = {
127+
let name = self.filename();
128+
if !name.is_empty() {
129+
match name.rfind('.') {
130+
None | Some(0) => {
131+
if extension.is_empty() {
132+
None
133+
} else {
134+
let mut s = str::with_capacity(name.len() + extension.len() + 1);
135+
s.push_str(name);
136+
s.push_char('.');
137+
s.push_str(extension);
138+
Some(s)
139+
}
140+
}
141+
Some(idx) => {
142+
if extension.is_empty() {
143+
Some(name.slice_to(idx).to_owned())
144+
} else {
145+
let mut s = str::with_capacity(idx + extension.len() + 1);
146+
s.push_str(name.slice_to(idx+1));
147+
s.push_str(extension);
148+
Some(s)
149+
}
150+
}
151+
}
152+
} else { None }
153+
};
154+
match val {
155+
None => (),
156+
Some(s) => self.set_filename(s)
157+
}
158+
}
159+
160+
/// Returns a new Path constructed by replacing the dirname with the given string.
161+
/// See `set_dirname` for details.
162+
fn with_dirname(&self, dirname: &str) -> Self {
163+
let mut p = self.clone();
164+
p.set_dirname(dirname);
165+
p
166+
}
167+
/// Returns a new Path constructed by replacing the filename with the given string.
168+
/// See `set_filename` for details.
169+
fn with_filename(&self, filename: &str) -> Self {
170+
let mut p = self.clone();
171+
p.set_filename(filename);
172+
p
173+
}
174+
/// Returns a new Path constructed by setting the filestem to the given string.
175+
/// See `set_filestem` for details.
176+
fn with_filestem(&self, filestem: &str) -> Self {
177+
let mut p = self.clone();
178+
p.set_filestem(filestem);
179+
p
180+
}
181+
/// Returns a new Path constructed by setting the extension to the given string.
182+
/// See `set_extension` for details.
183+
fn with_extension(&self, extension: &str) -> Self {
184+
let mut p = self.clone();
185+
p.set_extension(extension);
186+
p
187+
}
188+
189+
190+
/// Returns the directory component of `self`, as a Path.
191+
/// If `self` represents the root of the filesystem hierarchy, returns `self`.
192+
fn dir_path(&self) -> Self {
193+
GenericPath::from_str(self.dirname())
194+
}
195+
/// Returns the file component of `self`, as a relative Path.
196+
/// If `self` represents the root of the filesystem hierarchy, returns None.
197+
fn file_path(&self) -> Option<Self> {
198+
match self.filename() {
199+
"" => None,
200+
s => Some(GenericPath::from_str(s))
201+
}
202+
}
203+
204+
/// Pushes a path (as a string) onto `self`.
205+
/// If the argument represents an absolute path, it replaces `self`.
206+
fn push(&mut self, path: &str);
207+
/// Pushes a Path onto `self`.
208+
/// If the argument represents an absolute path, it replaces `self`.
209+
fn push_path(&mut self, path: &Self);
210+
/// Pops the last path component off of `self` and returns it.
211+
/// If `self` represents the root of the file hierarchy, None is returned.
212+
fn pop_opt(&mut self) -> Option<~str>;
213+
214+
/// Returns a new Path constructed by joining `self` with the given path (as a string).
215+
/// If the given path is absolute, the new Path will represent just that.
216+
fn join(&self, path: &str) -> Self {
217+
let mut p = self.clone();
218+
p.push(path);
219+
p
220+
}
221+
/// Returns a new Path constructed by joining `self` with the given path.
222+
/// If the given path is absolute, the new Path will represent just that.
223+
fn join_path(&self, path: &Self) -> Self {
224+
let mut p = self.clone();
225+
p.push_path(path);
226+
p
227+
}
228+
229+
/// Returns whether `self` represents an absolute path.
230+
fn is_absolute(&self) -> bool;
231+
232+
/// Returns whether `self` is equal to, or is an ancestor of, the given path.
233+
/// If both paths are relative, they are compared as though they are relative
234+
/// to the same parent path.
235+
fn is_ancestor_of(&self, other: &Self) -> bool;
236+
237+
/// Returns the Path that, were it joined to `base`, would yield `self`.
238+
/// If no such path exists, None is returned.
239+
/// If `self` is absolute and `base` is relative, or on Windows if both
240+
/// paths refer to separate drives, an absolute path is returned.
241+
fn path_relative_from(&self, base: &Self) -> Option<Self>;
242+
}
243+
244+
impl ToStr for PosixPath {
245+
#[inline]
246+
fn to_str(&self) -> ~str {
247+
self.as_str().to_owned()
248+
}
249+
}
250+
251+
impl ToCStr for PosixPath {
252+
#[inline]
253+
fn to_c_str(&self) -> CString {
254+
self.as_str().to_c_str()
255+
}
256+
257+
#[inline]
258+
unsafe fn to_c_str_unchecked(&self) -> CString {
259+
self.as_str().to_c_str_unchecked()
260+
}
261+
}
262+
263+
/// Various POSIX helpers
264+
pub mod posix {
265+
/// The standard path separator character
266+
pub static sep: char = '/';
267+
268+
/// Returns whether the given char is a path separator
269+
#[inline]
270+
pub fn is_sep(u: char) -> bool {
271+
u == sep
272+
}
273+
}
274+
275+
/// Various Windows helpers
276+
pub mod windows {
277+
/// The standard path separator character
278+
pub static sep: char = '\\';
279+
280+
/// Returns whether the given char is a path separator (both / and \)
281+
#[inline]
282+
pub fn is_sep(u: char) -> bool {
283+
u == sep || u == '/'
284+
}
285+
}

src/libstd/std.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ pub mod libc;
177177
pub mod c_str;
178178
pub mod os;
179179
pub mod path;
180+
pub mod path2;
180181
pub mod rand;
181182
pub mod run;
182183
pub mod sys;

0 commit comments

Comments
 (0)