rust_require 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Rust
2
+ VERSION = "0.2.0"
3
+ end
@@ -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: []