faster_path 0.0.6 → 0.0.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 +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
|