faster_path 0.3.7 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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){}
|