faster_path 0.1.13 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f1b4b37c294db2912d786c35de76f60cba0b6a9
4
- data.tar.gz: 46af8f1bb6c06baed02866d6f9777bb9dfb6f1ff
3
+ metadata.gz: 4b227f5a94ba3ae27a33eab04fa65c80d95b9842
4
+ data.tar.gz: 6cf955a639547780ecd12279dd50c8f00343b772
5
5
  SHA512:
6
- metadata.gz: c6d51a6c3a7796aa41063ee31a3c0f05c88df32350f5fbc2f0913553c9fdaf6ab5600475594d3e9dc3706df49785f5bfc0e0ed0de4b29d169e166abd1acf4f45
7
- data.tar.gz: 96b16a98d9e807e33669956d6adb879f57d5e976def60c2d11502b9107a601bf793cfe75148f56e2e6c99b3b3af7745434e5c166d40c1b902b911efd797a0b65
6
+ metadata.gz: 2571373e3f523f8db360b7b68593d192b10b4e718ba8f12cdc47292479c9e6facb74498d799dca7121aa4e895a7d2088b8d921855bd6857a3c9f1c7512617fcb
7
+ data.tar.gz: 3e2c243a5921e93c3e0f47e028aa2e7b10cbdf5eb304830093e869a6abca1159b6b86dc627516c548e404b5ce738ecbc8fd2f5a5b5e48ef802d8e20a7c392d34
data/Cargo.lock CHANGED
@@ -3,7 +3,7 @@ name = "faster_path"
3
3
  version = "0.0.1"
4
4
  dependencies = [
5
5
  "array_tool 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
6
- "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
6
+ "ruru 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
7
7
  ]
8
8
 
9
9
  [[package]]
@@ -11,11 +11,36 @@ name = "array_tool"
11
11
  version = "0.4.1"
12
12
  source = "registry+https://github.com/rust-lang/crates.io-index"
13
13
 
14
+ [[package]]
15
+ name = "lazy_static"
16
+ version = "0.2.8"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+
14
19
  [[package]]
15
20
  name = "libc"
16
21
  version = "0.2.30"
17
22
  source = "registry+https://github.com/rust-lang/crates.io-index"
18
23
 
24
+ [[package]]
25
+ name = "ruby-sys"
26
+ version = "0.2.20"
27
+ source = "registry+https://github.com/rust-lang/crates.io-index"
28
+ dependencies = [
29
+ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
30
+ ]
31
+
32
+ [[package]]
33
+ name = "ruru"
34
+ version = "0.9.3"
35
+ source = "registry+https://github.com/rust-lang/crates.io-index"
36
+ dependencies = [
37
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
38
+ "ruby-sys 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
39
+ ]
40
+
19
41
  [metadata]
20
42
  "checksum array_tool 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a07ccb27c611e5cda99e498e99ba71b3ecdb7db5df02096cef42a3df5b84542"
43
+ "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
21
44
  "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915"
45
+ "checksum ruby-sys 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e71509f17ce93733dc196258e168b58050490a156b04563816a8120a74ba04c7"
46
+ "checksum ruru 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6486d6c50b7a08246a492a61893635c1977d41c138041d443eb603f6298e0273"
data/Cargo.toml CHANGED
@@ -13,5 +13,5 @@ name = "faster_path"
13
13
  crate-type = ["dylib"]
14
14
 
15
15
  [dependencies]
16
- libc = "0.2.30"
16
+ ruru = "0.9.3"
17
17
  array_tool = "0.4.1"
data/Rakefile CHANGED
@@ -24,8 +24,38 @@ task :sysinfo do
24
24
  end
25
25
  end
26
26
 
27
+ desc "Add libruby to deps"
28
+ task :libruby_release do
29
+ filename = RbConfig::CONFIG["LIBRUBY_ALIASES"].split(" ").first
30
+ libfile = File.join(RbConfig::CONFIG["libdir"], filename)
31
+ deps = "target/release/deps"
32
+
33
+ printf "Copying libruby.so ... "
34
+ unless File.exist? "#{deps}/#{filename}"
35
+ FileUtils.mkdir_p deps
36
+ FileUtils.cp libfile, deps
37
+ end
38
+ exit 1 unless File.exist? "#{deps}/#{filename}"
39
+ puts "libruby.so copied."
40
+ end
41
+
42
+ desc "Add libruby to debug deps"
43
+ task :libruby_debug do
44
+ filename = RbConfig::CONFIG["LIBRUBY_ALIASES"].split(" ").first
45
+ libfile = File.join(RbConfig::CONFIG["libdir"], filename)
46
+ deps = "target/debug/deps"
47
+
48
+ printf "Copying libruby.so ... "
49
+ unless File.exist? "#{deps}/#{filename}"
50
+ FileUtils.mkdir_p deps
51
+ FileUtils.cp libfile, deps
52
+ end
53
+ exit 1 unless File.exist? "#{deps}/#{filename}"
54
+ puts "libruby.so copied."
55
+ end
56
+
27
57
  desc "Build Rust extension"
28
- task :build_src do
58
+ task build_src: :libruby_release do
29
59
  puts "Building extension..."
30
60
  sh "cargo build --release"
31
61
  end
@@ -58,7 +88,7 @@ task :lint do
58
88
  end
59
89
 
60
90
  desc "Run Rust Tests"
61
- task :cargo do
91
+ task cargo: :libruby_debug do
62
92
  sh "cargo test -- --nocapture"
63
93
  end
64
94
 
@@ -4,6 +4,26 @@ require "ffi"
4
4
  require 'faster_path/asset_resolution'
5
5
 
6
6
  module FasterPath
7
+ FFI_LIBRARY = begin
8
+ prefix = Gem.win_platform? ? "" : "lib"
9
+ "#{File.expand_path("../target/release/", __dir__)}/#{prefix}faster_path.#{FFI::Platform::LIBSUFFIX}"
10
+ end
11
+ require 'fiddle'
12
+ library = Fiddle.dlopen(FFI_LIBRARY)
13
+ Fiddle::Function.
14
+ new(library['Init_faster_pathname'], [], Fiddle::TYPE_VOIDP).
15
+ call
16
+
17
+ FasterPathname.class_eval do
18
+ private :add_trailing_separator
19
+ private :basename
20
+ private :chop_basename
21
+ private :dirname
22
+ private :entries
23
+ private :extname
24
+ private :plus
25
+ end
26
+
7
27
  def self.rust_arch_bits
8
28
  Rust.rust_arch_bits
9
29
  end
@@ -12,102 +32,60 @@ module FasterPath
12
32
  1.size * 8
13
33
  end
14
34
 
15
- # Spec to Pathname#absolute?
16
35
  def self.absolute?(pth)
17
- Rust.is_absolute(pth)
36
+ FasterPathname.allocate.send(:absolute?, pth)
18
37
  end
19
38
 
20
- # Spec to Pathname#directory?
21
- def self.directory?(pth)
22
- Rust.is_directory(pth)
39
+ def self.add_trailing_separator(pth)
40
+ FasterPathname.allocate.send(:add_trailing_separator, pth)
23
41
  end
24
42
 
25
- # Spec to Pathname#relative?
26
- def self.relative?(pth)
27
- Rust.is_relative(pth)
43
+ def self.blank?(str)
44
+ "#{str}".strip.empty?
28
45
  end
29
46
 
30
- def self.dirname(pth)
31
- Rust.dirname(pth)
47
+ def self.basename(pth, ext="")
48
+ FasterPathname.allocate.send(:basename, pth, ext)
32
49
  end
33
50
 
34
- # Spec to Pathname#chop_basename
35
- # WARNING! Pathname#chop_basename in STDLIB doesn't handle blank strings correctly!
36
- # This implementation correctly handles blank strings just as Pathname had intended
37
- # to handle non-path strings.
38
51
  def self.chop_basename(pth)
39
- d = Rust.dirname_for_chop(pth)
40
- b = Rust.basename_for_chop(pth)
41
- [d, b] unless Rust.both_are_blank(d, b)
52
+ result = FasterPathname.allocate.send(:chop_basename, pth)
53
+ result unless result.empty?
42
54
  end
43
55
 
44
- def self.blank?(str)
45
- Rust.is_blank(str)
56
+ def self.directory?(pth)
57
+ FasterPathname.allocate.send(:directory?, pth)
46
58
  end
47
59
 
48
- def self.basename(pth, ext="")
49
- Rust.basename(pth, ext)
60
+ def self.dirname(pth)
61
+ FasterPathname.allocate.send(:dirname, pth)
50
62
  end
51
63
 
52
- def self.plus(pth, pth2)
53
- Rust.plus(pth, pth2)
64
+ def self.entries(pth)
65
+ FasterPathname.allocate.send(:entries, pth)
54
66
  end
55
67
 
56
- def self.add_trailing_separator(pth)
57
- Rust.add_trailing_separator(pth)
68
+ def self.extname(pth)
69
+ FasterPathname.allocate.send(:extname, pth)
58
70
  end
59
71
 
60
72
  def self.has_trailing_separator?(pth)
61
- Rust.has_trailing_separator(pth)
73
+ FasterPathname.allocate.send(:has_trailing_separator?, pth)
62
74
  end
63
75
 
64
- def self.extname(pth)
65
- Rust.extname(pth)
76
+ def self.plus(pth, pth2)
77
+ FasterPathname.allocate.send(:plus, pth, pth2)
66
78
  end
67
79
 
68
- def self.entries(pth)
69
- Array(Rust.entries(pth))
80
+ def self.relative?(pth)
81
+ FasterPathname.allocate.send(:relative?, pth)
70
82
  end
71
83
 
72
- # EXAMPLE
73
- # def self.one_and_two
74
- # Rust.one_and_two.to_a
75
- # end
76
-
77
84
  module Rust
78
85
  extend FFI::Library
79
- ffi_lib begin
80
- prefix = Gem.win_platform? ? "" : "lib"
81
- "#{File.expand_path("../target/release/", __dir__)}/#{prefix}faster_path.#{FFI::Platform::LIBSUFFIX}"
82
- end
83
-
84
- class FromRustArray < FFI::Struct
85
- layout :len, :size_t, # dynamic array layout
86
- :data, :pointer #
87
-
88
- def to_a
89
- self[:data].get_array_of_string(0, self[:len]).compact
90
- end
91
- end
86
+ ffi_lib ::FasterPath::FFI_LIBRARY
92
87
 
93
88
  attach_function :rust_arch_bits, [], :int32
94
- attach_function :is_absolute, [ :string ], :bool
95
- attach_function :is_directory, [ :string ], :bool
96
- attach_function :is_relative, [ :string ], :bool
97
- attach_function :is_blank, [ :string ], :bool
98
- attach_function :both_are_blank, [ :string, :string ], :bool
99
- attach_function :basename, [ :string, :string ], :string
100
- attach_function :plus, [ :string, :string ], :string
101
- attach_function :dirname, [ :string ], :string
102
- attach_function :basename_for_chop, [ :string ], :string # decoupling behavior
103
- attach_function :dirname_for_chop, [ :string ], :string # decoupling behavior
104
- attach_function :add_trailing_separator, [ :string ], :string
105
- attach_function :has_trailing_separator, [ :string ], :bool
106
- attach_function :extname, [ :string ], :string
107
- attach_function :entries, [ :string ], FromRustArray.by_value
108
-
109
- # EXAMPLE
110
- # attach_function :one_and_two, [], FromRustArray.by_value
111
89
  end
112
90
  private_constant :Rust
113
91
  end
@@ -3,11 +3,12 @@ require 'pathname'
3
3
  module FasterPath
4
4
  module MonkeyPatches
5
5
  # rubocop:disable Metrics/CyclomaticComplexity
6
+ # rubocop:disable Metrics/PerceivedComplexity
6
7
  def self._ruby_core_file!
7
8
  ::File.class_eval do
8
9
  def self.basename(pth, ext = '')
9
10
  pth = pth.to_path if pth.respond_to? :to_path
10
- raise TypeError unless pth.is_a? String
11
+ raise TypeError unless pth.is_a?(String) && ext.is_a?(String)
11
12
  FasterPath.basename(pth, ext)
12
13
  end
13
14
 
@@ -5,7 +5,7 @@ module FasterPath
5
5
  refine File do
6
6
  def self.basename(pth, ext = '')
7
7
  pth = pth.to_path if pth.respond_to? :to_path
8
- raise TypeError unless pth.is_a? String
8
+ raise TypeError unless pth.is_a?(String) && ext.is_a?(String)
9
9
  FasterPath.basename(pth, ext)
10
10
  end
11
11
 
@@ -1,3 +1,3 @@
1
1
  module FasterPath
2
- VERSION = "0.1.13"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,41 +1,23 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr, CString};
1
+ extern crate array_tool;
2
+ use path_parsing::extract_last_path_segment;
3
+ use self::array_tool::string::Squeeze;
3
4
 
4
- #[no_mangle]
5
- pub extern "C" fn basename(c_pth: *const c_char, c_ext: *const c_char) -> *const c_char {
6
- if c_pth.is_null() || c_ext.is_null() {
7
- return c_pth;
5
+ pub fn basename(pth: &str, ext: &str) -> String {
6
+ // Known edge case
7
+ match &pth.squeeze("/")[..] {
8
+ "/" => { return "/".to_string() }
9
+ _ => {}
8
10
  }
9
- let pth = unsafe { CStr::from_ptr(c_pth) }.to_str().unwrap();
10
- let ext = unsafe { CStr::from_ptr(c_ext) }.to_str().unwrap();
11
11
 
12
- let name = rust::basename(pth, ext);
13
-
14
- CString::new(name).unwrap().into_raw()
15
- }
16
-
17
- pub mod rust {
18
- extern crate array_tool;
19
- use path_parsing::extract_last_path_segment;
20
- use self::array_tool::string::Squeeze;
12
+ let mut name = extract_last_path_segment(pth);
21
13
 
22
- pub fn basename(pth: &str, ext: &str) -> String {
23
- // Known edge case
24
- match &pth.squeeze("/")[..] {
25
- "/" => { return "/".to_string() }
26
- _ => {}
14
+ if ext == ".*" {
15
+ if let Some(dot_i) = name.rfind('.') {
16
+ name = &name[0..dot_i];
27
17
  }
28
-
29
- let mut name = extract_last_path_segment(pth);
30
-
31
- if ext == ".*" {
32
- if let Some(dot_i) = name.rfind('.') {
33
- name = &name[0..dot_i];
34
- }
35
- } else if name.ends_with(ext) {
36
- name = &name[..name.len() - ext.len()];
37
- };
38
- name.to_string()
39
- }
18
+ } else if name.ends_with(ext) {
19
+ name = &name[..name.len() - ext.len()];
20
+ };
21
+ name.to_string()
40
22
  }
41
23
 
@@ -1,56 +1,54 @@
1
- pub mod rust {
2
- use std::path::MAIN_SEPARATOR;
3
- use std::str;
1
+ use std::path::MAIN_SEPARATOR;
2
+ use std::str;
4
3
 
5
- pub fn chop_basename(input: &str) -> Option<(String,String)> {
6
- if input.is_empty() {
7
- return None;
8
- }
4
+ pub fn chop_basename(input: &str) -> Option<(String,String)> {
5
+ if input.is_empty() {
6
+ return None;
7
+ }
9
8
 
10
- let mut offset = 0;
11
- let mut trailing_slashes = input.chars().rev();
12
- loop {
13
- match trailing_slashes.next() {
14
- Some(MAIN_SEPARATOR) => { offset = offset + 1 },
15
- _ => { break },
16
- }
9
+ let mut offset = 0;
10
+ let mut trailing_slashes = input.chars().rev();
11
+ loop {
12
+ match trailing_slashes.next() {
13
+ Some(MAIN_SEPARATOR) => { offset = offset + 1 },
14
+ _ => { break },
17
15
  }
16
+ }
18
17
 
19
- let input = &input[0..input.len()-offset];
20
- let base = input.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("");
21
- let directory = &input[0..input.len()-base.len()];
22
-
23
- if directory.is_empty() && (base.is_empty() || base == "/") {
24
- return None
25
- };
18
+ let input = &input[0..input.len()-offset];
19
+ let base = input.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("");
20
+ let directory = &input[0..input.len()-base.len()];
26
21
 
27
- Some((directory.to_string(), base.to_string()))
28
- }
22
+ if directory.is_empty() && (base.is_empty() || base.chars().next().unwrap() == MAIN_SEPARATOR) {
23
+ return None
24
+ };
29
25
 
30
- #[test]
31
- fn it_chops_the_basename_and_dirname() {
32
- assert_eq!(chop_basename(&""[..]), None);
33
- assert_eq!(chop_basename(&"/"[..]), None);
34
- assert_eq!(
35
- chop_basename(&"."[..]),
36
- Some(("".to_string(), ".".to_string()))
37
- );
38
- assert_eq!(
39
- chop_basename(&"asdf/asdf"[..]),
40
- Some(("asdf/".to_string(), "asdf".to_string()))
41
- );
42
- assert_eq!(
43
- chop_basename(&"asdf.txt"[..]),
44
- Some(("".to_string(), "asdf.txt".to_string()))
45
- );
46
- assert_eq!(
47
- chop_basename(&"asdf/"[..]),
48
- Some(("".to_string(), "asdf".to_string()))
49
- );
50
- assert_eq!(
51
- chop_basename(&"/asdf/"[..]),
52
- Some(("/".to_string(), "asdf".to_string()))
53
- );
54
- }
26
+ Some((directory.to_string(), base.to_string()))
27
+ }
55
28
 
29
+ #[test]
30
+ fn it_chops_the_basename_and_dirname() {
31
+ assert_eq!(chop_basename(&""[..]), None);
32
+ assert_eq!(chop_basename(&"/"[..]), None);
33
+ assert_eq!(
34
+ chop_basename(&"."[..]),
35
+ Some(("".to_string(), ".".to_string()))
36
+ );
37
+ assert_eq!(
38
+ chop_basename(&"asdf/asdf"[..]),
39
+ Some(("asdf/".to_string(), "asdf".to_string()))
40
+ );
41
+ assert_eq!(
42
+ chop_basename(&"asdf.txt"[..]),
43
+ Some(("".to_string(), "asdf.txt".to_string()))
44
+ );
45
+ assert_eq!(
46
+ chop_basename(&"asdf/"[..]),
47
+ Some(("".to_string(), "asdf".to_string()))
48
+ );
49
+ assert_eq!(
50
+ chop_basename(&"/asdf/"[..]),
51
+ Some(("/".to_string(), "asdf".to_string()))
52
+ );
56
53
  }
54
+
@@ -1,46 +1,31 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr, CString};
1
+ use std::path::MAIN_SEPARATOR;
2
+ use path_parsing::{last_sep_i, last_non_sep_i, last_non_sep_i_before};
3
3
 
4
- #[no_mangle]
5
- pub extern "C" fn dirname(path: *const c_char) -> *const c_char {
6
- if path.is_null() {
7
- return path
4
+ pub fn dirname(path: &str) -> String {
5
+ let r_str = path;
6
+ if r_str.is_empty() {
7
+ return ".".to_string();
8
8
  }
9
- let r_str = unsafe { CStr::from_ptr(path) }.to_str().unwrap();
10
-
11
- CString::new(rust::dirname(r_str)).unwrap().into_raw()
12
- }
13
-
14
- pub mod rust {
15
- use std::path::MAIN_SEPARATOR;
16
- use path_parsing::{last_sep_i, last_non_sep_i, last_non_sep_i_before};
17
-
18
- pub fn dirname(path: &str) -> String {
19
- let r_str = path;
20
- if r_str.is_empty() {
21
- return ".".to_string();
22
- }
23
- let non_sep_i = last_non_sep_i(r_str);
24
- if non_sep_i == -1 {
25
- return MAIN_SEPARATOR.to_string();
26
- }
27
- let sep_i = last_sep_i(r_str, non_sep_i);
28
- if sep_i == -1 {
29
- return ".".to_string();
30
- }
31
- if sep_i == 0 {
32
- return MAIN_SEPARATOR.to_string();
33
- }
34
- let non_sep_i2 = last_non_sep_i_before(r_str, sep_i);
35
- if non_sep_i2 != -1 {
36
- return r_str[..(non_sep_i2 + 1) as usize].to_string();
37
- } else {
38
- return MAIN_SEPARATOR.to_string();
39
- }
9
+ let non_sep_i = last_non_sep_i(r_str);
10
+ if non_sep_i == -1 {
11
+ return MAIN_SEPARATOR.to_string();
12
+ }
13
+ let sep_i = last_sep_i(r_str, non_sep_i);
14
+ if sep_i == -1 {
15
+ return ".".to_string();
16
+ }
17
+ if sep_i == 0 {
18
+ return MAIN_SEPARATOR.to_string();
19
+ }
20
+ let non_sep_i2 = last_non_sep_i_before(r_str, sep_i);
21
+ if non_sep_i2 != -1 {
22
+ return r_str[..(non_sep_i2 + 1) as usize].to_string();
23
+ } else {
24
+ return MAIN_SEPARATOR.to_string();
40
25
  }
41
26
  }
42
27
 
43
28
  #[test]
44
29
  fn returns_dot_for_empty_string(){
45
- assert_eq!(rust::dirname(""), ".".to_string());
30
+ assert_eq!(dirname(""), ".".to_string());
46
31
  }
@@ -1,20 +1,13 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr, CString};
3
1
  use path_parsing::extract_last_path_segment;
4
2
 
5
- #[no_mangle]
6
- pub extern "C" fn extname(c_pth: *const c_char) -> *const c_char {
7
- if c_pth.is_null() {
8
- return c_pth
9
- }
10
-
11
- let name = extract_last_path_segment(unsafe { CStr::from_ptr(c_pth) }.to_str().unwrap());
3
+ pub fn extname(pth: &str) -> String {
4
+ let name = extract_last_path_segment(pth);
12
5
 
13
6
  if let Some(dot_i) = name.rfind('.') {
14
7
  if dot_i > 0 && dot_i < name.len() - 1 && name[..dot_i].chars().rev().next().unwrap() != '.' {
15
- return CString::new(&name[dot_i..]).unwrap().into_raw()
8
+ return String::from(&name[dot_i..])
16
9
  }
17
10
  }
18
11
 
19
- CString::new("").unwrap().into_raw()
12
+ String::from("")
20
13
  }
data/src/lib.rs CHANGED
@@ -4,34 +4,140 @@
4
4
  // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5
5
  // http://opensource.org/licenses/MIT>, at your option. This file may not be
6
6
  // copied, modified, or distributed except according to those terms.
7
- extern crate libc;
8
-
9
- pub mod ruby_string;
10
- pub mod ruby_array;
11
- pub mod is_absolute;
12
- pub mod is_directory;
13
- pub mod is_relative;
14
- pub mod is_blank;
15
- pub mod both_are_blank;
16
- pub mod basename;
17
- pub mod plus;
18
- pub mod dirname;
19
- pub mod chop_basename;
20
- pub mod basename_for_chop;
21
- pub mod dirname_for_chop;
22
- pub mod add_trailing_separator;
23
- pub mod has_trailing_separator;
24
- pub mod extname;
25
- pub mod entries;
7
+ #[macro_use]
8
+ extern crate ruru;
9
+
10
+ class!(FasterPathname);
11
+
12
+ mod basename;
13
+ mod chop_basename;
14
+ mod dirname;
15
+ mod extname;
16
+ mod plus;
26
17
  pub mod rust_arch_bits;
27
18
  mod path_parsing;
28
19
 
29
- // EXAMPLE
30
- //
31
- //#[no_mangle]
32
- //pub extern fn one_and_two() -> RubyArray {
33
- // let mut words = vec![];
34
- // words.push(RubyString::to_ruby(&"one".to_string()));
35
- // words.push(RubyString::to_ruby(&"two".to_string()));
36
- // RubyArray::from_vec(words)
37
- //}
20
+ use ruru::{Class, Object, RString, Boolean, Array};
21
+ use std::path::{MAIN_SEPARATOR,Path};
22
+ use std::fs;
23
+
24
+ methods!(
25
+ FasterPathname,
26
+ _itself,
27
+
28
+ fn r_add_trailing_separator(pth: RString) -> RString {
29
+ let p = pth.ok().unwrap();
30
+ let x = format!("{}{}", p.to_str(), "a");
31
+ match x.rsplit_terminator(MAIN_SEPARATOR).next() {
32
+ Some("a") => p,
33
+ _ => RString::new(format!("{}{}", p.to_str(), MAIN_SEPARATOR).as_str())
34
+ }
35
+ }
36
+
37
+ fn r_is_absolute(pth: RString) -> Boolean {
38
+ Boolean::new(match pth.ok().unwrap_or(RString::new("")).to_str().chars().next() {
39
+ Some(c) => c == MAIN_SEPARATOR,
40
+ None => false
41
+ })
42
+ }
43
+
44
+ fn r_basename(pth: RString, ext: RString) -> RString {
45
+ RString::new(
46
+ &basename::basename(
47
+ pth.ok().unwrap_or(RString::new("")).to_str(),
48
+ ext.ok().unwrap_or(RString::new("")).to_str()
49
+ )[..]
50
+ )
51
+ }
52
+
53
+ fn r_chop_basename(pth: RString) -> Array {
54
+ let mut arr = Array::with_capacity(2);
55
+ let results = chop_basename::chop_basename(pth.ok().unwrap_or(RString::new("")).to_str());
56
+ match results {
57
+ Some((dirname, basename)) => {
58
+ arr.push(RString::new(&dirname[..]));
59
+ arr.push(RString::new(&basename[..]));
60
+ arr
61
+ },
62
+ None => arr
63
+ }
64
+ }
65
+
66
+ fn r_is_directory(pth: RString) -> Boolean {
67
+ Boolean::new(
68
+ Path::new(
69
+ pth.ok().unwrap_or(RString::new("")).to_str()
70
+ ).is_dir()
71
+ )
72
+ }
73
+
74
+ fn r_dirname(pth: RString) -> RString {
75
+ RString::new(
76
+ &dirname::dirname(
77
+ pth.ok().unwrap_or(RString::new("")).to_str()
78
+ )[..]
79
+ )
80
+ }
81
+
82
+ fn r_entries(pth: RString) -> Array {
83
+ let files = fs::read_dir(pth.ok().unwrap_or(RString::new("")).to_str()).unwrap();
84
+ let mut arr = Array::new();
85
+
86
+ arr.push(RString::new("."));
87
+ arr.push(RString::new(".."));
88
+
89
+ for file in files {
90
+ let file_name_str = file.unwrap().file_name().into_string().unwrap();
91
+ arr.push(RString::new(&file_name_str[..]));
92
+ }
93
+
94
+ arr
95
+ }
96
+
97
+ fn r_extname(pth: RString) -> RString {
98
+ RString::new(
99
+ &extname::extname(pth.ok().unwrap_or(RString::new("")).to_str())[..]
100
+ )
101
+ }
102
+
103
+ fn r_has_trailing_separator(pth: RString) -> Boolean {
104
+ let v = pth.ok().unwrap_or(RString::new(""));
105
+ match chop_basename::chop_basename(v.to_str()) {
106
+ Some((a,b)) => {
107
+ Boolean::new(a.len() + b.len() < v.to_str().len())
108
+ },
109
+ _ => Boolean::new(false)
110
+ }
111
+ }
112
+
113
+ fn r_plus(pth1: RString, pth2: RString) -> RString {
114
+ RString::new(&plus::plus_paths(pth1.ok().unwrap().to_str(), pth2.ok().unwrap().to_str())[..])
115
+ }
116
+
117
+ fn r_is_relative(pth: RString) -> Boolean {
118
+ Boolean::new(
119
+ match pth.ok().unwrap_or(RString::new(&MAIN_SEPARATOR.to_string()[..])).to_str().chars().next() {
120
+ Some(c) => c != MAIN_SEPARATOR,
121
+ None => true
122
+ }
123
+ )
124
+ }
125
+ );
126
+
127
+ #[allow(non_snake_case)]
128
+ #[no_mangle]
129
+ pub extern "C" fn Init_faster_pathname(){
130
+ Class::new("FasterPathname", None).define(|itself| {
131
+ itself.def("absolute?", r_is_absolute);
132
+ itself.def("add_trailing_separator", r_add_trailing_separator);
133
+ itself.def("basename", r_basename);
134
+ itself.def("chop_basename", r_chop_basename);
135
+ itself.def("directory?", r_is_directory);
136
+ itself.def("dirname", r_dirname);
137
+ itself.def("entries", r_entries);
138
+ itself.def("extname", r_extname);
139
+ itself.def("has_trailing_separator?", r_has_trailing_separator);
140
+ itself.def("plus", r_plus);
141
+ itself.def("relative?", r_is_relative);
142
+ });
143
+ }
@@ -1,40 +1,13 @@
1
1
  extern crate array_tool;
2
2
  use std::path::Path;
3
- use libc::c_char;
4
- use std::ffi::{CStr,CString};
5
3
  use std::str;
6
- use chop_basename::rust::chop_basename;
7
- use basename::rust::basename;
8
- use dirname::rust::dirname;
4
+ use chop_basename::chop_basename;
5
+ use basename::basename;
6
+ use dirname::dirname;
9
7
  use self::array_tool::vec::Shift;
10
8
  use std::ops::Index;
11
9
 
12
- #[no_mangle]
13
- pub extern fn plus(string: *const c_char, string2: *const c_char) -> *const c_char {
14
- let c_str = unsafe {
15
- if string.is_null() {
16
- return string;
17
- }
18
- CStr::from_ptr(string)
19
- };
20
-
21
- let c_str2 = unsafe {
22
- if string2.is_null() {
23
- return string2;
24
- }
25
- CStr::from_ptr(string2)
26
- };
27
-
28
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
29
- let r_str2 = str::from_utf8(c_str2.to_bytes()).unwrap();
30
-
31
- let result = plus_paths(r_str, r_str2);
32
-
33
- let output = CString::new(result).unwrap();
34
- output.into_raw()
35
- }
36
-
37
- fn plus_paths(path1: &str, path2: &str) -> String {
10
+ pub fn plus_paths(path1: &str, path2: &str) -> String {
38
11
  let mut prefix2 = path2.to_string();
39
12
  let mut index_list2: Vec<usize> = vec![];
40
13
  let mut basename_list2: Vec<String> = vec![];
@@ -1,5 +1,5 @@
1
1
  #[no_mangle]
2
- pub extern fn rust_arch_bits() -> i32 {
2
+ pub extern "C" fn rust_arch_bits() -> i32 {
3
3
  use std::mem::size_of;
4
4
  let s = size_of::<usize>() * 8;
5
5
  s as i32
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.1.13
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel P. Clark
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-08 00:00:00.000000000 Z
11
+ date: 2017-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -173,25 +173,13 @@ files:
173
173
  - lib/faster_path/optional/monkeypatches.rb
174
174
  - lib/faster_path/optional/refinements.rb
175
175
  - lib/faster_path/version.rb
176
- - src/add_trailing_separator.rs
177
176
  - src/basename.rs
178
- - src/basename_for_chop.rs
179
- - src/both_are_blank.rs
180
177
  - src/chop_basename.rs
181
178
  - src/dirname.rs
182
- - src/dirname_for_chop.rs
183
- - src/entries.rs
184
179
  - src/extname.rs
185
- - src/has_trailing_separator.rs
186
- - src/is_absolute.rs
187
- - src/is_blank.rs
188
- - src/is_directory.rs
189
- - src/is_relative.rs
190
180
  - src/lib.rs
191
181
  - src/path_parsing.rs
192
182
  - src/plus.rs
193
- - src/ruby_array.rs
194
- - src/ruby_string.rs
195
183
  - src/rust_arch_bits.rs
196
184
  homepage: https://github.com/danielpclark/faster_path
197
185
  licenses:
@@ -1,29 +0,0 @@
1
- use std::path::{Path, MAIN_SEPARATOR};
2
- use libc::c_char;
3
- use std::ffi::{CStr, CString};
4
- use std::str;
5
-
6
- #[no_mangle]
7
- pub extern fn add_trailing_separator(string: *const c_char) -> *const c_char {
8
- let c_str = unsafe {
9
- if string.is_null() {
10
- return string;
11
- }
12
- CStr::from_ptr(string)
13
- };
14
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
15
-
16
- if r_str.is_empty() {
17
- return string;
18
- }
19
-
20
- let path = Path::new(r_str);
21
- let out_str = if !(path.to_str().unwrap().chars().last().unwrap() == '/') {
22
- format!("{}{}", path.to_str().unwrap(), MAIN_SEPARATOR)
23
- } else {
24
- path.to_str().unwrap().to_string()
25
- };
26
-
27
- let output = CString::new(out_str).unwrap();
28
- output.into_raw()
29
- }
@@ -1,31 +0,0 @@
1
- use std::path::MAIN_SEPARATOR;
2
- use libc::c_char;
3
- use std::ffi::{CStr,CString};
4
- use std::str;
5
-
6
- #[no_mangle]
7
- pub extern fn basename_for_chop(string: *const c_char) -> *const c_char {
8
- let c_str = unsafe {
9
- if string.is_null() {
10
- return string;
11
- }
12
- CStr::from_ptr(string)
13
- };
14
-
15
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
16
-
17
- let mut offset = 0;
18
- let mut trailing_slashes = r_str.chars().rev();
19
- loop {
20
- match trailing_slashes.next() {
21
- Some(MAIN_SEPARATOR) => { offset = offset + 1 },
22
- _ => { break },
23
- }
24
- }
25
-
26
- let r_str = &r_str[0..r_str.len()-offset];
27
- let part = r_str.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("");
28
-
29
- let output = CString::new(part).unwrap();
30
- output.into_raw()
31
- }
@@ -1,22 +0,0 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr};
3
- use std::str;
4
-
5
- #[no_mangle]
6
- pub extern fn both_are_blank(s1: *const c_char, s2: *const c_char) -> bool {
7
- let c_str1 = unsafe {
8
- if s1.is_null() {
9
- return true;
10
- }
11
- CStr::from_ptr(s1)
12
- };
13
- let c_str2 = unsafe {
14
- if s2.is_null() {
15
- return true;
16
- }
17
- CStr::from_ptr(s2)
18
- };
19
-
20
- str::from_utf8(c_str1.to_bytes()).unwrap().trim().is_empty() &&
21
- str::from_utf8(c_str2.to_bytes()).unwrap().trim().is_empty()
22
- }
@@ -1,36 +0,0 @@
1
- use std::path::MAIN_SEPARATOR;
2
- use libc::c_char;
3
- use std::ffi::{CStr,CString};
4
- use std::str;
5
-
6
- #[no_mangle]
7
- pub extern fn dirname_for_chop(string: *const c_char) -> *const c_char {
8
- let c_str = unsafe {
9
- if string.is_null() {
10
- return string
11
- }
12
- CStr::from_ptr(string)
13
- };
14
-
15
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
16
-
17
- if r_str.is_empty() {
18
- return string
19
- }
20
-
21
- let mut offset = 0;
22
- let mut trailing_slashes = r_str.chars().rev();
23
- loop {
24
- match trailing_slashes.next() {
25
- Some(MAIN_SEPARATOR) => { offset = offset + 1 },
26
- _ => { break },
27
- }
28
- }
29
-
30
- let r_str = &r_str[0..r_str.len()-offset];
31
-
32
- let base = r_str.rsplit_terminator(MAIN_SEPARATOR).nth(0).unwrap_or("");
33
-
34
- let output = CString::new(&r_str[0..r_str.len()-base.len()]).unwrap();
35
- output.into_raw()
36
- }
@@ -1,30 +0,0 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr,CString};
3
- use std::str;
4
- use std::fs;
5
- use ruby_array::RubyArray;
6
-
7
- #[no_mangle]
8
- pub extern fn entries(string: *const c_char) -> RubyArray {
9
- let c_str = unsafe {
10
- assert!(!string.is_null());
11
-
12
- CStr::from_ptr(string)
13
- };
14
-
15
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
16
-
17
- let files = fs::read_dir(r_str).unwrap();
18
- let mut files_vec = vec![];
19
-
20
- files_vec.push(CString::new(".").unwrap().into_raw());
21
- files_vec.push(CString::new("..").unwrap().into_raw());
22
-
23
- for file in files {
24
- let file_name_str = file.unwrap().file_name().into_string().unwrap();
25
- let file_name_cstr = CString::new(file_name_str).unwrap().into_raw();
26
- files_vec.push(file_name_cstr);
27
- }
28
-
29
- RubyArray::from_vec(files_vec)
30
- }
@@ -1,27 +0,0 @@
1
- use std::path::{Path, MAIN_SEPARATOR};
2
- use libc::c_char;
3
- use std::ffi::CStr;
4
- use std::str;
5
-
6
- #[no_mangle]
7
- pub extern "C" fn has_trailing_separator(string: *const c_char) -> bool {
8
- let c_str = unsafe {
9
- if string.is_null() {
10
- return false
11
- }
12
- CStr::from_ptr(string)
13
- };
14
-
15
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
16
- let path = Path::new(r_str);
17
- let last_component = path.iter().last();
18
- if last_component.is_none() {
19
- false
20
- } else {
21
- let mut parts: Vec<&str> = r_str.rsplit_terminator(MAIN_SEPARATOR).collect();
22
- parts.retain(|x| !x.is_empty());
23
- let last_part = parts.first().unwrap_or(&"").chars().last().unwrap_or(MAIN_SEPARATOR);
24
- let last_char = r_str.chars().last().unwrap();
25
- (last_part != last_char) && (last_char == MAIN_SEPARATOR)
26
- }
27
- }
@@ -1,17 +0,0 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr};
3
- use std::path::MAIN_SEPARATOR;
4
-
5
-
6
- #[no_mangle]
7
- pub extern fn is_absolute(path: *const c_char) -> bool {
8
- if path.is_null() {
9
- return false;
10
- }
11
- let r_str = unsafe { CStr::from_ptr(path) }.to_str().unwrap();
12
-
13
- match r_str.chars().next() {
14
- Some(c) => c == MAIN_SEPARATOR,
15
- None => false
16
- }
17
- }
@@ -1,15 +0,0 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr};
3
- use std::str;
4
-
5
- #[no_mangle]
6
- pub extern fn is_blank(string: *const c_char) -> bool {
7
- let c_str = unsafe {
8
- if string.is_null() {
9
- return true;
10
- }
11
- CStr::from_ptr(string)
12
- };
13
-
14
- str::from_utf8(c_str.to_bytes()).unwrap().trim().is_empty()
15
- }
@@ -1,18 +0,0 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr};
3
- use std::str;
4
- use std::path::Path;
5
-
6
- #[no_mangle]
7
- pub extern fn is_directory(string: *const c_char) -> bool {
8
- let c_str = unsafe {
9
- if string.is_null() {
10
- return false;
11
- }
12
- CStr::from_ptr(string)
13
- };
14
-
15
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
16
-
17
- Path::new(r_str).is_dir()
18
- }
@@ -1,16 +0,0 @@
1
- use std::path::MAIN_SEPARATOR;
2
- use libc::c_char;
3
- use std::ffi::{CStr};
4
-
5
- #[no_mangle]
6
- pub extern fn is_relative(path: *const c_char) -> bool {
7
- if path.is_null() {
8
- return false;
9
- }
10
- let r_str = unsafe { CStr::from_ptr(path) }.to_str().unwrap();
11
-
12
- match r_str.chars().next() {
13
- Some(c) => c != MAIN_SEPARATOR,
14
- None => true
15
- }
16
- }
@@ -1,20 +0,0 @@
1
- use libc;
2
- use std::mem;
3
-
4
- #[repr(C)]
5
- pub struct RubyArray {
6
- len: libc::size_t,
7
- data: *const libc::c_void,
8
- }
9
-
10
- impl RubyArray {
11
- #[allow(dead_code)]
12
- pub fn from_vec<T>(vec: Vec<T>) -> RubyArray {
13
- let array = RubyArray {
14
- data: vec.as_ptr() as *const libc::c_void,
15
- len: vec.len() as libc::size_t
16
- };
17
- mem::forget(vec);
18
- array
19
- }
20
- }
@@ -1,34 +0,0 @@
1
- use libc::c_char;
2
- use std::ffi::{CStr,CString};
3
- use std::str;
4
-
5
- pub struct RubyString;
6
-
7
- // Coercing strs into Strings has some loss of performance
8
- // You may use these methods temporarily but it would be much better
9
- // to write all of this code out in each method using just str.
10
- //
11
- // Using these methods you will still get you 10X (= 900%) performance
12
- // gain regardless. But really consider not using String. If you do
13
- // as I've intstructed the performance gains will go from 900% to 1250%.
14
- impl RubyString {
15
- #[allow(dead_code)]
16
- // FOR QUICK IMPLEMENTATION. NOT FOR PRODUCTION.
17
- // SEE BENCHMARKS FOR SANCTIONED IMPLEMENTATION.
18
- fn from_ruby(s: *const c_char) -> String {
19
- let c_str = unsafe {
20
- assert!(!s.is_null());
21
- CStr::from_ptr(s)
22
- };
23
- (*str::from_utf8(c_str.to_bytes()).unwrap_or("")).to_string()
24
- }
25
-
26
- #[allow(dead_code)]
27
- // FOR QUICK IMPLEMENTATION. NOT FOR PRODUCTION.
28
- // SEE BENCHMARKS FOR SANCTIONED IMPLEMENTATION.
29
- fn to_ruby<S: Into<String>>(s: S) -> *const c_char {
30
- let r_str = s.into();
31
- let s_slice: &str = &r_str[..];
32
- CString::new(s_slice).unwrap().into_raw()
33
- }
34
- }