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