faster_path 0.1.13 → 0.2.0

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 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
- }