faster_path 0.3.7 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -24
- data/lib/faster_path.rb +2 -26
- data/lib/faster_path/optional/monkeypatches.rb +2 -2
- data/lib/faster_path/thermite_initialize.rb +2 -1
- data/lib/faster_path/version.rb +1 -1
- data/src/basename.rs +63 -20
- data/src/chop_basename.rs +12 -13
- data/src/cleanpath_aggressive.rs +21 -33
- data/src/cleanpath_conservative.rs +27 -41
- data/src/dirname.rs +59 -19
- data/src/extname.rs +19 -57
- data/src/helpers.rs +13 -8
- data/src/lib.rs +14 -9
- data/src/memrnchr.rs +70 -0
- data/src/path_parsing.rs +23 -14
- data/src/pathname.rs +79 -122
- data/src/prepend_prefix.rs +12 -11
- data/src/relative_path_from.rs +17 -15
- metadata +3 -2
data/src/dirname.rs
CHANGED
@@ -1,26 +1,66 @@
|
|
1
|
-
|
2
|
-
use
|
3
|
-
use path_parsing::{SEP, SEP_STR, last_non_sep_i, last_non_sep_i_before};
|
1
|
+
use std::str;
|
2
|
+
use path_parsing::{find_last_sep_pos, find_last_non_sep_pos};
|
4
3
|
|
5
4
|
pub fn dirname(path: &str) -> &str {
|
6
|
-
|
7
|
-
let
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
5
|
+
let bytes = path.as_bytes();
|
6
|
+
let mut last_slash_pos = match find_last_sep_pos(bytes) {
|
7
|
+
Some(pos) => pos,
|
8
|
+
_ => return ".",
|
9
|
+
};
|
10
|
+
// Skip trailing slashes.
|
11
|
+
if last_slash_pos == bytes.len() - 1 {
|
12
|
+
let last_non_slash_pos = match find_last_non_sep_pos(&bytes[..last_slash_pos]) {
|
13
|
+
Some(pos) => pos,
|
14
|
+
_ => return "/"
|
15
|
+
};
|
16
|
+
last_slash_pos = match find_last_sep_pos(&bytes[..last_non_slash_pos]) {
|
17
|
+
Some(pos) => pos,
|
18
|
+
_ => return "."
|
19
|
+
};
|
20
|
+
};
|
21
|
+
if let Some(end) = find_last_non_sep_pos(&bytes[..last_slash_pos]) {
|
22
|
+
&path[..end + 1]
|
23
|
+
} else {
|
24
|
+
"/"
|
20
25
|
}
|
21
26
|
}
|
22
27
|
|
23
28
|
#[test]
|
24
|
-
fn
|
25
|
-
assert_eq!(dirname(""), "
|
29
|
+
fn absolute() {
|
30
|
+
assert_eq!(dirname("/a/b///c"), "/a/b");
|
31
|
+
}
|
32
|
+
|
33
|
+
#[test]
|
34
|
+
fn trailing_slashes_absolute() {
|
35
|
+
assert_eq!(dirname("/a/b///c//////"), "/a/b");
|
36
|
+
}
|
37
|
+
|
38
|
+
#[test]
|
39
|
+
fn relative() {
|
40
|
+
assert_eq!(dirname("b///c"), "b");
|
41
|
+
}
|
42
|
+
|
43
|
+
#[test]
|
44
|
+
fn trailing_slashes_relative() {
|
45
|
+
assert_eq!(dirname("b/c//"), "b");
|
46
|
+
}
|
47
|
+
|
48
|
+
#[test]
|
49
|
+
fn root() {
|
50
|
+
assert_eq!(dirname("//c"), "/");
|
51
|
+
}
|
52
|
+
|
53
|
+
#[test]
|
54
|
+
fn trailing_slashes_root() {
|
55
|
+
assert_eq!(dirname("//c//"), "/");
|
56
|
+
}
|
57
|
+
|
58
|
+
#[test]
|
59
|
+
fn trailing_slashes_relative_root() {
|
60
|
+
assert_eq!(dirname("c//"), ".");
|
61
|
+
}
|
62
|
+
|
63
|
+
#[test]
|
64
|
+
fn returns_dot_for_empty_string() {
|
65
|
+
assert_eq!(dirname(""), ".");
|
26
66
|
}
|
data/src/extname.rs
CHANGED
@@ -1,63 +1,25 @@
|
|
1
|
-
use path_parsing::SEP;
|
2
1
|
use std::str;
|
2
|
+
use path_parsing::{SEP, find_last_non_sep_pos};
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
start: usize,
|
9
|
-
end: usize,
|
10
|
-
}
|
11
|
-
|
12
|
-
impl ExtnameCoords {
|
13
|
-
pub fn dec(&mut self) {
|
14
|
-
self.start -= 1;
|
15
|
-
if !self.word {
|
16
|
-
self.end -= 1;
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
|
21
|
-
pub fn extname(pth: &str) -> &str {
|
22
|
-
let path = pth.as_bytes();
|
23
|
-
let mut extname = ExtnameCoords {
|
24
|
-
word: false,
|
25
|
-
pred: false,
|
26
|
-
dot: false,
|
27
|
-
start: path.len(),
|
28
|
-
end: path.len(),
|
4
|
+
pub fn extname(path: &str) -> &str {
|
5
|
+
let end = match find_last_non_sep_pos(path.as_bytes()) {
|
6
|
+
Some(pos) => pos + 1,
|
7
|
+
_ => return "",
|
29
8
|
};
|
30
|
-
|
31
|
-
for
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
if extname.word {
|
42
|
-
extname.dot = true;
|
43
|
-
}
|
44
|
-
} else {
|
45
|
-
if extname.dot {
|
46
|
-
extname.pred = true;
|
47
|
-
break;
|
48
|
-
} else {
|
49
|
-
extname.word = true;
|
50
|
-
}
|
51
|
-
|
52
|
-
if !extname.pred {
|
53
|
-
extname.dec()
|
9
|
+
let bytes = &path.as_bytes()[..end];
|
10
|
+
for (pos, c) in bytes.iter().enumerate().rev() {
|
11
|
+
match *c {
|
12
|
+
b'.' => {
|
13
|
+
let prev = bytes.get(pos - 1);
|
14
|
+
if pos == end - 1 || prev == None || prev == Some(&SEP) {
|
15
|
+
return "";
|
16
|
+
} else {
|
17
|
+
return &path[pos..end]
|
18
|
+
};
|
54
19
|
}
|
20
|
+
SEP => return "",
|
21
|
+
_ => {}
|
55
22
|
}
|
56
|
-
}
|
57
|
-
|
58
|
-
if !extname.pred {
|
59
|
-
return "";
|
60
|
-
}
|
61
|
-
|
62
|
-
str::from_utf8(&path[extname.start..extname.end]).unwrap_or("")
|
23
|
+
};
|
24
|
+
""
|
63
25
|
}
|
data/src/helpers.rs
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
use ruru::{RString, Object, Class, AnyObject};
|
2
2
|
extern crate ruby_sys;
|
3
3
|
use debug::RubyDebugInfo;
|
4
|
-
use
|
4
|
+
use ruru;
|
5
|
+
|
6
|
+
type MaybeString = Result<ruru::RString, ruru::result::Error>;
|
5
7
|
|
6
8
|
pub trait TryFrom<T>: Sized {
|
7
9
|
type Error;
|
@@ -23,21 +25,24 @@ pub fn anyobject_to_string(item: AnyObject) -> Result<String, RubyDebugInfo> {
|
|
23
25
|
if Class::from_existing("String").case_equals(result) {
|
24
26
|
return Ok(RString::from(result.value()).to_string())
|
25
27
|
}
|
26
|
-
|
28
|
+
|
27
29
|
if Class::from_existing("Pathname").case_equals(result) {
|
28
30
|
return Ok(result.instance_variable_get("@path").
|
29
31
|
try_convert_to::<RString>().
|
30
32
|
unwrap_or(RString::new("")).
|
31
33
|
to_string())
|
32
34
|
}
|
33
|
-
|
35
|
+
|
34
36
|
if result.respond_to("to_path") {
|
35
|
-
return Ok(
|
36
|
-
instance_variable_get("@path").
|
37
|
-
try_convert_to::<RString>().
|
38
|
-
unwrap_or(RString::new("")).
|
39
|
-
to_string())
|
37
|
+
return Ok(RString::from(result.send("to_path", None).value()).to_string())
|
40
38
|
}
|
41
39
|
|
42
40
|
Ok(RString::from(result.send("to_s", None).value()).to_string())
|
43
41
|
}
|
42
|
+
|
43
|
+
pub fn to_str(maybe_string: &MaybeString) -> &str {
|
44
|
+
match maybe_string {
|
45
|
+
&Ok(ref ruru_string) => ruru_string.to_str(),
|
46
|
+
&Err(_) => "",
|
47
|
+
}
|
48
|
+
}
|
data/src/lib.rs
CHANGED
@@ -25,13 +25,14 @@ mod pathname_sys;
|
|
25
25
|
mod plus;
|
26
26
|
mod prepend_prefix;
|
27
27
|
pub mod rust_arch_bits;
|
28
|
+
mod memrnchr;
|
28
29
|
mod path_parsing;
|
29
30
|
mod relative_path_from;
|
30
31
|
|
31
32
|
use pathname::Pathname;
|
32
33
|
use pathname_sys::raise;
|
33
34
|
|
34
|
-
use ruru::{Module, Object, RString, Boolean,
|
35
|
+
use ruru::{Module, Object, RString, Boolean, AnyObject};
|
35
36
|
|
36
37
|
use pathname_sys::*;
|
37
38
|
|
@@ -54,14 +55,16 @@ methods!(
|
|
54
55
|
}
|
55
56
|
|
56
57
|
fn pub_children(pth: RString, with_dir: Boolean) -> AnyObject {
|
57
|
-
pathname::pn_children(pth, with_dir)
|
58
|
+
pathname::pn_children(pth, with_dir).
|
59
|
+
map_err(|e| raise(e) ).unwrap()
|
58
60
|
}
|
59
61
|
|
60
62
|
fn pub_children_compat(pth: RString, with_dir: Boolean) -> AnyObject {
|
61
|
-
pathname::pn_children_compat(pth, with_dir)
|
63
|
+
pathname::pn_children_compat(pth, with_dir).
|
64
|
+
map_err(|e| raise(e) ).unwrap()
|
62
65
|
}
|
63
66
|
|
64
|
-
fn pub_chop_basename(pth: RString) ->
|
67
|
+
fn pub_chop_basename(pth: RString) -> AnyObject {
|
65
68
|
pathname::pn_chop_basename(pth)
|
66
69
|
}
|
67
70
|
|
@@ -99,12 +102,14 @@ methods!(
|
|
99
102
|
|
100
103
|
// pub_entries returns an array of String objects
|
101
104
|
fn pub_entries(pth: RString) -> AnyObject {
|
102
|
-
pathname::pn_entries(pth)
|
105
|
+
pathname::pn_entries(pth).
|
106
|
+
map_err(|e| raise(e) ).unwrap()
|
103
107
|
}
|
104
108
|
|
105
109
|
// pub_entries_compat returns an array of Pathname objects
|
106
110
|
fn pub_entries_compat(pth: RString) -> AnyObject {
|
107
|
-
pathname::pn_entries_compat(pth)
|
111
|
+
pathname::pn_entries_compat(pth).
|
112
|
+
map_err(|e| raise(e) ).unwrap()
|
108
113
|
}
|
109
114
|
|
110
115
|
fn pub_extname(pth: RString) -> RString {
|
@@ -163,10 +168,13 @@ pub extern "C" fn Init_faster_pathname() {
|
|
163
168
|
itself.def_self("absolute?", pub_is_absolute);
|
164
169
|
itself.def_self("add_trailing_separator", pub_add_trailing_separator);
|
165
170
|
itself.def_self("del_trailing_separator", pub_del_trailing_separator);
|
171
|
+
itself.def_self("chop_basename", pub_chop_basename);
|
166
172
|
itself.def_self("cleanpath_aggressive", pub_cleanpath_aggressive);
|
167
173
|
itself.def_self("cleanpath_conservative", pub_cleanpath_conservative);
|
168
174
|
itself.def_self("directory?", pub_is_directory);
|
169
175
|
itself.def_self("dirname", pub_dirname);
|
176
|
+
itself.def_self("entries", pub_entries);
|
177
|
+
itself.def_self("entries_compat", pub_entries_compat);
|
170
178
|
itself.def_self("extname", pub_extname);
|
171
179
|
itself.def_self("has_trailing_separator?", pub_has_trailing_separator);
|
172
180
|
//itself.def_self("join", pub_join);
|
@@ -182,8 +190,5 @@ pub extern "C" fn Init_faster_pathname() {
|
|
182
190
|
itself.def_self("basename", pub_basename);
|
183
191
|
itself.def_self("children", pub_children);
|
184
192
|
itself.def_self("children_compat", pub_children_compat);
|
185
|
-
itself.def_self("chop_basename", pub_chop_basename);
|
186
|
-
itself.def_self("entries", pub_entries);
|
187
|
-
itself.def_self("entries_compat", pub_entries_compat);
|
188
193
|
});
|
189
194
|
}
|
data/src/memrnchr.rs
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
// The code below is based on the fallback `memrchr` implementation from the respective crate.
|
2
|
+
//
|
3
|
+
// We use this mainly to skip repeated `/`. If there is only one slash, `memrnchr` performs the same
|
4
|
+
// as a naive version (e.g. `rposition`). However, it is much faster in pathological cases.
|
5
|
+
|
6
|
+
use std::mem::size_of;
|
7
|
+
|
8
|
+
// Returns the byte offset of the last byte that is NOT equal to the given one.
|
9
|
+
#[inline(always)]
|
10
|
+
pub fn memrnchr(x: u8, text: &[u8]) -> Option<usize> {
|
11
|
+
// Scan for a single byte value by reading two `usize` words at a time.
|
12
|
+
//
|
13
|
+
// Split `text` in three parts
|
14
|
+
// - unaligned tail, after the last word aligned address in text
|
15
|
+
// - body, scan by 2 words at a time
|
16
|
+
// - the first remaining bytes, < 2 word size
|
17
|
+
let len = text.len();
|
18
|
+
let ptr = text.as_ptr();
|
19
|
+
|
20
|
+
// search to an aligned boundary
|
21
|
+
let end_align = (ptr as usize + len) & (size_of::<usize>() - 1);
|
22
|
+
let mut offset;
|
23
|
+
if end_align > 0 {
|
24
|
+
offset = if end_align >= len { 0 } else { len - end_align };
|
25
|
+
if let Some(index) = memrnchr_naive(x, &text[offset..]) {
|
26
|
+
return Some(offset + index);
|
27
|
+
}
|
28
|
+
} else {
|
29
|
+
offset = len;
|
30
|
+
}
|
31
|
+
|
32
|
+
// search the body of the text
|
33
|
+
let repeated_x = repeat_byte(x);
|
34
|
+
while offset >= 2 * size_of::<usize>() {
|
35
|
+
debug_assert_eq!((ptr as usize + offset) % size_of::<usize>(), 0);
|
36
|
+
unsafe {
|
37
|
+
let u = *(ptr.offset(offset as isize - 2 * size_of::<usize>() as isize) as *const usize);
|
38
|
+
let v = *(ptr.offset(offset as isize - size_of::<usize>() as isize) as *const usize);
|
39
|
+
if u & repeated_x != usize::max_value() || v & repeated_x != usize::max_value() {
|
40
|
+
break;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
offset -= 2 * size_of::<usize>();
|
44
|
+
}
|
45
|
+
|
46
|
+
// find the byte before the point the body loop stopped
|
47
|
+
memrnchr_naive(x, &text[..offset])
|
48
|
+
}
|
49
|
+
|
50
|
+
#[inline(always)]
|
51
|
+
fn memrnchr_naive(x: u8, text: &[u8]) -> Option<usize> {
|
52
|
+
text.iter().rposition(|c| *c != x)
|
53
|
+
}
|
54
|
+
|
55
|
+
#[cfg(target_pointer_width = "32")]
|
56
|
+
#[inline]
|
57
|
+
fn repeat_byte(b: u8) -> usize {
|
58
|
+
let mut rep = (b as usize) << 8 | b as usize;
|
59
|
+
rep = rep << 16 | rep;
|
60
|
+
rep
|
61
|
+
}
|
62
|
+
|
63
|
+
#[cfg(target_pointer_width = "64")]
|
64
|
+
#[inline]
|
65
|
+
fn repeat_byte(b: u8) -> usize {
|
66
|
+
let mut rep = (b as usize) << 8 | b as usize;
|
67
|
+
rep = rep << 16 | rep;
|
68
|
+
rep = rep << 32 | rep;
|
69
|
+
rep
|
70
|
+
}
|
data/src/path_parsing.rs
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
extern crate memchr;
|
2
|
+
|
3
|
+
use self::memchr::{memchr, memrchr};
|
4
|
+
use memrnchr::memrnchr;
|
2
5
|
use std::path::MAIN_SEPARATOR;
|
3
6
|
use std::str;
|
4
7
|
|
@@ -7,20 +10,26 @@ lazy_static! {
|
|
7
10
|
pub static ref SEP_STR: &'static str = str::from_utf8(&[SEP]).unwrap();
|
8
11
|
}
|
9
12
|
|
10
|
-
// Returns the byte offset of the last byte
|
11
|
-
|
12
|
-
|
13
|
+
// Returns the byte offset of the last byte that equals MAIN_SEPARATOR.
|
14
|
+
#[inline(always)]
|
15
|
+
pub fn find_last_dot_pos(bytes: &[u8]) -> Option<usize> {
|
16
|
+
memrchr(b'.', bytes)
|
17
|
+
}
|
18
|
+
|
19
|
+
// Returns the byte offset of the last byte that equals MAIN_SEPARATOR.
|
20
|
+
#[inline(always)]
|
21
|
+
pub fn find_last_sep_pos(bytes: &[u8]) -> Option<usize> {
|
22
|
+
memrchr(SEP, bytes)
|
23
|
+
}
|
24
|
+
|
25
|
+
// Returns the byte offset of the last byte that is not MAIN_SEPARATOR.
|
26
|
+
#[inline(always)]
|
27
|
+
pub fn find_last_non_sep_pos(bytes: &[u8]) -> Option<usize> {
|
28
|
+
memrnchr(SEP, bytes)
|
13
29
|
}
|
14
30
|
|
15
|
-
//
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
let ptr = path.as_ptr();
|
20
|
-
let mut i = end;
|
21
|
-
while i >= 0 {
|
22
|
-
if unsafe { *ptr.offset(i) } != SEP { break; };
|
23
|
-
i -= 1;
|
24
|
-
}
|
25
|
-
i
|
31
|
+
// Whether the given byte sequence contains a MAIN_SEPARATOR.
|
32
|
+
#[inline(always)]
|
33
|
+
pub fn contains_sep(bytes: &[u8]) -> bool {
|
34
|
+
memchr(SEP, bytes) != None
|
26
35
|
}
|
data/src/pathname.rs
CHANGED
@@ -8,8 +8,9 @@ use extname;
|
|
8
8
|
use plus;
|
9
9
|
use relative_path_from;
|
10
10
|
use debug;
|
11
|
-
use helpers::TryFrom;
|
11
|
+
use helpers::{TryFrom, to_str};
|
12
12
|
use pathname_sys::null_byte_check;
|
13
|
+
use path_parsing::{SEP, find_last_non_sep_pos};
|
13
14
|
|
14
15
|
use ruru;
|
15
16
|
use ruru::{
|
@@ -40,7 +41,7 @@ impl Pathname {
|
|
40
41
|
pub fn new(path: &str) -> Pathname {
|
41
42
|
let mut instance = Class::from_existing("Pathname").allocate();
|
42
43
|
instance.instance_variable_set("@path", RString::new(path).to_any_object());
|
43
|
-
|
44
|
+
|
44
45
|
Pathname { value: instance.value() }
|
45
46
|
}
|
46
47
|
|
@@ -58,14 +59,14 @@ impl Pathname {
|
|
58
59
|
)
|
59
60
|
};
|
60
61
|
|
61
|
-
if null_byte_check(path.value()) {
|
62
|
+
if null_byte_check(path.value()) {
|
62
63
|
return Err( Exception::new("ArgumentError", Some("pathname contains null byte")) )
|
63
64
|
}
|
64
65
|
|
65
66
|
// if it crashes then dup the path string here before assigning to @path
|
66
67
|
let mut instance = Class::from_existing("Pathname").allocate();
|
67
68
|
instance.instance_variable_set("@path", RString::from(pth).to_any_object());
|
68
|
-
|
69
|
+
|
69
70
|
Ok(Pathname { value: instance.value() })
|
70
71
|
}
|
71
72
|
|
@@ -84,11 +85,11 @@ impl TryFrom<AnyObject> for Pathname {
|
|
84
85
|
type Error = debug::RubyDebugInfo;
|
85
86
|
fn try_from(obj: AnyObject) -> Result<Pathname, Self::Error> {
|
86
87
|
if Class::from_existing("String").case_equals(&obj) {
|
87
|
-
Ok(Pathname::new(&RString::from(obj.value()).
|
88
|
+
Ok(Pathname::new(&RString::from(obj.value()).to_str()))
|
88
89
|
} else if Class::from_existing("Pathname").case_equals(&obj) {
|
89
90
|
Ok(Pathname::from(obj.value()))
|
90
91
|
} else if obj.respond_to("to_path") {
|
91
|
-
Ok(Pathname::from(obj.send("to_path", None).value()))
|
92
|
+
Ok(Pathname::new(&RString::from(obj.send("to_path", None).value()).to_str()))
|
92
93
|
} else {
|
93
94
|
Err(Self::Error::from(obj))
|
94
95
|
}
|
@@ -114,7 +115,7 @@ impl VerifiedObject for Pathname {
|
|
114
115
|
}
|
115
116
|
|
116
117
|
pub fn pn_add_trailing_separator(pth: MaybeString) -> RString {
|
117
|
-
let p = pth.
|
118
|
+
let p = pth.unwrap();
|
118
119
|
let x = format!("{}{}", p.to_str(), "a");
|
119
120
|
match x.rsplit_terminator(MAIN_SEPARATOR).next() {
|
120
121
|
Some("a") => p,
|
@@ -123,34 +124,26 @@ pub fn pn_add_trailing_separator(pth: MaybeString) -> RString {
|
|
123
124
|
}
|
124
125
|
|
125
126
|
pub fn pn_is_absolute(pth: MaybeString) -> Boolean {
|
126
|
-
Boolean::new(
|
127
|
-
Some(c) => c == MAIN_SEPARATOR,
|
128
|
-
None => false
|
129
|
-
})
|
127
|
+
Boolean::new(to_str(&pth).as_bytes().get(0) == Some(&SEP))
|
130
128
|
}
|
131
129
|
|
132
130
|
// pub fn pn_ascend(){}
|
133
131
|
|
134
132
|
pub fn pn_basename(pth: MaybeString, ext: MaybeString) -> RString {
|
135
|
-
RString::new(
|
136
|
-
basename::basename(
|
137
|
-
pth.ok().unwrap_or(RString::new("")).to_str(),
|
138
|
-
ext.ok().unwrap_or(RString::new("")).to_str()
|
139
|
-
)
|
140
|
-
)
|
133
|
+
RString::new(basename::basename(to_str(&pth), to_str(&ext)))
|
141
134
|
}
|
142
135
|
|
143
|
-
pub fn pn_children(pth: MaybeString, with_dir: MaybeBoolean) -> AnyObject {
|
144
|
-
let
|
145
|
-
let
|
136
|
+
pub fn pn_children(pth: MaybeString, with_dir: MaybeBoolean) -> Result<AnyObject, Exception> {
|
137
|
+
let path = pth.unwrap_or(RString::new("."));
|
138
|
+
let path = path.to_str();
|
146
139
|
|
147
|
-
if let Ok(entries) = fs::read_dir(
|
148
|
-
let mut with_directory = with_dir.
|
149
|
-
if
|
140
|
+
if let Ok(entries) = fs::read_dir(path) {
|
141
|
+
let mut with_directory = with_dir.unwrap_or(Boolean::new(true)).to_bool();
|
142
|
+
if path == "." {
|
150
143
|
with_directory = false;
|
151
144
|
}
|
152
145
|
|
153
|
-
let mut arr = Array::
|
146
|
+
let mut arr = Array::with_capacity(entries.size_hint().1.unwrap_or(0));
|
154
147
|
for entry in entries {
|
155
148
|
if with_directory {
|
156
149
|
match entry {
|
@@ -165,25 +158,23 @@ pub fn pn_children(pth: MaybeString, with_dir: MaybeBoolean) -> AnyObject {
|
|
165
158
|
}
|
166
159
|
}
|
167
160
|
|
168
|
-
arr.to_any_object()
|
161
|
+
Ok(arr.to_any_object())
|
169
162
|
} else {
|
170
|
-
|
171
|
-
|
172
|
-
NilClass::new().to_any_object()
|
163
|
+
let msg = format!("No such file or directory @ dir_initialize - {}", path);
|
164
|
+
Err(Exception::new("Errno::NOENT", Some(&msg)))
|
173
165
|
}
|
174
166
|
}
|
175
167
|
|
176
|
-
pub fn pn_children_compat(pth: MaybeString, with_dir: MaybeBoolean) -> AnyObject {
|
177
|
-
let
|
178
|
-
let val = val.to_str();
|
168
|
+
pub fn pn_children_compat(pth: MaybeString, with_dir: MaybeBoolean) -> Result<AnyObject, Exception> {
|
169
|
+
let path = to_str(&pth);
|
179
170
|
|
180
|
-
if let Ok(entries) = fs::read_dir(
|
181
|
-
let mut with_directory = with_dir.
|
182
|
-
if
|
171
|
+
if let Ok(entries) = fs::read_dir(path) {
|
172
|
+
let mut with_directory = with_dir.unwrap_or(Boolean::new(true)).to_bool();
|
173
|
+
if path == "." {
|
183
174
|
with_directory = false;
|
184
175
|
}
|
185
176
|
|
186
|
-
let mut arr = Array::
|
177
|
+
let mut arr = Array::with_capacity(entries.size_hint().1.unwrap_or(0));
|
187
178
|
for entry in entries {
|
188
179
|
if with_directory {
|
189
180
|
if let Ok(v) = entry {
|
@@ -196,82 +187,60 @@ pub fn pn_children_compat(pth: MaybeString, with_dir: MaybeBoolean) -> AnyObject
|
|
196
187
|
}
|
197
188
|
}
|
198
189
|
|
199
|
-
arr.to_any_object()
|
190
|
+
Ok(arr.to_any_object())
|
200
191
|
} else {
|
201
|
-
|
202
|
-
|
203
|
-
NilClass::new().to_any_object()
|
192
|
+
let msg = format!("No such file or directory @ dir_initialize - {}", path);
|
193
|
+
Err(Exception::new("Errno::NOENT", Some(&msg)))
|
204
194
|
}
|
205
195
|
}
|
206
196
|
|
207
|
-
pub fn pn_chop_basename(pth: MaybeString) ->
|
208
|
-
|
209
|
-
let pth = pth.ok().unwrap_or(RString::new(""));
|
210
|
-
let results = chop_basename::chop_basename(pth.to_str());
|
211
|
-
match results {
|
197
|
+
pub fn pn_chop_basename(pth: MaybeString) -> AnyObject {
|
198
|
+
match chop_basename::chop_basename(to_str(&pth)) {
|
212
199
|
Some((dirname, basename)) => {
|
213
|
-
arr
|
214
|
-
arr.push(RString::new(&
|
215
|
-
arr
|
200
|
+
let mut arr = Array::with_capacity(2);
|
201
|
+
arr.push(RString::new(&dirname));
|
202
|
+
arr.push(RString::new(&basename));
|
203
|
+
arr.to_any_object()
|
216
204
|
},
|
217
|
-
None =>
|
205
|
+
None => NilClass::new().to_any_object()
|
218
206
|
}
|
219
207
|
}
|
220
208
|
|
221
209
|
// pub fn pn_cleanpath(pth: MaybeString){}
|
222
210
|
|
223
211
|
pub fn pn_cleanpath_aggressive(pth: MaybeString) -> RString {
|
224
|
-
|
225
|
-
pth.ok().unwrap_or(RString::new("")).to_str()
|
226
|
-
);
|
227
|
-
|
228
|
-
RString::new(&path)
|
212
|
+
RString::new(&cleanpath_aggressive::cleanpath_aggressive(to_str(&pth)))
|
229
213
|
}
|
230
214
|
|
231
215
|
pub fn pn_cleanpath_conservative(pth: MaybeString) -> RString {
|
232
|
-
|
233
|
-
pth.ok().unwrap_or(RString::new("")).to_str()
|
234
|
-
);
|
235
|
-
|
236
|
-
RString::new(&path)
|
216
|
+
RString::new(&cleanpath_conservative::cleanpath_conservative(to_str(&pth)))
|
237
217
|
}
|
238
218
|
|
239
219
|
pub fn pn_del_trailing_separator(pth: MaybeString) -> RString {
|
240
|
-
|
241
|
-
let path =
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
220
|
+
{
|
221
|
+
let path = to_str(&pth);
|
222
|
+
if path.is_empty() {
|
223
|
+
return RString::new("/");
|
224
|
+
}
|
225
|
+
let pos = match find_last_non_sep_pos(path.as_bytes()) {
|
226
|
+
Some(pos) => pos,
|
227
|
+
None => return RString::new("/"),
|
228
|
+
};
|
229
|
+
if pos != path.len() - 1 {
|
230
|
+
return RString::new(&path[..pos + 1]);
|
251
231
|
}
|
252
|
-
} else {
|
253
|
-
return RString::new("");
|
254
232
|
}
|
255
|
-
|
256
233
|
pth.unwrap()
|
257
234
|
}
|
258
235
|
|
259
236
|
// pub fn pn_descend(){}
|
260
237
|
|
261
238
|
pub fn pn_is_directory(pth: MaybeString) -> Boolean {
|
262
|
-
Boolean::new(
|
263
|
-
Path::new(
|
264
|
-
pth.ok().unwrap_or(RString::new("")).to_str()
|
265
|
-
).is_dir()
|
266
|
-
)
|
239
|
+
Boolean::new(Path::new(to_str(&pth)).is_dir())
|
267
240
|
}
|
268
241
|
|
269
242
|
pub fn pn_dirname(pth: MaybeString) -> RString {
|
270
|
-
RString::new(
|
271
|
-
dirname::dirname(
|
272
|
-
pth.ok().unwrap_or(RString::new("")).to_str()
|
273
|
-
)
|
274
|
-
)
|
243
|
+
RString::new(dirname::dirname(to_str(&pth)))
|
275
244
|
}
|
276
245
|
|
277
246
|
// pub fn pn_each_child(){}
|
@@ -280,60 +249,54 @@ pub fn pn_dirname(pth: MaybeString) -> RString {
|
|
280
249
|
// NilClass::new()
|
281
250
|
// }
|
282
251
|
|
283
|
-
pub fn pn_entries(pth: MaybeString) -> AnyObject {
|
284
|
-
|
285
|
-
|
252
|
+
pub fn pn_entries(pth: MaybeString) -> Result<AnyObject, Exception> {
|
253
|
+
let path = to_str(&pth);
|
254
|
+
if let Ok(files) = fs::read_dir(path) {
|
255
|
+
let mut arr = Array::with_capacity(files.size_hint().1.unwrap_or(0) + 2);
|
286
256
|
|
287
257
|
arr.push(RString::new("."));
|
288
258
|
arr.push(RString::new(".."));
|
289
259
|
|
290
260
|
for file in files {
|
291
|
-
|
292
|
-
arr.push(RString::new(&file_name_str[..]));
|
261
|
+
arr.push(RString::new(file.unwrap().file_name().to_str().unwrap()));
|
293
262
|
}
|
294
263
|
|
295
|
-
arr.to_any_object()
|
264
|
+
Ok(arr.to_any_object())
|
296
265
|
} else {
|
297
|
-
|
298
|
-
|
299
|
-
NilClass::new().to_any_object()
|
266
|
+
let msg = format!("No such file or directory @ dir_initialize - {}", path);
|
267
|
+
Err(Exception::new("Errno::NOENT", Some(&msg)))
|
300
268
|
}
|
301
269
|
}
|
302
270
|
|
303
|
-
pub fn pn_entries_compat(pth: MaybeString) -> AnyObject {
|
304
|
-
|
305
|
-
|
271
|
+
pub fn pn_entries_compat(pth: MaybeString) -> Result<AnyObject, Exception> {
|
272
|
+
let path = to_str(&pth);
|
273
|
+
if let Ok(files) = fs::read_dir(path) {
|
274
|
+
let mut arr = Array::with_capacity(files.size_hint().1.unwrap_or(0) + 2);
|
306
275
|
|
307
276
|
arr.push(Pathname::new("."));
|
308
277
|
arr.push(Pathname::new(".."));
|
309
278
|
|
310
279
|
for file in files {
|
311
|
-
|
312
|
-
arr.push(Pathname::new(&file_name_str));
|
280
|
+
arr.push(Pathname::new(file.unwrap().file_name().to_str().unwrap()));
|
313
281
|
}
|
314
282
|
|
315
|
-
arr.to_any_object()
|
283
|
+
Ok(arr.to_any_object())
|
316
284
|
} else {
|
317
|
-
|
318
|
-
|
319
|
-
NilClass::new().to_any_object()
|
285
|
+
let msg = format!("No such file or directory @ dir_initialize - {}", path);
|
286
|
+
Err(Exception::new("Errno::NOENT", Some(&msg)))
|
320
287
|
}
|
321
288
|
}
|
322
289
|
|
323
290
|
pub fn pn_extname(pth: MaybeString) -> RString {
|
324
|
-
RString::new(
|
325
|
-
extname::extname(pth.ok().unwrap_or(RString::new("")).to_str())
|
326
|
-
)
|
291
|
+
RString::new(extname::extname(to_str(&pth)))
|
327
292
|
}
|
328
293
|
|
329
294
|
// pub fn pn_find(pth: MaybeString, ignore_error: Boolean){}
|
330
295
|
|
331
296
|
pub fn pn_has_trailing_separator(pth: MaybeString) -> Boolean {
|
332
|
-
let v = pth
|
333
|
-
match chop_basename::chop_basename(v
|
334
|
-
Some((a,b)) =>
|
335
|
-
Boolean::new(a.len() + b.len() < v.to_str().len())
|
336
|
-
},
|
297
|
+
let v = to_str(&pth);
|
298
|
+
match chop_basename::chop_basename(v) {
|
299
|
+
Some((a,b)) => Boolean::new(a.len() + b.len() < v.len()),
|
337
300
|
_ => Boolean::new(false)
|
338
301
|
}
|
339
302
|
}
|
@@ -353,13 +316,13 @@ pub fn pn_join(args: MaybeArray) -> AnyObject {
|
|
353
316
|
|
354
317
|
let item = args.pop();
|
355
318
|
result = plus::plus_paths(&anyobject_to_string(item).unwrap(), &result);
|
356
|
-
if result.
|
319
|
+
if result.as_bytes().get(0) == Some(&SEP) {
|
357
320
|
return Pathname::new(&result).to_any_object()
|
358
321
|
}
|
359
322
|
|
360
323
|
qty -= 1;
|
361
324
|
}
|
362
|
-
|
325
|
+
|
363
326
|
let result = plus::plus_paths(&path_self, &result);
|
364
327
|
|
365
328
|
Pathname::new(&result).to_any_object()
|
@@ -374,23 +337,17 @@ pub fn pn_join(args: MaybeArray) -> AnyObject {
|
|
374
337
|
// pub fn pn_parent(pth: MaybeString){}
|
375
338
|
|
376
339
|
pub fn pn_plus(pth1: MaybeString, pth2: MaybeString) -> RString {
|
377
|
-
RString::new(
|
378
|
-
&plus::plus_paths(
|
379
|
-
pth1.ok().unwrap_or(RString::new("")).to_str(),
|
380
|
-
pth2.ok().unwrap_or(RString::new("")).to_str()
|
381
|
-
)[..]
|
382
|
-
)
|
340
|
+
RString::new(&plus::plus_paths(to_str(&pth1), to_str(&pth2)))
|
383
341
|
}
|
384
342
|
|
385
343
|
// pub fn pn_prepend_prefix(prefix: MaybeString, relpath: MaybeString){}
|
386
344
|
|
387
345
|
pub fn pn_is_relative(pth: MaybeString) -> Boolean {
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
)
|
346
|
+
let path = match &pth {
|
347
|
+
&Ok(ref ruru_string) => ruru_string.to_str(),
|
348
|
+
&Err(_) => return Boolean::new(false),
|
349
|
+
};
|
350
|
+
Boolean::new(path.as_bytes().get(0) != Some(&SEP))
|
394
351
|
}
|
395
352
|
|
396
353
|
// pub fn pn_root(pth: MaybeString){}
|