rust_require 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 +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: []
|