ffi 1.17.0-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +456 -0
  3. data/COPYING +49 -0
  4. data/Gemfile +21 -0
  5. data/LICENSE +24 -0
  6. data/LICENSE.SPECS +22 -0
  7. data/README.md +137 -0
  8. data/Rakefile +206 -0
  9. data/ffi.gemspec +42 -0
  10. data/lib/2.5/ffi_c.bundle +0 -0
  11. data/lib/2.6/ffi_c.bundle +0 -0
  12. data/lib/2.7/ffi_c.bundle +0 -0
  13. data/lib/3.0/ffi_c.bundle +0 -0
  14. data/lib/3.1/ffi_c.bundle +0 -0
  15. data/lib/3.2/ffi_c.bundle +0 -0
  16. data/lib/3.3/ffi_c.bundle +0 -0
  17. data/lib/ffi/abstract_memory.rb +44 -0
  18. data/lib/ffi/autopointer.rb +180 -0
  19. data/lib/ffi/buffer.rb +4 -0
  20. data/lib/ffi/callback.rb +4 -0
  21. data/lib/ffi/compat.rb +43 -0
  22. data/lib/ffi/data_converter.rb +67 -0
  23. data/lib/ffi/dynamic_library.rb +118 -0
  24. data/lib/ffi/enum.rb +302 -0
  25. data/lib/ffi/errno.rb +43 -0
  26. data/lib/ffi/ffi.rb +50 -0
  27. data/lib/ffi/function.rb +71 -0
  28. data/lib/ffi/io.rb +62 -0
  29. data/lib/ffi/library.rb +576 -0
  30. data/lib/ffi/library_path.rb +109 -0
  31. data/lib/ffi/managedstruct.rb +84 -0
  32. data/lib/ffi/memorypointer.rb +1 -0
  33. data/lib/ffi/platform/aarch64-darwin/types.conf +130 -0
  34. data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
  35. data/lib/ffi/platform/aarch64-freebsd12/types.conf +181 -0
  36. data/lib/ffi/platform/aarch64-linux/types.conf +175 -0
  37. data/lib/ffi/platform/aarch64-openbsd/types.conf +134 -0
  38. data/lib/ffi/platform/aarch64-windows/types.conf +52 -0
  39. data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
  40. data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
  41. data/lib/ffi/platform/arm-linux/types.conf +132 -0
  42. data/lib/ffi/platform/hppa1.1-linux/types.conf +178 -0
  43. data/lib/ffi/platform/hppa2.0-linux/types.conf +178 -0
  44. data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
  45. data/lib/ffi/platform/i386-darwin/types.conf +100 -0
  46. data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  47. data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
  48. data/lib/ffi/platform/i386-gnu/types.conf +107 -0
  49. data/lib/ffi/platform/i386-linux/types.conf +103 -0
  50. data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  51. data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
  52. data/lib/ffi/platform/i386-solaris/types.conf +122 -0
  53. data/lib/ffi/platform/i386-windows/types.conf +52 -0
  54. data/lib/ffi/platform/ia64-linux/types.conf +104 -0
  55. data/lib/ffi/platform/loongarch64-linux/types.conf +141 -0
  56. data/lib/ffi/platform/mips-linux/types.conf +102 -0
  57. data/lib/ffi/platform/mips64-linux/types.conf +104 -0
  58. data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
  59. data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
  60. data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
  61. data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
  62. data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
  63. data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
  64. data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
  65. data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
  66. data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
  67. data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
  68. data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
  69. data/lib/ffi/platform/powerpc64le-linux/types.conf +100 -0
  70. data/lib/ffi/platform/riscv64-linux/types.conf +104 -0
  71. data/lib/ffi/platform/s390-linux/types.conf +102 -0
  72. data/lib/ffi/platform/s390x-linux/types.conf +102 -0
  73. data/lib/ffi/platform/sparc-linux/types.conf +102 -0
  74. data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
  75. data/lib/ffi/platform/sparcv9-linux/types.conf +102 -0
  76. data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
  77. data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
  78. data/lib/ffi/platform/sw_64-linux/types.conf +141 -0
  79. data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
  80. data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
  81. data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +130 -0
  82. data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
  83. data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
  84. data/lib/ffi/platform/x86_64-haiku/types.conf +117 -0
  85. data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
  86. data/lib/ffi/platform/x86_64-msys/types.conf +119 -0
  87. data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
  88. data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
  89. data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
  90. data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
  91. data/lib/ffi/platform.rb +187 -0
  92. data/lib/ffi/pointer.rb +167 -0
  93. data/lib/ffi/struct.rb +317 -0
  94. data/lib/ffi/struct_by_reference.rb +72 -0
  95. data/lib/ffi/struct_layout.rb +96 -0
  96. data/lib/ffi/struct_layout_builder.rb +227 -0
  97. data/lib/ffi/tools/const_generator.rb +232 -0
  98. data/lib/ffi/tools/generator.rb +105 -0
  99. data/lib/ffi/tools/generator_task.rb +32 -0
  100. data/lib/ffi/tools/struct_generator.rb +195 -0
  101. data/lib/ffi/tools/types_generator.rb +137 -0
  102. data/lib/ffi/types.rb +222 -0
  103. data/lib/ffi/union.rb +43 -0
  104. data/lib/ffi/variadic.rb +80 -0
  105. data/lib/ffi/version.rb +3 -0
  106. data/lib/ffi.rb +27 -0
  107. data/rakelib/ffi_gem_helper.rb +65 -0
  108. data/samples/getlogin.rb +8 -0
  109. data/samples/getpid.rb +8 -0
  110. data/samples/gettimeofday.rb +18 -0
  111. data/samples/hello.rb +8 -0
  112. data/samples/hello_ractor.rb +11 -0
  113. data/samples/inotify.rb +60 -0
  114. data/samples/pty.rb +75 -0
  115. data/samples/qsort.rb +20 -0
  116. data/samples/qsort_ractor.rb +28 -0
  117. data/sig/ffi/abstract_memory.rbs +165 -0
  118. data/sig/ffi/auto_pointer.rbs +27 -0
  119. data/sig/ffi/buffer.rbs +18 -0
  120. data/sig/ffi/data_converter.rbs +10 -0
  121. data/sig/ffi/dynamic_library.rbs +9 -0
  122. data/sig/ffi/enum.rbs +38 -0
  123. data/sig/ffi/function.rbs +39 -0
  124. data/sig/ffi/library.rbs +42 -0
  125. data/sig/ffi/native_type.rbs +86 -0
  126. data/sig/ffi/pointer.rbs +42 -0
  127. data/sig/ffi/struct.rbs +76 -0
  128. data/sig/ffi/struct_by_reference.rbs +11 -0
  129. data/sig/ffi/struct_by_value.rbs +7 -0
  130. data/sig/ffi/struct_layout.rbs +9 -0
  131. data/sig/ffi/struct_layout_builder.rbs +5 -0
  132. data/sig/ffi/type.rbs +39 -0
  133. data/sig/ffi.rbs +26 -0
  134. metadata +241 -0
@@ -0,0 +1,105 @@
1
+ require 'ffi/tools/struct_generator'
2
+ require 'ffi/tools/const_generator'
3
+
4
+ module FFI
5
+
6
+ ##
7
+ # Generate files with C structs for FFI::Struct and C constants.
8
+ #
9
+ # == A simple example
10
+ #
11
+ # In file +zlib.rb.ffi+:
12
+ # module Zlib
13
+ # @@@
14
+ # constants do |c|
15
+ # c.include "zlib.h"
16
+ # c.const :ZLIB_VERNUM
17
+ # end
18
+ # @@@
19
+ #
20
+ # class ZStream < FFI::Struct
21
+ #
22
+ # struct do |s|
23
+ # s.name "struct z_stream_s"
24
+ # s.include "zlib.h"
25
+ #
26
+ # s.field :next_in, :pointer
27
+ # s.field :avail_in, :uint
28
+ # s.field :total_in, :ulong
29
+ # end
30
+ # @@@
31
+ # end
32
+ # end
33
+ #
34
+ # Translate the file:
35
+ # require "ffi/tools/generator"
36
+ # FFI::Generator.new "zlib.rb.ffi", "zlib.rb"
37
+ #
38
+ # Generates the file +zlib.rb+ with constant values and offsets:
39
+ # module Zlib
40
+ # ZLIB_VERNUM = 4784
41
+ #
42
+ # class ZStream < FFI::Struct
43
+ # layout :next_in, :pointer, 0,
44
+ # :avail_in, :uint, 8,
45
+ # :total_in, :ulong, 16
46
+ # end
47
+ #
48
+ # @see FFI::Generator::Task for easy integration in a Rakefile
49
+ class Generator
50
+
51
+ def initialize(ffi_name, rb_name, options = {})
52
+ @ffi_name = ffi_name
53
+ @rb_name = rb_name
54
+ @options = options
55
+ @name = File.basename rb_name, '.rb'
56
+
57
+ file = File.read @ffi_name
58
+
59
+ new_file = file.gsub(/^( *)@@@(.*?)@@@/m) do
60
+ @constants = []
61
+ @structs = []
62
+
63
+ indent = $1
64
+ original_lines = $2.count "\n"
65
+
66
+ instance_eval $2, @ffi_name, $`.count("\n")
67
+
68
+ new_lines = []
69
+ @constants.each { |c| new_lines << c.to_ruby }
70
+ @structs.each { |s| new_lines << s.generate_layout }
71
+
72
+ new_lines = new_lines.join("\n").split "\n" # expand multiline blocks
73
+ new_lines = new_lines.map { |line| indent + line }
74
+
75
+ padding = original_lines - new_lines.length
76
+ new_lines += [nil] * padding if padding >= 0
77
+
78
+ new_lines.join "\n"
79
+ end
80
+
81
+ open @rb_name, 'w' do |f|
82
+ f.puts "# This file is generated from `#{@ffi_name}'. Do not edit."
83
+ f.puts
84
+ f.puts new_file
85
+ end
86
+ end
87
+
88
+ def constants(options = {}, &block)
89
+ @constants << FFI::ConstGenerator.new(@name, @options.merge(options), &block)
90
+ end
91
+
92
+ def struct(options = {}, &block)
93
+ @structs << FFI::StructGenerator.new(@name, @options.merge(options), &block)
94
+ end
95
+
96
+ ##
97
+ # Utility converter for constants
98
+
99
+ def to_s
100
+ proc { |obj| obj.to_s.inspect }
101
+ end
102
+
103
+ end
104
+ end
105
+
@@ -0,0 +1,32 @@
1
+ require 'ffi/tools/generator'
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+
5
+ ##
6
+ # Add Rake tasks that generate files with C structs for FFI::Struct and C constants.
7
+ #
8
+ # @example a simple example for your Rakefile
9
+ # require "ffi/tools/generator_task"
10
+ # # Add a task to generate my_object.rb out of my_object.rb.ffi
11
+ # FFI::Generator::Task.new ["my_object.rb"], cflags: "-I/usr/local/mylibrary"
12
+ #
13
+ # The generated files are also added to the 'clear' task.
14
+ #
15
+ # @see FFI::Generator for a description of the file content
16
+ class FFI::Generator::Task < Rake::TaskLib
17
+
18
+ def initialize(rb_names, options={})
19
+ task :clean do rm_f rb_names end
20
+
21
+ rb_names.each do |rb_name|
22
+ ffi_name = "#{rb_name}.ffi"
23
+
24
+ file rb_name => ffi_name do |t|
25
+ puts "Generating #{rb_name}..." if Rake.application.options.trace
26
+
27
+ FFI::Generator.new ffi_name, rb_name, options
28
+ end
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,195 @@
1
+ require 'tempfile'
2
+
3
+ module FFI
4
+
5
+ ##
6
+ # Generates an FFI Struct layout.
7
+ #
8
+ # Given the @@@ portion in:
9
+ #
10
+ # class Zlib::ZStream < FFI::Struct
11
+ # @@@
12
+ # name "struct z_stream_s"
13
+ # include "zlib.h"
14
+ #
15
+ # field :next_in, :pointer
16
+ # field :avail_in, :uint
17
+ # field :total_in, :ulong
18
+ #
19
+ # # ...
20
+ # @@@
21
+ # end
22
+ #
23
+ # StructGenerator will create the layout:
24
+ #
25
+ # layout :next_in, :pointer, 0,
26
+ # :avail_in, :uint, 4,
27
+ # :total_in, :ulong, 8,
28
+ # # ...
29
+ #
30
+ # StructGenerator does its best to pad the layout it produces to preserve
31
+ # line numbers. Place the struct definition as close to the top of the file
32
+ # for best results.
33
+
34
+ class StructGenerator
35
+ @options = {}
36
+ attr_accessor :size
37
+ attr_reader :fields
38
+
39
+ def initialize(name, options = {})
40
+ @name = name
41
+ @struct_name = nil
42
+ @includes = []
43
+ @fields = []
44
+ @found = false
45
+ @size = nil
46
+
47
+ if block_given? then
48
+ yield self
49
+ calculate self.class.options.merge(options)
50
+ end
51
+ end
52
+ def self.options=(options)
53
+ @options = options
54
+ end
55
+ def self.options
56
+ @options
57
+ end
58
+ def calculate(options = {})
59
+ binary = File.join Dir.tmpdir, "rb_struct_gen_bin_#{Process.pid}"
60
+
61
+ raise "struct name not set" if @struct_name.nil?
62
+
63
+ Tempfile.open("#{@name}.struct_generator") do |f|
64
+ f.puts "#include <stdio.h>"
65
+
66
+ @includes.each do |inc|
67
+ f.puts "#include <#{inc}>"
68
+ end
69
+
70
+ f.puts "#include <stddef.h>\n\n"
71
+ f.puts "int main(int argc, char **argv)\n{"
72
+ f.puts " #{@struct_name} s;"
73
+ f.puts %[ printf("sizeof(#{@struct_name}) %u\\n", (unsigned int) sizeof(#{@struct_name}));]
74
+
75
+ @fields.each do |field|
76
+ f.puts <<-EOF
77
+ printf("#{field.name} %u %u\\n", (unsigned int) offsetof(#{@struct_name}, #{field.name}),
78
+ (unsigned int) sizeof(s.#{field.name}));
79
+ EOF
80
+ end
81
+
82
+ f.puts "\n return 0;\n}"
83
+ f.flush
84
+
85
+ cc = ENV['CC'] || 'gcc'
86
+ output = `#{cc} #{options[:cppflags]} #{options[:cflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary} 2>&1`
87
+
88
+ unless $?.success? then
89
+ @found = false
90
+ output = output.split("\n").map { |l| "\t#{l}" }.join "\n"
91
+ raise "Compilation error generating struct #{@name} (#{@struct_name}):\n#{output}"
92
+ end
93
+ end
94
+
95
+ output = `#{binary}`.split "\n"
96
+ File.unlink(binary + (FFI::Platform.windows? ? ".exe" : ""))
97
+ sizeof = output.shift
98
+ unless @size
99
+ m = /\s*sizeof\([^)]+\) (\d+)/.match sizeof
100
+ @size = m[1]
101
+ end
102
+
103
+ line_no = 0
104
+ output.each do |line|
105
+ md = line.match(/.+ (\d+) (\d+)/)
106
+ @fields[line_no].offset = md[1].to_i
107
+ @fields[line_no].size = md[2].to_i
108
+
109
+ line_no += 1
110
+ end
111
+
112
+ @found = true
113
+ end
114
+
115
+ def field(name, type=nil)
116
+ field = Field.new(name, type)
117
+ @fields << field
118
+ return field
119
+ end
120
+
121
+ def found?
122
+ @found
123
+ end
124
+
125
+ def dump_config(io)
126
+ io.puts "rbx.platform.#{@name}.sizeof = #{@size}"
127
+
128
+ @fields.each { |field| io.puts field.to_config(@name) }
129
+ end
130
+
131
+ def generate_layout
132
+ buf = ""
133
+
134
+ @fields.each_with_index do |field, i|
135
+ if buf.empty?
136
+ buf << "layout :#{field.name}, :#{field.type}, #{field.offset}"
137
+ else
138
+ buf << " :#{field.name}, :#{field.type}, #{field.offset}"
139
+ end
140
+
141
+ if i < @fields.length - 1
142
+ buf << ",\n"
143
+ end
144
+ end
145
+
146
+ buf
147
+ end
148
+
149
+ def get_field(name)
150
+ @fields.find { |f| name == f.name }
151
+ end
152
+
153
+ def include(i)
154
+ @includes << i
155
+ end
156
+
157
+ def name(n)
158
+ @struct_name = n
159
+ end
160
+
161
+ end
162
+
163
+ ##
164
+ # A field in a Struct.
165
+
166
+ class StructGenerator::Field
167
+
168
+ attr_reader :name
169
+ attr_reader :type
170
+ attr_reader :offset
171
+ attr_accessor :size
172
+
173
+ def initialize(name, type)
174
+ @name = name
175
+ @type = type
176
+ @offset = nil
177
+ @size = nil
178
+ end
179
+
180
+ def offset=(o)
181
+ @offset = o
182
+ end
183
+
184
+ def to_config(name)
185
+ buf = []
186
+ buf << "rbx.platform.#{name}.#{@name}.offset = #{@offset}"
187
+ buf << "rbx.platform.#{name}.#{@name}.size = #{@size}"
188
+ buf << "rbx.platform.#{name}.#{@name}.type = #{@type}" if @type
189
+ buf
190
+ end
191
+
192
+ end
193
+
194
+ end
195
+
@@ -0,0 +1,137 @@
1
+ require 'tempfile'
2
+
3
+ module FFI
4
+
5
+ # @private
6
+ class TypesGenerator
7
+
8
+ ##
9
+ # Maps different C types to the C type representations we use
10
+
11
+ TYPE_MAP = {
12
+ "char" => :char,
13
+ "signed char" => :char,
14
+ "__signed char" => :char,
15
+ "unsigned char" => :uchar,
16
+
17
+ "short" => :short,
18
+ "signed short" => :short,
19
+ "signed short int" => :short,
20
+ "unsigned short" => :ushort,
21
+ "unsigned short int" => :ushort,
22
+
23
+ "int" => :int,
24
+ "signed int" => :int,
25
+ "unsigned int" => :uint,
26
+
27
+ "long" => :long,
28
+ "long int" => :long,
29
+ "signed long" => :long,
30
+ "signed long int" => :long,
31
+ "unsigned long" => :ulong,
32
+ "unsigned long int" => :ulong,
33
+ "long unsigned int" => :ulong,
34
+
35
+ "long long" => :long_long,
36
+ "long long int" => :long_long,
37
+ "signed long long" => :long_long,
38
+ "signed long long int" => :long_long,
39
+ "unsigned long long" => :ulong_long,
40
+ "unsigned long long int" => :ulong_long,
41
+
42
+ "char *" => :string,
43
+ "void *" => :pointer,
44
+ }
45
+
46
+ def self.generate(options = {})
47
+ typedefs = nil
48
+ Tempfile.open 'ffi_types_generator' do |io|
49
+ io.puts <<-C
50
+ #include <stdint.h>
51
+ #include <stddef.h>
52
+ #include <sys/types.h>
53
+ #if !(defined(WIN32))
54
+ #include <sys/socket.h>
55
+ #include <netinet/in.h>
56
+ #include <sys/resource.h>
57
+ #endif
58
+ C
59
+
60
+ io.close
61
+ cc = ENV['CC'] || 'gcc'
62
+ cmd = "#{cc} -E -x c #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -c"
63
+ if options[:input]
64
+ typedefs = File.read(options[:input])
65
+ elsif options[:remote]
66
+ typedefs = `ssh #{options[:remote]} #{cmd} - < #{io.path}`
67
+ else
68
+ typedefs = `#{cmd} #{io.path}`
69
+ end
70
+ end
71
+
72
+ code = []
73
+
74
+ typedefs.each_line do |type|
75
+ # We only care about single line typedef
76
+ next unless type =~ /typedef/
77
+ # Ignore unions or structs
78
+ next if type =~ /union|struct/
79
+
80
+ # strip off the starting typedef and ending ;
81
+ type.gsub!(/^(.*typedef\s*)/, "")
82
+ type.gsub!(/\s*;\s*$/, "")
83
+
84
+ parts = type.split(/\s+/)
85
+ def_type = parts.join(" ")
86
+
87
+ # GCC does mapping with __attribute__ stuf, also see
88
+ # http://hal.cs.berkeley.edu/cil/cil016.html section 16.2.7. Problem
89
+ # with this is that the __attribute__ stuff can either occur before or
90
+ # after the new type that is defined...
91
+ if type =~ /__attribute__/
92
+ if parts.last =~ /__QI__|__HI__|__SI__|__DI__|__word__/
93
+
94
+ # In this case, the new type is BEFORE __attribute__ we need to
95
+ # find the final_type as the type before the part that starts with
96
+ # __attribute__
97
+ final_type = ""
98
+ parts.each do |p|
99
+ break if p =~ /__attribute__/
100
+ final_type = p
101
+ end
102
+ else
103
+ final_type = parts.pop
104
+ end
105
+
106
+ def_type = case type
107
+ when /__QI__/ then "char"
108
+ when /__HI__/ then "short"
109
+ when /__SI__/ then "int"
110
+ when /__DI__/ then "long long"
111
+ when /__word__/ then "long"
112
+ else "int"
113
+ end
114
+
115
+ def_type = "unsigned #{def_type}" if type =~ /unsigned/
116
+ else
117
+ final_type = parts.pop
118
+ def_type = parts.join(" ")
119
+ end
120
+
121
+ if type = TYPE_MAP[def_type]
122
+ code << "rbx.platform.typedef.#{final_type} = #{type}"
123
+ TYPE_MAP[final_type] = TYPE_MAP[def_type]
124
+ else
125
+ # Fallback to an ordinary pointer if we don't know the type
126
+ if def_type =~ /\*/
127
+ code << "rbx.platform.typedef.#{final_type} = pointer"
128
+ TYPE_MAP[final_type] = :pointer
129
+ end
130
+ end
131
+ end
132
+
133
+ code.sort.join("\n")
134
+ end
135
+ end
136
+ end
137
+
data/lib/ffi/types.rb ADDED
@@ -0,0 +1,222 @@
1
+ #
2
+ # Copyright (C) 2008-2010 Wayne Meissner
3
+ # Copyright (c) 2007, 2008 Evan Phoenix
4
+ #
5
+ # This file is part of ruby-ffi.
6
+ #
7
+ # All rights reserved.
8
+ #
9
+ # Redistribution and use in source and binary forms, with or without
10
+ # modification, are permitted provided that the following conditions are met:
11
+ #
12
+ # * Redistributions of source code must retain the above copyright notice, this
13
+ # list of conditions and the following disclaimer.
14
+ # * Redistributions in binary form must reproduce the above copyright notice
15
+ # this list of conditions and the following disclaimer in the documentation
16
+ # and/or other materials provided with the distribution.
17
+ # * Neither the name of the Ruby FFI project nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this software
19
+ # without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+
33
+ # see {file:README}
34
+ module FFI
35
+
36
+ # Unless custom_typedefs already defined in the C-ext?
37
+ unless defined?(custom_typedefs)
38
+ # Truffleruby and JRuby don't support Ractor so far.
39
+ # So they don't need separation between builtin and custom types.
40
+ def self.custom_typedefs
41
+ TypeDefs
42
+ end
43
+ writable_typemap = true
44
+ end
45
+
46
+ class << self
47
+
48
+ private :custom_typedefs
49
+
50
+ # @param [Type, DataConverter, Symbol] old type definition used by {FFI.find_type}
51
+ # @param [Symbol] add new type definition's name to add
52
+ # @return [Type]
53
+ # Add a definition type to type definitions.
54
+ #
55
+ # The type definition is local per Ractor.
56
+ def typedef(old, add)
57
+ tm = custom_typedefs
58
+ tm[add] = find_type(old)
59
+ end
60
+
61
+ # (see FFI.typedef)
62
+ def add_typedef(old, add)
63
+ typedef old, add
64
+ end
65
+
66
+ private def __typedef(old, add)
67
+ TypeDefs[add] = find_type(old, TypeDefs)
68
+ end
69
+
70
+ # @param [Type, DataConverter, Symbol] name
71
+ # @param [Hash] type_map if nil, {FFI::TypeDefs} is used
72
+ # @return [Type]
73
+ # Find a type in +type_map+ ({FFI::TypeDefs}, by default) from
74
+ # a type objet, a type name (symbol). If +name+ is a {DataConverter},
75
+ # a new {Type::Mapped} is created.
76
+ def find_type(name, type_map = nil)
77
+ if name.is_a?(Type)
78
+ name
79
+
80
+ elsif type_map&.has_key?(name)
81
+ type_map[name]
82
+
83
+ elsif (tm=custom_typedefs).has_key?(name)
84
+ tm[name]
85
+
86
+ elsif TypeDefs.has_key?(name)
87
+ TypeDefs[name]
88
+
89
+ elsif name.is_a?(DataConverter)
90
+ # Add a typedef so next time the converter is used, it hits the cache
91
+ tm = (type_map || custom_typedefs)
92
+ tm[name] = Type::Mapped.new(name)
93
+ else
94
+ raise TypeError, "unable to resolve type '#{name}'"
95
+ end
96
+ end
97
+
98
+ # @param type +type+ is an instance of class accepted by {FFI.find_type}
99
+ # @return [Integer]
100
+ # Get +type+ size, in bytes.
101
+ def type_size(type)
102
+ find_type(type).size
103
+ end
104
+ end
105
+
106
+ # List of type definitions
107
+ TypeDefs.merge!({
108
+ # The C void type; only useful for function return types
109
+ :void => Type::VOID,
110
+
111
+ # C boolean type
112
+ :bool => Type::BOOL,
113
+
114
+ # C nul-terminated string
115
+ :string => Type::STRING,
116
+
117
+ # C signed char
118
+ :char => Type::CHAR,
119
+ # C unsigned char
120
+ :uchar => Type::UCHAR,
121
+
122
+ # C signed short
123
+ :short => Type::SHORT,
124
+ # C unsigned short
125
+ :ushort => Type::USHORT,
126
+
127
+ # C signed int
128
+ :int => Type::INT,
129
+ # C unsigned int
130
+ :uint => Type::UINT,
131
+
132
+ # C signed long
133
+ :long => Type::LONG,
134
+
135
+ # C unsigned long
136
+ :ulong => Type::ULONG,
137
+
138
+ # C signed long long integer
139
+ :long_long => Type::LONG_LONG,
140
+
141
+ # C unsigned long long integer
142
+ :ulong_long => Type::ULONG_LONG,
143
+
144
+ # C single precision float
145
+ :float => Type::FLOAT,
146
+
147
+ # C double precision float
148
+ :double => Type::DOUBLE,
149
+
150
+ # C long double
151
+ :long_double => Type::LONGDOUBLE,
152
+
153
+ # Native memory address
154
+ :pointer => Type::POINTER,
155
+
156
+ # 8 bit signed integer
157
+ :int8 => Type::INT8,
158
+ # 8 bit unsigned integer
159
+ :uint8 => Type::UINT8,
160
+
161
+ # 16 bit signed integer
162
+ :int16 => Type::INT16,
163
+ # 16 bit unsigned integer
164
+ :uint16 => Type::UINT16,
165
+
166
+ # 32 bit signed integer
167
+ :int32 => Type::INT32,
168
+ # 32 bit unsigned integer
169
+ :uint32 => Type::UINT32,
170
+
171
+ # 64 bit signed integer
172
+ :int64 => Type::INT64,
173
+ # 64 bit unsigned integer
174
+ :uint64 => Type::UINT64,
175
+
176
+ :buffer_in => Type::BUFFER_IN,
177
+ :buffer_out => Type::BUFFER_OUT,
178
+ :buffer_inout => Type::BUFFER_INOUT,
179
+
180
+ # Used in function prototypes to indicate the arguments are variadic
181
+ :varargs => Type::VARARGS,
182
+ })
183
+
184
+ # This will convert a pointer to a Ruby string (just like `:string`), but
185
+ # also allow to work with the pointer itself. This is useful when you want
186
+ # a Ruby string already containing a copy of the data, but also the pointer
187
+ # to the data for you to do something with it, like freeing it, in case the
188
+ # library handed the memory off to the caller (Ruby-FFI).
189
+ #
190
+ # It's {typedef}'d as +:strptr+.
191
+ class StrPtrConverter
192
+ extend DataConverter
193
+ native_type Type::POINTER
194
+
195
+ # @param [Pointer] val
196
+ # @param ctx not used
197
+ # @return [Array(String, Pointer)]
198
+ # Returns a [ String, Pointer ] tuple so the C memory for the string can be freed
199
+ def self.from_native(val, ctx)
200
+ [ val.null? ? nil : val.get_string(0), val ]
201
+ end
202
+ end
203
+
204
+ __typedef(StrPtrConverter, :strptr)
205
+
206
+ # Load all the platform dependent types
207
+ begin
208
+ File.open(File.join(Platform::CONF_DIR, 'types.conf'), "r") do |f|
209
+ prefix = "rbx.platform.typedef."
210
+ f.each_line { |line|
211
+ if line.index(prefix) == 0
212
+ new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/)
213
+ __typedef(orig_type.to_sym, new_type.to_sym)
214
+ end
215
+ }
216
+ end
217
+ __typedef :pointer, :caddr_t
218
+ rescue Errno::ENOENT
219
+ end
220
+
221
+ FFI.make_shareable(TypeDefs) unless writable_typemap
222
+ end