ffi 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (59) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +34 -26
  3. data/ext/ffi_c/AbstractMemory.c +73 -70
  4. data/ext/ffi_c/AbstractMemory.h +8 -4
  5. data/ext/ffi_c/AutoPointer.c +8 -9
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +19 -20
  8. data/ext/ffi_c/Callback.c +85 -33
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +148 -192
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +26 -19
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +49 -47
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +52 -21
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +70 -61
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +47 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +20 -43
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/lib/ffi.rb +10 -1
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +78 -17
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/spec/ffi/bool_spec.rb +24 -0
  47. data/spec/ffi/callback_spec.rb +217 -17
  48. data/spec/ffi/enum_spec.rb +164 -0
  49. data/spec/ffi/managed_struct_spec.rb +6 -1
  50. data/spec/ffi/number_spec.rb +30 -0
  51. data/spec/ffi/pointer_spec.rb +33 -8
  52. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  53. data/spec/ffi/spec_helper.rb +5 -1
  54. data/spec/ffi/string_spec.rb +65 -4
  55. data/spec/ffi/struct_callback_spec.rb +41 -0
  56. data/spec/ffi/struct_initialize_spec.rb +30 -0
  57. data/spec/ffi/struct_spec.rb +19 -20
  58. metadata +29 -52
  59. data/ext/ffi_c/ffi.mk +0 -23
@@ -8,14 +8,12 @@ extern "C" {
8
8
  #endif
9
9
 
10
10
  #define MAX_PARAMETERS (32)
11
-
12
- extern void rb_FFI_AbstractMemory_Init(void);
13
- extern void rb_FFI_MemoryPointer_Init(void);
14
- extern void rb_FFI_Buffer_Init(void);
15
- extern void rb_FFI_Callback_Init(void);
16
- extern void rb_FFI_Invoker_Init(void);
17
- extern VALUE rb_FFI_AbstractMemory_class;
18
- extern int rb_FFI_type_size(VALUE type);
11
+
12
+ extern void rbffi_Type_Init(VALUE ffiModule);
13
+ extern void rbffi_Buffer_Init(VALUE ffiModule);
14
+ extern void rbffi_Invoker_Init(VALUE ffiModule);
15
+ extern VALUE rbffi_AbstractMemoryClass, rbffi_InvokerClass;
16
+ extern int rbffi_type_size(VALUE type);
19
17
 
20
18
  #ifdef __cplusplus
21
19
  }
data/lib/ffi.rb CHANGED
@@ -1,2 +1,11 @@
1
- require 'ffi_c'
1
+ begin
2
+ if RUBY_VERSION =~ /1.8/
3
+ require '1.8/ffi_c'
4
+ elsif RUBY_VERSION =~ /1.9/
5
+ require '1.9/ffi_c'
6
+ end
7
+ rescue Exception
8
+ require 'ffi_c'
9
+ end
10
+
2
11
  require 'ffi/ffi'
@@ -28,7 +28,7 @@ module FFI
28
28
  # release(), which by default does nothing.
29
29
  #
30
30
  def initialize(ptr, proc=nil, &block)
31
- raise ArgumentError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
31
+ raise TypeError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
32
32
  || ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer)
33
33
  free_lambda = if proc and proc.is_a? Method
34
34
  AutoPointer.finalize(ptr, AutoPointer.method_to_proc(proc))
@@ -0,0 +1,78 @@
1
+ module FFI
2
+
3
+ class Enums
4
+
5
+ def initialize
6
+ @all_enums = Array.new
7
+ @tagged_enums = Hash.new
8
+ @symbol_map = Hash.new
9
+ end
10
+
11
+ def <<(enum)
12
+ @all_enums << enum
13
+ @tagged_enums[enum.tag] = enum unless enum.tag.nil?
14
+ @symbol_map.merge!(enum.symbol_map)
15
+ end
16
+
17
+ def find(query)
18
+ if @tagged_enums.has_key?(query)
19
+ @tagged_enums[query]
20
+ else
21
+ @all_enums.detect { |enum| enum.symbols.include?(query) }
22
+ end
23
+ end
24
+
25
+ def __map_symbol(symbol)
26
+ @symbol_map[symbol]
27
+ end
28
+
29
+ end
30
+
31
+ class Enum
32
+ attr_reader :tag
33
+
34
+ def initialize(info, tag=nil)
35
+ @tag = tag
36
+ @kv_map = Hash.new
37
+ @vk_map = Hash.new
38
+ unless info.nil?
39
+ last_cst = nil
40
+ value = 0
41
+ info.each do |i|
42
+ case i
43
+ when Symbol
44
+ @kv_map[i] = value
45
+ @vk_map[value] = i
46
+ last_cst = i
47
+ value += 1
48
+ when Integer
49
+ @kv_map[last_cst] = i
50
+ @vk_map[i] = last_cst
51
+ value = i+1
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ def symbols
58
+ @kv_map.keys
59
+ end
60
+
61
+ def [](query)
62
+ case query
63
+ when Symbol
64
+ @kv_map[query]
65
+ when Integer
66
+ @vk_map[query]
67
+ end
68
+ end
69
+ alias find []
70
+
71
+ def symbol_map
72
+ @kv_map
73
+ end
74
+ alias to_h symbol_map
75
+
76
+ end
77
+
78
+ end
@@ -30,8 +30,6 @@ module FFI
30
30
  # Specialised error classes
31
31
  class NativeError < LoadError; end
32
32
 
33
- class TypeError < NativeError; end
34
-
35
33
  class SignatureError < NativeError; end
36
34
 
37
35
  class NotFoundError < NativeError
@@ -54,6 +52,7 @@ require 'ffi/callback'
54
52
  require 'ffi/io'
55
53
  require 'ffi/autopointer'
56
54
  require 'ffi/variadic'
55
+ require 'ffi/enum'
57
56
 
58
57
  module FFI
59
58
 
@@ -67,7 +66,7 @@ module FFI
67
66
  end
68
67
  lib
69
68
  end
70
- def self.create_invoker(lib, name, args, ret, options = { :convention => :default })
69
+ def self.create_invoker(lib, name, args, ret_type, native_ret_type, options = { :convention => :default })
71
70
  # Current artificial limitation based on JRuby::FFI limit
72
71
  raise SignatureError, 'FFI functions may take max 32 arguments!' if args.size > 32
73
72
 
@@ -82,14 +81,14 @@ module FFI
82
81
  else
83
82
  raise LoadError, "Invalid library '#{lib}'"
84
83
  end
85
- function = library.find_symbol(name)
84
+ function = library.find_function(name)
86
85
  raise NotFoundError.new(name, library.name) unless function
87
86
 
88
87
  args = args.map {|e| find_type(e) }
89
88
  if args.length > 0 && args[args.length - 1] == FFI::NativeType::VARARGS
90
- invoker = FFI::VariadicInvoker.new(library, function, args, find_type(ret), options)
89
+ invoker = FFI::VariadicInvoker.new(function, args, ret_type, find_type(native_ret_type), options)
91
90
  else
92
- invoker = FFI::Invoker.new(library, function, args, find_type(ret), options[:convention].to_s)
91
+ invoker = FFI::Invoker.new(function, args, ret_type, find_type(native_ret_type), options[:convention].to_s, options[:enums])
93
92
  end
94
93
  raise NotFoundError.new(name, library.name) unless invoker
95
94
  return invoker
@@ -3,5 +3,19 @@ module FFI
3
3
  def self.for_fd(fd, mode = "r")
4
4
  ::IO.for_fd(fd, mode)
5
5
  end
6
+
7
+ #
8
+ # A version of IO#read that reads into a native buffer
9
+ #
10
+ # This will be optimized at some future time to eliminate the double copy
11
+ #
12
+ def self.native_read(io, buf, len)
13
+ tmp = io.read(len)
14
+ return -1 unless tmp
15
+ buf.put_bytes(0, tmp)
16
+ tmp.length
17
+ end
18
+
6
19
  end
7
- end
20
+ end
21
+
@@ -3,6 +3,7 @@ module FFI::Library
3
3
 
4
4
  def ffi_lib(*names)
5
5
  ffi_libs = []
6
+ errors = {}
6
7
  names.each do |name|
7
8
  [ name, FFI.map_library_name(name) ].each do |libname|
8
9
  begin
@@ -11,11 +12,17 @@ module FFI::Library
11
12
  ffi_libs << lib
12
13
  break
13
14
  end
14
- rescue LoadError => ex
15
+ rescue Exception => ex
16
+ errors[name] = ex
15
17
  end
16
18
  end
17
19
  end
18
- raise LoadError, "Could not open any of [#{names.join(", ")}]" if ffi_libs.empty?
20
+ if ffi_libs.empty?
21
+ msgs = []
22
+ errors.each {|name, ex| msgs << "Failed to load library '#{name}': #{ex.message}" }
23
+ raise LoadError.new(msgs.join('\n'))
24
+ end
25
+
19
26
  @ffi_libs = ffi_libs
20
27
  end
21
28
  def ffi_convention(convention)
@@ -33,20 +40,21 @@ module FFI::Library
33
40
 
34
41
  def attach_function(mname, a3, a4, a5=nil)
35
42
  cname, arg_types, ret_type = a5 ? [ a3, a4, a5 ] : [ mname.to_s, a3, a4 ]
36
- libraries = defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
37
- convention = defined?(@ffi_convention) ? @ffi_convention : :default
38
43
 
39
44
  # Convert :foo to the native type
40
45
  arg_types.map! { |e| find_type(e) }
41
46
  has_callback = arg_types.any? {|t| t.kind_of?(FFI::CallbackInfo)}
42
47
  options = Hash.new
43
- options[:convention] = convention
48
+ options[:convention] = defined?(@ffi_convention) ? @ffi_convention : :default
44
49
  options[:type_map] = @ffi_typedefs if defined?(@ffi_typedefs)
50
+ options[:enums] = @ffi_enums if defined?(@ffi_enums)
51
+
45
52
  # Try to locate the function in any of the libraries
46
53
  invokers = []
54
+ libraries = defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
47
55
  libraries.each do |lib|
48
56
  begin
49
- invokers << FFI.create_invoker(lib, cname.to_s, arg_types, find_type(ret_type), options)
57
+ invokers << FFI.create_invoker(lib, cname.to_s, arg_types, ret_type, find_type(ret_type), options)
50
58
  rescue LoadError => ex
51
59
  end if invokers.empty?
52
60
  end
@@ -87,7 +95,7 @@ module FFI::Library
87
95
  address = nil
88
96
  libraries.each do |lib|
89
97
  begin
90
- address = lib.find_symbol(cname.to_s)
98
+ address = lib.find_variable(cname.to_s)
91
99
  break unless address.nil?
92
100
  rescue LoadError
93
101
  end
@@ -120,7 +128,7 @@ module FFI::Library
120
128
  if ffi_type.is_a?(FFI::CallbackInfo)
121
129
  op = :callback
122
130
  else
123
- raise FFI::TypeError, "Cannot access library variable of type #{type}"
131
+ raise TypeError, "Cannot access library variable of type #{type}"
124
132
  end
125
133
  end
126
134
  #
@@ -150,20 +158,72 @@ module FFI::Library
150
158
  end
151
159
  address
152
160
  end
153
- def callback(name, args, ret)
154
- @ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
155
- @ffi_callbacks[name] = FFI::CallbackInfo.new(find_type(ret), args.map { |e| find_type(e) })
161
+
162
+ def callback(*args)
163
+ raise ArgError, "wrong number of arguments" if args.length < 2 || args.length > 3
164
+ name, params, ret = if args.length == 3
165
+ args
166
+ else
167
+ [ nil, args[0], args[1] ]
168
+ end
169
+ cb = FFI::CallbackInfo.new(find_type(ret), params.map { |e| find_type(e) })
170
+
171
+ # Add to the symbol -> type map (unless there was no name)
172
+ unless name.nil?
173
+ @ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
174
+ @ffi_callbacks[name] = cb
175
+ end
176
+
177
+ cb
156
178
  end
157
- def typedef(current, add)
179
+
180
+ def typedef(current, add, info=nil)
158
181
  @ffi_typedefs = Hash.new unless defined?(@ffi_typedefs)
159
- if current.kind_of? Integer
160
- code = current
182
+ code = if current.kind_of?(FFI::Type)
183
+ current
184
+ elsif current == :enum
185
+ if add.kind_of?(Array)
186
+ self.enum(add)
187
+ else
188
+ self.enum(info, add)
189
+ end
161
190
  else
162
- code = @ffi_typedefs[current] || FFI.find_type(current)
191
+ @ffi_typedefs[current] || FFI.find_type(current)
163
192
  end
164
193
 
165
194
  @ffi_typedefs[add] = code
166
195
  end
196
+
197
+ def enum(*args)
198
+ #
199
+ # enum can be called as:
200
+ # enum :zero, :one, :two # unnamed enum
201
+ # enum [ :zero, :one, :two ] # equivalent to above
202
+ # enum :foo, [ :zero, :one, :two ] create an enum named :foo
203
+ #
204
+ name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array)
205
+ [ args[0], args[1] ]
206
+ elsif args[0].kind_of?(Array)
207
+ [ nil, args[0] ]
208
+ else
209
+ [ nil, args ]
210
+ end
211
+ @ffi_enums = FFI::Enums.new unless defined?(@ffi_enums)
212
+ @ffi_enums << (e = FFI::Enum.new(values, name))
213
+
214
+ # If called as enum :foo, [ :zero, :one, :two ], add a typedef alias
215
+ typedef(e, name) if name
216
+ e
217
+ end
218
+
219
+ def enum_type(name)
220
+ @ffi_enums.find(name) if defined?(@ffi_enums)
221
+ end
222
+
223
+ def enum_value(symbol)
224
+ @ffi_enums.__map_symbol(symbol)
225
+ end
226
+
167
227
  def find_type(name)
168
228
  code = if defined?(@ffi_typedefs) && @ffi_typedefs.has_key?(name)
169
229
  @ffi_typedefs[name]
@@ -171,12 +231,13 @@ module FFI::Library
171
231
  @ffi_callbacks[name]
172
232
  elsif name.is_a?(Class) && name < FFI::Struct
173
233
  FFI::NativeType::POINTER
234
+ elsif name.kind_of?(FFI::Type)
235
+ name
174
236
  end
175
- code = name if !code && name.kind_of?(FFI::CallbackInfo)
176
237
  if code.nil? || code.kind_of?(Symbol)
177
238
  FFI.find_type(name)
178
239
  else
179
240
  code
180
241
  end
181
242
  end
182
- end
243
+ end
@@ -52,13 +52,13 @@ module FFI
52
52
 
53
53
  def read_string(len=nil)
54
54
  if len
55
- get_string(0, len)
55
+ get_bytes(0, len)
56
56
  else
57
57
  get_string(0)
58
58
  end
59
59
  end
60
60
  def read_string_length(len)
61
- get_string(0, len)
61
+ get_bytes(0, len)
62
62
  end
63
63
  def read_string_to_null
64
64
  get_string(0)
@@ -1,5 +1,6 @@
1
1
  require 'ffi/platform'
2
2
  module FFI
3
+
3
4
  class StructLayout
4
5
  attr_reader :size, :align
5
6
 
@@ -13,6 +14,7 @@ module FFI
13
14
  @fields[field_name].offset
14
15
  end
15
16
  end
17
+
16
18
  class StructLayoutBuilder
17
19
  class Field
18
20
  def size
@@ -31,6 +33,7 @@ module FFI
31
33
  const_get(:ALIGN)
32
34
  end
33
35
  end
36
+
34
37
  def self.struct_field_class_from(type)
35
38
  klass_name = type.name.split('::').last
36
39
  code = <<-code
@@ -39,7 +42,7 @@ module FFI
39
42
  class << self
40
43
  attr_reader :info
41
44
  def size
42
- #{type.size} * 8
45
+ #{type.size}
43
46
  end
44
47
  def align
45
48
  #{type.align}
@@ -53,6 +56,7 @@ module FFI
53
56
  code
54
57
  self.module_eval(code)
55
58
  end
59
+
56
60
  def self.array_field_class_from(type, num)
57
61
  klass_name = type.name.split('::').last
58
62
  code = <<-code
@@ -80,22 +84,32 @@ module FFI
80
84
  code
81
85
  self.module_eval(code)
82
86
  end
87
+
83
88
  class CallbackField < Field
84
- def self.size; Platform::ADDRESS_SIZE; end
85
- def self.align; Platform::ADDRESS_ALIGN; end
89
+ def self.size
90
+ FFI::Type::POINTER.size
91
+ end
92
+
93
+ def self.align
94
+ FFI::Type::POINTER.alignment
95
+ end
96
+
86
97
  def put(ptr, proc)
87
98
  ptr.put_callback(@off, proc, @info)
88
99
  end
100
+
89
101
  def get(ptr)
90
102
  raise ArgumentError, "Cannot get callback fields"
91
103
  end
92
104
  end
105
+
93
106
  def initialize
94
107
  @field_names = []
95
108
  @fields = {}
96
109
  @size = 0
97
110
  @min_align = 1
98
111
  end
112
+
99
113
  def native_field_class_from(type)
100
114
  case type
101
115
  when :char, NativeType::INT8
@@ -128,15 +142,19 @@ module FFI
128
142
  StringField
129
143
  end
130
144
  end
145
+
131
146
  def callback_field_class_from(type)
132
147
  return CallbackField, type if type.is_a?(FFI::CallbackInfo)
133
148
  end
149
+
134
150
  def struct_field_class_from(type)
135
151
  self.class.struct_field_class_from(type) if type.is_a?(Class) and type < FFI::Struct
136
152
  end
153
+
137
154
  def array_field_class_from(type)
138
155
  self.class.array_field_class_from(field_class_from(type[0]), type[1]) if type.is_a?(Array)
139
156
  end
157
+
140
158
  def field_class_from(type)
141
159
  field_class = native_field_class_from(type) ||
142
160
  callback_field_class_from(type) ||
@@ -144,24 +162,24 @@ module FFI
144
162
  struct_field_class_from(type)
145
163
  field_class or raise ArgumentError, "Unknown type: #{type}"
146
164
  end
165
+
147
166
  def add_field(name, type, offset = nil)
148
167
  field_class, info = field_class_from(type)
149
168
  off = calc_alignment_of(field_class, offset)
150
- calc_current_size(off, field_class.size / 8)
169
+ calc_current_size(off, field_class.size)
151
170
  @field_names << name
152
171
  @fields[name] = field_class.new(off, info)
153
172
  @min_align = field_class.align if field_class.align > @min_align
154
173
  end
174
+
155
175
  def build
156
- align = @min_align / 8
157
- StructLayout.new @field_names, @fields, align + ((@size - 1) & ~(align - 1)), @min_align
176
+ StructLayout.new(@field_names, @fields, align(@size, @min_align), @min_align)
158
177
  end
159
- def align(offset, bits)
160
- bytes = bits / 8
161
- mask = bytes - 1;
162
- off = offset;
163
- ((off & mask) != 0) ? (off & ~mask) + bytes : off
178
+
179
+ def align(offset, align)
180
+ align + ((offset - 1) & ~(align - 1))
164
181
  end
182
+
165
183
  private
166
184
  def calc_alignment_of(field_class, offset)
167
185
  offset ? offset.to_i : align(@size, field_class.align)
@@ -170,81 +188,112 @@ module FFI
170
188
  @size = offset + size
171
189
  end
172
190
  end
191
+
173
192
  class Struct
174
193
  class Array
175
194
  include Enumerable
195
+
176
196
  def initialize(ptr, type, num)
177
197
  @pointer, @type, @num = ptr, type, num
178
198
  end
179
- def to_ptr
199
+
200
+ def to_ptr
180
201
  @pointer
181
202
  end
203
+
182
204
  def to_a
183
205
  get_array_data(@pointer)
184
206
  end
207
+
185
208
  def size
186
- @num * @type.size / 8
209
+ @num * @type.size
187
210
  end
211
+
188
212
  def each(&blk)
189
213
  to_a.each(&blk)
190
214
  end
215
+
191
216
  private
192
217
  def get_array_data(ptr)
193
218
  (0..@num - 1).inject([]) do |array, index|
194
- array << @type.new(0).get(ptr + index * @type.size / 8)
219
+ array << @type.new(0).get(ptr + index * @type.size)
195
220
  end
196
221
  end
197
222
  end
223
+
198
224
  def self.size
199
225
  @size
200
226
  end
227
+
201
228
  def self.members
202
229
  @layout.members
203
230
  end
231
+
204
232
  def self.align
205
233
  @layout.align
206
234
  end
235
+
207
236
  def self.offsets
208
237
  @layout.offsets
209
238
  end
239
+
210
240
  def self.offset_of(field_name)
211
241
  @layout.offset_of(field_name)
212
242
  end
243
+
213
244
  def size
214
245
  self.class.size
215
246
  end
247
+
216
248
  def align
217
249
  self.class.align
218
250
  end
251
+
219
252
  def members
220
253
  layout.members
221
254
  end
255
+
222
256
  def values
223
257
  layout.members.map { |m| self[m] }
224
258
  end
225
259
  def offsets
226
260
  self.class.offsets
227
261
  end
262
+
228
263
  def offset_of(field_name)
229
264
  self.class.offset_of(field_name)
230
265
  end
266
+
231
267
  def clear
232
268
  pointer.clear
233
269
  self
234
270
  end
271
+
235
272
  def to_ptr
236
273
  pointer
237
274
  end
275
+
238
276
  def self.in
239
277
  :buffer_in
240
278
  end
279
+
241
280
  def self.out
242
281
  :buffer_out
243
282
  end
283
+
284
+ protected
285
+
286
+ def self.callback(params, ret)
287
+ mod = enclosing_module
288
+ FFI::CallbackInfo.new(find_type(ret, mod), params.map { |e| find_type(e, mod) })
289
+ end
290
+
244
291
  private
292
+
245
293
  def self.builder
246
294
  StructLayoutBuilder.new
247
295
  end
296
+
248
297
  def self.enclosing_module
249
298
  begin
250
299
  mod = self.name.split("::")[0..-2].inject(Object) { |obj, c| obj.const_get(c) }
@@ -253,13 +302,16 @@ module FFI
253
302
  nil
254
303
  end
255
304
  end
305
+
256
306
  def self.is_a_struct?(type)
257
307
  type.is_a?(Class) and type < Struct
258
308
  end
309
+
259
310
  def self.find_type(type, mod = nil)
260
311
  return type if is_a_struct?(type) or type.is_a?(::Array)
261
312
  mod ? mod.find_type(type) : FFI.find_type(type)
262
313
  end
314
+
263
315
  def self.hash_layout(spec)
264
316
  raise "Ruby version not supported" if RUBY_VERSION =~ /1.8.*/
265
317
  builder = self.builder
@@ -269,6 +321,7 @@ module FFI
269
321
  end
270
322
  builder.build
271
323
  end
324
+
272
325
  def self.array_layout(spec)
273
326
  builder = self.builder
274
327
  mod = enclosing_module
@@ -288,6 +341,7 @@ module FFI
288
341
  end
289
342
  builder.build
290
343
  end
344
+
291
345
  public
292
346
  def self.layout(*spec)
293
347
  return @layout if spec.size == 0