rust_require 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/source_analyzer/extconf.rb +10 -0
- data/ext/source_analyzer/lib/libsource_analyzer.so +0 -0
- data/lib/rust_require/c_wrapper_generator.rb +75 -0
- data/lib/rust_require/ruby_wrapper_generator.rb +72 -0
- data/lib/rust_require/rust_require.rb +100 -0
- data/lib/rust_require/rustc.rb +86 -0
- data/lib/rust_require/types/primitives.rb +61 -0
- data/lib/rust_require/types/string.rb +79 -0
- data/lib/rust_require/types.rb +98 -0
- data/lib/rust_require/version.rb +3 -0
- data/lib/rust_require.rb +21 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 965d9bac57b7c7c943ecbd174a1e608f9d00ce22
|
4
|
+
data.tar.gz: 1bc2d94473b2ebde3854f693fdaebe5adf3c9ede
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 613dbd5fed2cd485bb3f3cbeb64e27ab4f2a17c222a719d53b2d80322f3918909a3acaee7183af509e670ee1682a60a81c5e97c9f4ca1ac9af1f3de2eedc3614
|
7
|
+
data.tar.gz: c20418ae1136f036af523885bcb88405f0496445335d2381ff4ef614378f8ebb3f30ba9a7f3604ff2b97d2906f1a89ec69fdcaa122c754448f18cf87c481b1ac
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
# Stops the installation process if one of these commands is not found in
|
4
|
+
# $PATH.
|
5
|
+
find_executable('rustc')
|
6
|
+
find_executable('rake')
|
7
|
+
|
8
|
+
puts `rustc #{File.dirname(__FILE__)}/lib/source_analyzer.rs -o #{File.dirname(__FILE__)}/lib/libsource_analyzer.so`
|
9
|
+
|
10
|
+
$makefile_created = true
|
Binary file
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Rust
|
4
|
+
# A Generator for Rust-to-C-wrappers
|
5
|
+
# Is initialized with a Json file containing
|
6
|
+
# relevant info about the rust file
|
7
|
+
class CWrapperGenerator
|
8
|
+
# info file, already parsed with json
|
9
|
+
def initialize(json)
|
10
|
+
@json = json
|
11
|
+
end
|
12
|
+
|
13
|
+
# Generates a Rust-to-C code wrapper as rust code (String)
|
14
|
+
def generate_wrapper
|
15
|
+
generate_mod_wrapper(@json, '')
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Generates wrapper fns for fn_headers and submodules in mod (String)
|
21
|
+
# submod_string is mods path eg. "mod::submod::"
|
22
|
+
def generate_mod_wrapper(mod,submod_string)
|
23
|
+
w = mod['submodules'].map do |x|
|
24
|
+
generate_mod_wrapper(x,submod_string+x['name']+'::')
|
25
|
+
end.join("\n")
|
26
|
+
|
27
|
+
w << generate_fns(mod['fn_headers'], submod_string)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Generates wrapper fns for fn_headers (String)
|
31
|
+
def generate_fns(fn_headers, submod_string)
|
32
|
+
fn_headers.map do |fn|
|
33
|
+
WrapperFn.new(submod_string + fn['name'], fn['inputs'], fn['output']).to_s
|
34
|
+
end.join("\n")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Rust
|
40
|
+
class CWrapperGenerator
|
41
|
+
# Rust code of a wrapper function
|
42
|
+
class WrapperFn
|
43
|
+
# original_name: name of the fn to be wrapped (String)
|
44
|
+
# inputs: input types in order (Array[String])
|
45
|
+
# output: output type (String || nil)
|
46
|
+
def initialize(original_name, inputs, output)
|
47
|
+
@original_name = original_name
|
48
|
+
@inputs = inputs
|
49
|
+
@output = output
|
50
|
+
end
|
51
|
+
|
52
|
+
# returns string of rust code
|
53
|
+
def to_s
|
54
|
+
# convert inputs
|
55
|
+
input_types = @inputs.map { |t| Rust::Types.find_type(t) }
|
56
|
+
c_inputs = input_types.map { |t| t.c_input_type } #C input types ([String])
|
57
|
+
input_str = c_inputs.map.with_index { |t,i| "c#{i}: #{t}" }.join(',') #fn foo_wrapper(input_str) ...
|
58
|
+
input_conversions = input_types.map.with_index { |t,i| t.c_input_conversion("c#{i}") }.join(",") #code used to convert input types to c types
|
59
|
+
|
60
|
+
# convert output
|
61
|
+
output_type = Rust::Types.find_type(@output)
|
62
|
+
c_output = output_type.c_output_type
|
63
|
+
output_conversion = output_type.c_output_conversion('output')
|
64
|
+
|
65
|
+
<<-END
|
66
|
+
#[no_mangle]
|
67
|
+
pub extern "C" fn _#{@original_name.gsub('::','_')}_wrapper(#{input_str}) -> #{c_output} {
|
68
|
+
let output = #{@original_name}(#{input_conversions});
|
69
|
+
#{output_conversion}
|
70
|
+
}
|
71
|
+
END
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Rust
|
2
|
+
# This class generates Ruby wrappers for a dylib
|
3
|
+
# with information from an info.json file and
|
4
|
+
# a ruby Module (or Class) Object
|
5
|
+
class RubyWrapperGenerator
|
6
|
+
# @info_file: info.json file, parsed with JSON
|
7
|
+
def info_file=(info_file)
|
8
|
+
@info_file = info_file
|
9
|
+
end
|
10
|
+
|
11
|
+
# @rust_lib: path to the rust lib to be included (String)
|
12
|
+
attr_writer :rust_lib
|
13
|
+
|
14
|
+
# makes items from lib available in mod
|
15
|
+
# mod: Module/Class into which the wrappers should get included (Module || Class)
|
16
|
+
def include_lib(mod)
|
17
|
+
# attach items according to @info_file
|
18
|
+
attach_items(@info_file, mod, '')
|
19
|
+
end
|
20
|
+
|
21
|
+
# attaches items to mod,
|
22
|
+
# mod_string is the mod's prefix eg 'mod_submod_'
|
23
|
+
def attach_items(rust_module, mod, mod_string)
|
24
|
+
rust_module['submodules'].each do |x|
|
25
|
+
rust_mod = Module.new
|
26
|
+
attach_items(x, rust_mod, mod_string+x['name']+'_')
|
27
|
+
mod.const_set(x['name'].camelize, rust_mod)
|
28
|
+
end
|
29
|
+
|
30
|
+
attach_fns(rust_module['fn_headers'], mod, mod_string)
|
31
|
+
end
|
32
|
+
|
33
|
+
# attaches items via FFI to mod
|
34
|
+
def attach_fns(fn_headers, mod, mod_string)
|
35
|
+
# add ffi and the rust lib to mod
|
36
|
+
mod.extend FFI::Library
|
37
|
+
mod.ffi_lib @rust_lib
|
38
|
+
|
39
|
+
fn_headers.each do |fn|
|
40
|
+
rust_fn_name = fn['name']
|
41
|
+
|
42
|
+
# fn mod::fn() => fn _mod_fn_wrapper
|
43
|
+
wrapper_name = "_#{mod_string+fn['name']}_wrapper".to_sym
|
44
|
+
|
45
|
+
input_types = fn['inputs'].map { |t| Rust::Types.find_type(t) }
|
46
|
+
ffi_input_types = input_types.map { |t| t.ffi_input_type }
|
47
|
+
|
48
|
+
|
49
|
+
output_type = Rust::Types.find_type(fn['output'])
|
50
|
+
ffi_output_type = output_type.ffi_output_type
|
51
|
+
|
52
|
+
# attach fn and define ruby wrapper
|
53
|
+
mod.attach_function wrapper_name, ffi_input_types, ffi_output_type
|
54
|
+
mod.instance_eval do
|
55
|
+
define_method(rust_fn_name) do |*args|
|
56
|
+
# check input parameter count
|
57
|
+
raise ArgumentError, "wrong number of arguments (#{args.count} for #{input_types.count})" unless args.count == input_types.count
|
58
|
+
|
59
|
+
# check & convert ruby objects before handling them to FFI
|
60
|
+
args.map!.with_index do |arg,i|
|
61
|
+
input_types[i].ruby_input_conversion(arg)
|
62
|
+
end
|
63
|
+
|
64
|
+
# call FFI function and convert output
|
65
|
+
raw_output = send wrapper_name, *args
|
66
|
+
output_type.ruby_output_conversion raw_output
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Rust
|
2
|
+
# Hash to keep record of already required files
|
3
|
+
ALREADY_REQUIRED = Hash.new(false)
|
4
|
+
|
5
|
+
# This should compile 'file_name' with rustc,
|
6
|
+
# generate rust-to-c wrappers and finally
|
7
|
+
# make as much as possible available
|
8
|
+
# in Module 'mod' as ruby objects/methods.
|
9
|
+
|
10
|
+
# file_path: String (path to .rs file)
|
11
|
+
# mod: Module/Class (Module which requires the .rs file)
|
12
|
+
def self.require_rust_file(file_path, mod)
|
13
|
+
# type check haha
|
14
|
+
check_file file_path
|
15
|
+
|
16
|
+
# make the path absolute
|
17
|
+
file_path = File.absolute_path file_path
|
18
|
+
|
19
|
+
# check if the file was already required by mod
|
20
|
+
return if already_required? [file_path,mod]
|
21
|
+
|
22
|
+
register_file [file_path,mod]
|
23
|
+
|
24
|
+
# compute rust crate name
|
25
|
+
# file name without .rs extension
|
26
|
+
crate_name = File.basename(file_path, '.rs')
|
27
|
+
|
28
|
+
# path of dir containing file_name
|
29
|
+
dir_name = File.dirname(file_path)
|
30
|
+
|
31
|
+
# in case of ../blabla/mod.rs
|
32
|
+
if crate_name == 'mod'
|
33
|
+
crate_name = dir_name.split("/").last
|
34
|
+
end
|
35
|
+
|
36
|
+
# create .rust_require/#{file_name} subfolder
|
37
|
+
subdir = create_subfolder(crate_name, dir_name)
|
38
|
+
|
39
|
+
# TODO: insert check for unmodified input here
|
40
|
+
|
41
|
+
# location of info.json
|
42
|
+
info_file_path = "#{subdir}/info.json"
|
43
|
+
|
44
|
+
# Use Rustc to create wrappers and compile the file + wrappers
|
45
|
+
rustc = Rustc.new(file_path)
|
46
|
+
rustc.subdir = subdir
|
47
|
+
rustc.info_file_path = info_file_path
|
48
|
+
rustc.output_path = "#{subdir}/lib#{File.basename(file_path, '.rs')}.so"
|
49
|
+
|
50
|
+
info_file = rustc.create_wrapper
|
51
|
+
rustc.compile
|
52
|
+
|
53
|
+
# Use RubyWrapperGenerator to make items from the compiled
|
54
|
+
# lib available in mod
|
55
|
+
gen = RubyWrapperGenerator.new
|
56
|
+
gen.info_file = info_file
|
57
|
+
gen.rust_lib = rustc.output_path
|
58
|
+
gen.include_lib(mod)
|
59
|
+
|
60
|
+
true #explicit return value
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# This checks if file_name is a valid .rs file
|
66
|
+
def self.check_file(file_path)
|
67
|
+
raise ArgumentError, 'input must be a String object' unless file_path.is_a? String
|
68
|
+
raise LoadError, "file #{file_path} not found" unless File.exists? file_path
|
69
|
+
raise NameError, 'input file must be a .rs file' unless file_path.end_with? '.rs'
|
70
|
+
end
|
71
|
+
|
72
|
+
# checks if the file/mod combination has already been required
|
73
|
+
def self.already_required?(comb)
|
74
|
+
ALREADY_REQUIRED[comb]
|
75
|
+
end
|
76
|
+
|
77
|
+
# registers a file/mod combination as 'already_required'
|
78
|
+
def self.register_file(comb)
|
79
|
+
ALREADY_REQUIRED[comb] = true
|
80
|
+
end
|
81
|
+
|
82
|
+
# This creates a subfolder '.rust_require/#{crate_name}' in dir_name
|
83
|
+
# to store intermediate files to cache compilation results
|
84
|
+
def self.create_subfolder(crate_name, dir_name)
|
85
|
+
# path of the dirs to be created
|
86
|
+
new_dir_paths = []
|
87
|
+
new_dir_paths << "#{dir_name}/.rust_require"
|
88
|
+
new_dir_paths << "#{dir_name}/.rust_require/#{crate_name}"
|
89
|
+
|
90
|
+
new_dir_paths.each do |path|
|
91
|
+
unless Dir.exists? path
|
92
|
+
# mkdir with permissions: rwx-rx-r
|
93
|
+
Dir.mkdir path, 0754
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# return the newly created dir path
|
98
|
+
new_dir_paths[1]
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Rust
|
2
|
+
# A Wrapper to use rustc
|
3
|
+
class Rustc
|
4
|
+
# Path of rustc lint plugin to gather information about .rs files
|
5
|
+
SOURCE_ANALYZER = Gem::Specification.find_by_name('rust_require').full_gem_path + '/ext/source_analyzer/lib/libsource_analyzer.so'
|
6
|
+
|
7
|
+
# default rustc command
|
8
|
+
RUSTC_CMD = 'rustc --crate-type dylib -A dead_code'
|
9
|
+
|
10
|
+
# @output_path: output path for library generated by Rustc
|
11
|
+
attr_accessor :output_path
|
12
|
+
|
13
|
+
# @info_file_path is the info.json file containing infos about the rust lib
|
14
|
+
attr_accessor :info_file_path
|
15
|
+
|
16
|
+
# @subdir is a tempdir
|
17
|
+
attr_writer :subdir
|
18
|
+
|
19
|
+
# input is a String object containing the absolute path to an input file
|
20
|
+
def initialize(input)
|
21
|
+
@input_path = input
|
22
|
+
end
|
23
|
+
|
24
|
+
# creates a c-wrapper for file at @input_path
|
25
|
+
# returns info.json, parsed with JSON
|
26
|
+
def create_wrapper
|
27
|
+
# @input_path with wrappers added
|
28
|
+
@tempfile = "#{File.dirname(@input_path)}/#{File.basename(@input_path, ".*")}_wrapper.rs"
|
29
|
+
|
30
|
+
analyze_tempfile
|
31
|
+
|
32
|
+
# parse info.json
|
33
|
+
info_file = JSON.parse File.open(@info_file_path, 'r').read
|
34
|
+
|
35
|
+
gen = CWrapperGenerator.new(info_file)
|
36
|
+
|
37
|
+
File.open(@tempfile, "w+") do |f|
|
38
|
+
# add necessary extern crate definitions
|
39
|
+
f << <<-SRC
|
40
|
+
#![allow(unused_features)]
|
41
|
+
#![feature(libc,cstr_to_str)]
|
42
|
+
extern crate libc;
|
43
|
+
SRC
|
44
|
+
|
45
|
+
# add the actual file content
|
46
|
+
File.open(@input_path, "r") { |input| f << input.read }
|
47
|
+
|
48
|
+
# add wrappers
|
49
|
+
f << gen.generate_wrapper
|
50
|
+
end
|
51
|
+
|
52
|
+
# return info_file for further use
|
53
|
+
info_file
|
54
|
+
end
|
55
|
+
|
56
|
+
# Compiles file @input_path with rustc
|
57
|
+
def compile
|
58
|
+
print `#{RUSTC_CMD} -L #{File.dirname(@input_path)} #{@tempfile} -o #{@output_path}`
|
59
|
+
raise "rust compiler error" if $? != 0
|
60
|
+
`rm #{@tempfile}`
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
# Analyze @tempfile with the lint
|
65
|
+
# create an info.json file in @subdir
|
66
|
+
def analyze_tempfile
|
67
|
+
File.open(@tempfile, 'w+') do |f|
|
68
|
+
# injection of the librust_grep_lints plugin
|
69
|
+
f << "#![feature(plugin)]\n#![plugin(source_analyzer)]\n"
|
70
|
+
|
71
|
+
# add the actual file content
|
72
|
+
File.open(@input_path, "r") { |input| f << input.read }
|
73
|
+
end
|
74
|
+
|
75
|
+
# use the lint to just parse the file (no output)
|
76
|
+
print `RUST_REQUIRE_FILE=#{@info_file_path} #{RUSTC_CMD} -Z no-trans -L #{File.dirname(@input_path)} -L #{File.dirname(SOURCE_ANALYZER)} #{@tempfile}`
|
77
|
+
raise "rust compiler error" if $? != 0
|
78
|
+
|
79
|
+
# remove the injected lint plugin again
|
80
|
+
File.open(@tempfile, 'w+') do |f|
|
81
|
+
# add just the actual file content
|
82
|
+
File.open(@input_path, "r") { |input| f << input.read }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Rust
|
2
|
+
# Implement primitive types:
|
3
|
+
module Types
|
4
|
+
# nil
|
5
|
+
class Nil < Type
|
6
|
+
@rust_type = 'nil'
|
7
|
+
|
8
|
+
def c_type; '()'; end
|
9
|
+
def ffi_output_type; :void; end
|
10
|
+
def ffi_input_type
|
11
|
+
raise ArgumentError, "nil as ffi input is not supported by the ffi gem"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Bool < Type
|
16
|
+
@rust_type = "bool"
|
17
|
+
end
|
18
|
+
|
19
|
+
class Isize < Type
|
20
|
+
@rust_type = "isize"
|
21
|
+
def ffi_type; :int; end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Usize < Type
|
25
|
+
@rust_type = "usize"
|
26
|
+
def ffi_type; :uint; end
|
27
|
+
end
|
28
|
+
|
29
|
+
# more metaprogramming!!
|
30
|
+
%w[8 16 32 64].each do |x|
|
31
|
+
usize = Class.new(Type) do
|
32
|
+
@rust_type = "u#{x}"
|
33
|
+
def ffi_type; rust_type.sub('u', 'uint').to_sym; end
|
34
|
+
end
|
35
|
+
|
36
|
+
isize = Class.new(Type) do
|
37
|
+
@rust_type = "i#{x}"
|
38
|
+
def ffi_type; rust_type.sub('i', 'int').to_sym; end
|
39
|
+
end
|
40
|
+
|
41
|
+
const_set('U'+x, usize)
|
42
|
+
const_set('I'+x, isize)
|
43
|
+
end
|
44
|
+
|
45
|
+
class F32 < Type
|
46
|
+
@rust_type = 'f32'
|
47
|
+
|
48
|
+
# Ruby Floats are always f64
|
49
|
+
def c_type; 'f64'; end
|
50
|
+
def c_input_conversion(name); "#{name} as f32"; end
|
51
|
+
def c_output_conversion(name); "#{name} as f64"; end
|
52
|
+
|
53
|
+
def ffi_type; :double; end
|
54
|
+
end
|
55
|
+
|
56
|
+
class F64 < Type
|
57
|
+
@rust_type = 'f64'
|
58
|
+
def ffi_type; :double; end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Rust
|
2
|
+
module Types
|
3
|
+
class String < Type
|
4
|
+
@rust_type = 'String'
|
5
|
+
|
6
|
+
def not_implemented
|
7
|
+
raise NotImplementedError, 'String as rust input type is not supported, use &str instead!'
|
8
|
+
end
|
9
|
+
|
10
|
+
def c_input_type
|
11
|
+
not_implemented
|
12
|
+
end
|
13
|
+
|
14
|
+
def c_output_type; '(*const u8,usize)'; end
|
15
|
+
|
16
|
+
def c_output_conversion(name)
|
17
|
+
<<-CODE
|
18
|
+
{
|
19
|
+
let mut #{name} = #{name};
|
20
|
+
#{name}.shrink_to_fit();
|
21
|
+
let tuple = (#{name}.as_ptr(), #{name}.len());
|
22
|
+
std::mem::forget(#{name});
|
23
|
+
tuple
|
24
|
+
}
|
25
|
+
CODE
|
26
|
+
end
|
27
|
+
|
28
|
+
def c_input_conversion(slice)
|
29
|
+
not_implemented
|
30
|
+
end
|
31
|
+
|
32
|
+
def ffi_type; Rust::Slice.by_value; end
|
33
|
+
|
34
|
+
def ruby_output_conversion(slice)
|
35
|
+
(start,len) = slice.unpack
|
36
|
+
start.read_string(len.to_i).force_encoding("UTF-8")
|
37
|
+
end
|
38
|
+
|
39
|
+
def ruby_input_conversion(str)
|
40
|
+
not_implemented
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class StrSlice < Type
|
45
|
+
def rust_type_regex
|
46
|
+
/^&(mut)?( )?str$/
|
47
|
+
end
|
48
|
+
|
49
|
+
def not_implemented
|
50
|
+
raise NotImplementedError, '&str as rust output parameter is not supported, use String instead!'
|
51
|
+
end
|
52
|
+
|
53
|
+
def c_output_type
|
54
|
+
not_implemented
|
55
|
+
end
|
56
|
+
|
57
|
+
def c_output_conversion(name)
|
58
|
+
not_implemented
|
59
|
+
end
|
60
|
+
|
61
|
+
def c_input_conversion(slice)
|
62
|
+
"#{slice}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def ffi_type; Rust::Slice.by_value; end
|
66
|
+
|
67
|
+
def ruby_output_conversion(slice)
|
68
|
+
not_implemented
|
69
|
+
end
|
70
|
+
|
71
|
+
def ruby_input_conversion(str)
|
72
|
+
str.encode!(Encoding::UTF_8)
|
73
|
+
len = str.bytesize
|
74
|
+
start = FFI::MemoryPointer.from_string(str).address
|
75
|
+
Rust::Slice.from(start, len)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Rust
|
2
|
+
# a rust fat pointer
|
3
|
+
class Slice < FFI::Struct
|
4
|
+
layout :ptr, :pointer,
|
5
|
+
:len, :uint
|
6
|
+
|
7
|
+
def self.from(start, len)
|
8
|
+
s = new
|
9
|
+
s[:ptr] = start
|
10
|
+
s[:len] = len
|
11
|
+
s
|
12
|
+
end
|
13
|
+
|
14
|
+
def unpack
|
15
|
+
[self[:ptr], self[:len]]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Types are used to implement support
|
20
|
+
# for rust types in rust_require
|
21
|
+
module Types
|
22
|
+
# returns type instance for rust_type
|
23
|
+
def self.find_type(rust_type)
|
24
|
+
# find types in module constants
|
25
|
+
type = constants
|
26
|
+
.map { |c| const_get(c) }
|
27
|
+
.keep_if { |c| c.is_a?(Class) && c.ancestors.include?(Type) && c != Type} #just Type subclass objects, excluding Type itself
|
28
|
+
.map { |c| c.new } # instances of the Type classes
|
29
|
+
.find { |c| c.rust_type_regex =~ rust_type }
|
30
|
+
|
31
|
+
if type
|
32
|
+
type.rust_type = rust_type
|
33
|
+
type
|
34
|
+
else
|
35
|
+
raise NotImplementedError, "type #{rust_type} is not implemented!"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# The base class for Types with simple defaults
|
40
|
+
class Type
|
41
|
+
# accessor for @rust_type of Type class
|
42
|
+
def self.rust_type; @rust_type; end
|
43
|
+
|
44
|
+
# set @rust_type from class variable @rust_type
|
45
|
+
def initialize
|
46
|
+
@rust_type = self.class.rust_type
|
47
|
+
end
|
48
|
+
|
49
|
+
# name of the rust type (String)
|
50
|
+
# raises error when @rust_type is nil
|
51
|
+
def rust_type
|
52
|
+
raise NotImplementedError, "This is a bug." if @rust_type.nil?
|
53
|
+
@rust_type
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_writer :rust_type
|
57
|
+
|
58
|
+
def rust_type_regex
|
59
|
+
Regexp.new @rust_type
|
60
|
+
end
|
61
|
+
|
62
|
+
def c_type; rust_type; end
|
63
|
+
|
64
|
+
# name of the type passed in from ruby (String)
|
65
|
+
def c_input_type; c_type; end
|
66
|
+
|
67
|
+
# name of the type returned by the wrapper fn to ruby
|
68
|
+
def c_output_type; c_type; end
|
69
|
+
|
70
|
+
# rust code performing necessary conversions on input from ruby
|
71
|
+
# with name before passing it to original rust fn (String)
|
72
|
+
def c_input_conversion(name); name; end
|
73
|
+
|
74
|
+
# rust code performing necessary conversions on output with name
|
75
|
+
# from rust fn before returning it to ruby (String)
|
76
|
+
def c_output_conversion(name); name; end
|
77
|
+
|
78
|
+
# Border between Rust and Ruby
|
79
|
+
########################################
|
80
|
+
|
81
|
+
# shortcut for ffi type (input and output)
|
82
|
+
def ffi_type; rust_type.to_sym; end
|
83
|
+
|
84
|
+
# returns symbol understood by ruby ffi gem corresponding to @rust_type as input
|
85
|
+
def ffi_input_type; ffi_type; end
|
86
|
+
|
87
|
+
# returns symbol understood by ruby ffi gem corresponding to @rust_type as output
|
88
|
+
def ffi_output_type; ffi_type; end
|
89
|
+
|
90
|
+
# return value will directly be passed into the ffi fn
|
91
|
+
def ruby_input_conversion(obj); obj; end
|
92
|
+
|
93
|
+
# obj is return value of ffi fn
|
94
|
+
# return value will be the final result of ffi call
|
95
|
+
def ruby_output_conversion(obj); obj; end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/rust_require.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Extern libs
|
2
|
+
require 'ffi'
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
4
|
+
|
5
|
+
# Libs
|
6
|
+
require_relative 'rust_require/version.rb'
|
7
|
+
require_relative 'rust_require/rust_require.rb'
|
8
|
+
require_relative 'rust_require/rustc.rb'
|
9
|
+
require_relative 'rust_require/types.rb'
|
10
|
+
require_relative 'rust_require/c_wrapper_generator.rb'
|
11
|
+
require_relative 'rust_require/ruby_wrapper_generator.rb'
|
12
|
+
|
13
|
+
# Types
|
14
|
+
require_relative 'rust_require/types/primitives.rb'
|
15
|
+
require_relative 'rust_require/types/string.rb'
|
16
|
+
|
17
|
+
class Module
|
18
|
+
def rust_require(file)
|
19
|
+
Rust.require_rust_file(file, self)
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rust_require
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Florian Lackner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.99'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.99'
|
69
|
+
description: |2
|
70
|
+
A ruby gem that generates bindings to rust files automatically.
|
71
|
+
email: lacknerflo@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ext/source_analyzer/extconf.rb
|
77
|
+
- ext/source_analyzer/lib/libsource_analyzer.so
|
78
|
+
- lib/rust_require.rb
|
79
|
+
- lib/rust_require/c_wrapper_generator.rb
|
80
|
+
- lib/rust_require/ruby_wrapper_generator.rb
|
81
|
+
- lib/rust_require/rust_require.rb
|
82
|
+
- lib/rust_require/rustc.rb
|
83
|
+
- lib/rust_require/types.rb
|
84
|
+
- lib/rust_require/types/primitives.rb
|
85
|
+
- lib/rust_require/types/string.rb
|
86
|
+
- lib/rust_require/version.rb
|
87
|
+
homepage: https://github.com/flo-l/rust_require
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.4.6
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: An automatic rust binding generator
|
111
|
+
test_files: []
|