faster_path 0.0.6 → 0.0.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 +4 -3
- data/ext/faster_path/extconf.rb +1 -1
- data/faster_path.gemspec +1 -1
- data/lib/faster_path.rb +20 -5
- data/lib/faster_path/version.rb +1 -1
- data/src/basename.rs +15 -0
- data/src/both_are_blank.rs +14 -0
- data/src/dirname.rs +25 -0
- data/src/is_absolute.rs +12 -0
- data/src/is_blank.rs +10 -0
- data/src/is_relative.rs +12 -0
- data/src/lib.rs +20 -79
- data/src/ruby_array.rs +17 -0
- data/src/ruby_string.rs +30 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f92e6ae04b2843b4ebbe35489a57a3761e549c5a
|
4
|
+
data.tar.gz: cf6a2778380a40beae6bd75f399c8e3ba3945c57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0924b343e18fbe1444b5e1ebe8def4f7856dfe99298bd24b3ba1e5d1b2367900d6464063ba9c0b6508ea75799cee37085531d63627937e0a1b620e7002496742
|
7
|
+
data.tar.gz: 834d364fd05f66a698964e9fd9c9f71717a8026f114f04f0349fe5e6c700572e1f39d86b1083cc1b475c659605d13b708f116c2f4baf9075be3976d18b466c47
|
data/README.md
CHANGED
@@ -86,7 +86,7 @@ Current methods implemented:
|
|
86
86
|
|FasterPath Rust Implementation|Ruby 2.3.1 Implementation|Performance Improvement|
|
87
87
|
|---|---|:---:|
|
88
88
|
| `FasterPath.absolute?` | `Pathname#absolute?` | 1234.6% |
|
89
|
-
| `FasterPath.chop_basename` | `Pathname#chop_basename` |
|
89
|
+
| `FasterPath.chop_basename` | `Pathname#chop_basename` | 46.7% |
|
90
90
|
| `FasterPath.relative?` | `Pathname#relative?` | 1262.3% |
|
91
91
|
| `FasterPath.blank?` | | |
|
92
92
|
|
@@ -115,8 +115,9 @@ FasterPath.sledgehammer_everything!
|
|
115
115
|
|
116
116
|
The primary methods to target are mostly listed in the **Why** section above. You may find the Ruby
|
117
117
|
source code useful for Pathname's [Ruby source](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/ext/pathname/lib/pathname.rb),
|
118
|
-
[C source](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/ext/pathname/pathname.c),
|
119
|
-
[tests](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/test/pathname/test_pathname.rb)
|
118
|
+
[C source](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/ext/pathname/pathname.c),
|
119
|
+
[tests](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/test/pathname/test_pathname.rb),
|
120
|
+
and checkout the [documentation](http://ruby-doc.org/stdlib-2.3.1/libdoc/pathname/rdoc/Pathname.html).
|
120
121
|
|
121
122
|
Methods will be written as exclusively in Rust as possible. Even just writing a **not** in Ruby with a
|
122
123
|
Rust method like `!absolute?` _(not absolute)_ drops 39% of the performance already gained in Rust.
|
data/ext/faster_path/extconf.rb
CHANGED
data/faster_path.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "https://github.com/danielpclark/faster_path"
|
14
14
|
spec.license = "MIT OR Apache-2.0"
|
15
15
|
|
16
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets)/}) }
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets|benches)/}) }
|
17
17
|
spec.bindir = "exe"
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.extensions << "ext/faster_path/extconf.rb"
|
data/lib/faster_path.rb
CHANGED
@@ -18,17 +18,18 @@ module FasterPath
|
|
18
18
|
# to handle non-path strings.
|
19
19
|
def self.chop_basename(pth)
|
20
20
|
d,b = [Rust.dirname(pth), Rust.basename(pth)]
|
21
|
-
|
22
|
-
nil
|
23
|
-
else
|
24
|
-
[d,b]
|
25
|
-
end
|
21
|
+
[d,b] unless Rust.both_are_blank(d,b)
|
26
22
|
end
|
27
23
|
|
28
24
|
def self.blank?(str)
|
29
25
|
Rust.is_blank(str)
|
30
26
|
end
|
31
27
|
|
28
|
+
# EXAMPLE
|
29
|
+
#def self.one_and_two
|
30
|
+
# Rust.one_and_two.to_a
|
31
|
+
#end
|
32
|
+
|
32
33
|
private
|
33
34
|
module Rust
|
34
35
|
extend FFI::Library
|
@@ -36,11 +37,25 @@ module FasterPath
|
|
36
37
|
prefix = Gem.win_platform? ? "" : "lib"
|
37
38
|
"#{File.expand_path("../target/release/", File.dirname(__FILE__))}/#{prefix}faster_path.#{FFI::Platform::LIBSUFFIX}"
|
38
39
|
end
|
40
|
+
|
41
|
+
class FromRustArray < FFI::Struct
|
42
|
+
layout :len, :size_t, # dynamic array layout
|
43
|
+
:data, :pointer #
|
44
|
+
|
45
|
+
def to_a
|
46
|
+
self[:data].get_array_of_string(0, self[:len]).compact
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
39
50
|
attach_function :is_absolute, [ :string ], :bool
|
40
51
|
attach_function :is_relative, [ :string ], :bool
|
41
52
|
attach_function :is_blank, [ :string ], :bool
|
53
|
+
attach_function :both_are_blank, [ :string, :string ], :bool
|
42
54
|
attach_function :basename, [ :string ], :string
|
43
55
|
attach_function :dirname, [ :string ], :string
|
56
|
+
|
57
|
+
# EXAMPLE
|
58
|
+
#attach_function :one_and_two, [], FromRustArray.by_value
|
44
59
|
end
|
45
60
|
private_constant :Rust
|
46
61
|
end
|
data/lib/faster_path/version.rb
CHANGED
data/src/basename.rs
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#[no_mangle]
|
2
|
+
pub extern fn basename(string: *const c_char) -> *const c_char {
|
3
|
+
let c_str = unsafe {
|
4
|
+
assert!(!string.is_null());
|
5
|
+
|
6
|
+
CStr::from_ptr(string)
|
7
|
+
};
|
8
|
+
|
9
|
+
let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
|
10
|
+
|
11
|
+
let part = Path::new(r_str).file_name().unwrap_or(OsStr::new("")).to_str();
|
12
|
+
|
13
|
+
let output = CString::new(format!("{}", part.unwrap())).unwrap();
|
14
|
+
output.into_raw()
|
15
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#[no_mangle]
|
2
|
+
pub extern fn both_are_blank(s1: *const c_char, s2: *const c_char) -> bool {
|
3
|
+
let c_str1 = unsafe {
|
4
|
+
assert!(!s1.is_null());
|
5
|
+
CStr::from_ptr(s1)
|
6
|
+
};
|
7
|
+
let c_str2 = unsafe {
|
8
|
+
assert!(!s2.is_null());
|
9
|
+
CStr::from_ptr(s2)
|
10
|
+
};
|
11
|
+
|
12
|
+
str::from_utf8(c_str1.to_bytes()).unwrap().trim().is_empty() &&
|
13
|
+
str::from_utf8(c_str2.to_bytes()).unwrap().trim().is_empty()
|
14
|
+
}
|
data/src/dirname.rs
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#[no_mangle]
|
2
|
+
pub extern fn dirname(string: *const c_char) -> *const c_char {
|
3
|
+
let c_str = unsafe {
|
4
|
+
assert!(!string.is_null());
|
5
|
+
|
6
|
+
CStr::from_ptr(string)
|
7
|
+
};
|
8
|
+
|
9
|
+
let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
|
10
|
+
|
11
|
+
if r_str.is_empty() {
|
12
|
+
return string
|
13
|
+
}
|
14
|
+
|
15
|
+
let path = Path::new(r_str).parent().unwrap_or(Path::new(""));
|
16
|
+
|
17
|
+
let out_str = if !path.to_str().unwrap().is_empty() {
|
18
|
+
format!("{}{}", path.to_str().unwrap(), MAIN_SEPARATOR)
|
19
|
+
} else {
|
20
|
+
format!("{}", path.to_str().unwrap())
|
21
|
+
};
|
22
|
+
|
23
|
+
let output = CString::new(out_str).unwrap();
|
24
|
+
output.into_raw()
|
25
|
+
}
|
data/src/is_absolute.rs
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#[no_mangle]
|
2
|
+
pub extern fn is_absolute(string: *const c_char) -> bool {
|
3
|
+
let c_str = unsafe {
|
4
|
+
assert!(!string.is_null());
|
5
|
+
|
6
|
+
CStr::from_ptr(string)
|
7
|
+
};
|
8
|
+
|
9
|
+
let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
|
10
|
+
|
11
|
+
r_str.chars().next().unwrap_or("muffins".chars().next().unwrap()) == MAIN_SEPARATOR
|
12
|
+
}
|
data/src/is_blank.rs
ADDED
data/src/is_relative.rs
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#[no_mangle]
|
2
|
+
pub extern fn is_relative(string: *const c_char) -> bool {
|
3
|
+
let c_str = unsafe {
|
4
|
+
assert!(!string.is_null());
|
5
|
+
|
6
|
+
CStr::from_ptr(string)
|
7
|
+
};
|
8
|
+
|
9
|
+
let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
|
10
|
+
|
11
|
+
r_str.chars().next().unwrap_or("muffins".chars().next().unwrap()) != MAIN_SEPARATOR
|
12
|
+
}
|
data/src/lib.rs
CHANGED
@@ -10,82 +10,23 @@ use std::path::{Path,MAIN_SEPARATOR};
|
|
10
10
|
use libc::c_char;
|
11
11
|
use std::ffi::{CStr,CString,OsStr};
|
12
12
|
use std::str;
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
};
|
34
|
-
|
35
|
-
let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
|
36
|
-
|
37
|
-
r_str.chars().next().unwrap_or("muffins".chars().next().unwrap()) != MAIN_SEPARATOR
|
38
|
-
}
|
39
|
-
|
40
|
-
#[no_mangle]
|
41
|
-
pub extern fn is_blank(string: *const c_char) -> bool {
|
42
|
-
let c_str = unsafe {
|
43
|
-
assert!(!string.is_null());
|
44
|
-
|
45
|
-
CStr::from_ptr(string)
|
46
|
-
};
|
47
|
-
|
48
|
-
str::from_utf8(c_str.to_bytes()).unwrap().trim().is_empty()
|
49
|
-
}
|
50
|
-
|
51
|
-
#[no_mangle]
|
52
|
-
pub extern fn basename(string: *const c_char) -> *const c_char {
|
53
|
-
let c_str = unsafe {
|
54
|
-
assert!(!string.is_null());
|
55
|
-
|
56
|
-
CStr::from_ptr(string)
|
57
|
-
};
|
58
|
-
|
59
|
-
let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
|
60
|
-
|
61
|
-
let part = Path::new(r_str).file_name().unwrap_or(OsStr::new("")).to_str();
|
62
|
-
|
63
|
-
let output = CString::new(format!("{}", part.unwrap())).unwrap();
|
64
|
-
output.into_raw()
|
65
|
-
}
|
66
|
-
|
67
|
-
#[no_mangle]
|
68
|
-
pub extern fn dirname(string: *const c_char) -> *const c_char {
|
69
|
-
let c_str = unsafe {
|
70
|
-
assert!(!string.is_null());
|
71
|
-
|
72
|
-
CStr::from_ptr(string)
|
73
|
-
};
|
74
|
-
|
75
|
-
let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
|
76
|
-
|
77
|
-
if r_str.is_empty() {
|
78
|
-
return string
|
79
|
-
}
|
80
|
-
|
81
|
-
let path = Path::new(r_str).parent().unwrap_or(Path::new(""));
|
82
|
-
|
83
|
-
let out_str = if !path.to_str().unwrap().is_empty() {
|
84
|
-
format!("{}{}", path.to_str().unwrap(), MAIN_SEPARATOR)
|
85
|
-
} else {
|
86
|
-
format!("{}", path.to_str().unwrap())
|
87
|
-
};
|
88
|
-
|
89
|
-
let output = CString::new(out_str).unwrap();
|
90
|
-
output.into_raw()
|
91
|
-
}
|
13
|
+
use std::mem;
|
14
|
+
|
15
|
+
include!("ruby_string.rs");
|
16
|
+
include!("ruby_array.rs");
|
17
|
+
include!("is_absolute.rs");
|
18
|
+
include!("is_relative.rs");
|
19
|
+
include!("is_blank.rs");
|
20
|
+
include!("both_are_blank.rs");
|
21
|
+
include!("basename.rs");
|
22
|
+
include!("dirname.rs");
|
23
|
+
|
24
|
+
// EXAMPLE
|
25
|
+
//
|
26
|
+
//#[no_mangle]
|
27
|
+
//pub extern fn one_and_two() -> RubyArray {
|
28
|
+
// let mut words = vec![];
|
29
|
+
// words.push(RubyString::to_ruby(&"one".to_string()));
|
30
|
+
// words.push(RubyString::to_ruby(&"two".to_string()));
|
31
|
+
// RubyArray::from_vec(words)
|
32
|
+
//}
|
data/src/ruby_array.rs
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#[repr(C)]
|
2
|
+
pub struct RubyArray {
|
3
|
+
len: libc::size_t,
|
4
|
+
data: *const libc::c_void,
|
5
|
+
}
|
6
|
+
|
7
|
+
impl RubyArray {
|
8
|
+
#[allow(dead_code)]
|
9
|
+
fn from_vec<T>(vec: Vec<T>) -> RubyArray {
|
10
|
+
let array = RubyArray {
|
11
|
+
data: vec.as_ptr() as *const libc::c_void,
|
12
|
+
len: vec.len() as libc::size_t
|
13
|
+
};
|
14
|
+
mem::forget(vec);
|
15
|
+
array
|
16
|
+
}
|
17
|
+
}
|
data/src/ruby_string.rs
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
pub struct RubyString;
|
2
|
+
|
3
|
+
// Coercing strs into Strings has some loss of performance
|
4
|
+
// You may use these methods temporarily but it would be much better
|
5
|
+
// to write all of this code out in each method using just str.
|
6
|
+
//
|
7
|
+
// Using these methods you will still get you 10X (= 900%) performance
|
8
|
+
// gain regardless. But really consider not using String. If you do
|
9
|
+
// as I've intstructed the performance gains will go from 900% to 1250%.
|
10
|
+
impl RubyString {
|
11
|
+
#[allow(dead_code)]
|
12
|
+
// FOR QUICK IMPLEMENTATION. NOT FOR PRODUCTION.
|
13
|
+
// SEE BENCHMARKS FOR SANCTIONED IMPLEMENTATION.
|
14
|
+
fn from_ruby(s: *const c_char) -> String {
|
15
|
+
let c_str = unsafe {
|
16
|
+
assert!(!s.is_null());
|
17
|
+
CStr::from_ptr(s)
|
18
|
+
};
|
19
|
+
(*str::from_utf8(c_str.to_bytes()).unwrap_or("")).to_string()
|
20
|
+
}
|
21
|
+
|
22
|
+
#[allow(dead_code)]
|
23
|
+
// FOR QUICK IMPLEMENTATION. NOT FOR PRODUCTION.
|
24
|
+
// SEE BENCHMARKS FOR SANCTIONED IMPLEMENTATION.
|
25
|
+
fn to_ruby<S: Into<String>>(s: S) -> *const c_char {
|
26
|
+
let r_str = s.into();
|
27
|
+
let s_slice: &str = &r_str[..];
|
28
|
+
CString::new(s_slice).unwrap().into_raw()
|
29
|
+
}
|
30
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faster_path
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel P. Clark
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -90,7 +90,15 @@ files:
|
|
90
90
|
- lib/faster_path/optional/monkeypatches.rb
|
91
91
|
- lib/faster_path/optional/refinements.rb
|
92
92
|
- lib/faster_path/version.rb
|
93
|
+
- src/basename.rs
|
94
|
+
- src/both_are_blank.rs
|
95
|
+
- src/dirname.rs
|
96
|
+
- src/is_absolute.rs
|
97
|
+
- src/is_blank.rs
|
98
|
+
- src/is_relative.rs
|
93
99
|
- src/lib.rs
|
100
|
+
- src/ruby_array.rs
|
101
|
+
- src/ruby_string.rs
|
94
102
|
homepage: https://github.com/danielpclark/faster_path
|
95
103
|
licenses:
|
96
104
|
- MIT OR Apache-2.0
|