ffi 0.3.1 → 0.4.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.
Files changed (76) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +38 -28
  3. data/ext/ffi_c/AbstractMemory.c +74 -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 +42 -24
  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 +152 -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 +27 -20
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +51 -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 +48 -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 +21 -44
  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/gen/Rakefile +12 -0
  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 +79 -18
  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/lib/ffi.rb +10 -1
  47. data/spec/ffi/bool_spec.rb +24 -0
  48. data/spec/ffi/callback_spec.rb +217 -17
  49. data/spec/ffi/enum_spec.rb +164 -0
  50. data/spec/ffi/managed_struct_spec.rb +6 -1
  51. data/spec/ffi/number_spec.rb +30 -0
  52. data/spec/ffi/pointer_spec.rb +33 -8
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  54. data/spec/ffi/spec_helper.rb +5 -1
  55. data/spec/ffi/string_spec.rb +65 -4
  56. data/spec/ffi/struct_callback_spec.rb +41 -0
  57. data/spec/ffi/struct_initialize_spec.rb +30 -0
  58. data/spec/ffi/struct_spec.rb +44 -21
  59. metadata +31 -69
  60. data/ext/ffi_c/ffi.mk +0 -23
  61. data/nbproject/Makefile-Default.mk +0 -57
  62. data/nbproject/Makefile-impl.mk +0 -123
  63. data/nbproject/Package-Default.bash +0 -72
  64. data/nbproject/configurations.xml +0 -293
  65. data/nbproject/private/configurations.xml +0 -22
  66. data/nbproject/private/private.xml +0 -7
  67. data/nbproject/project.properties +0 -0
  68. data/nbproject/project.xml +0 -15
  69. data/samples/getlogin.rb +0 -7
  70. data/samples/getpid.rb +0 -7
  71. data/samples/gettimeofday.rb +0 -17
  72. data/samples/hello.rb +0 -6
  73. data/samples/inotify.rb +0 -59
  74. data/samples/pty.rb +0 -75
  75. data/samples/qsort.rb +0 -20
  76. data/samples/sample_helper.rb +0 -6
data/lib/ffi/struct.rb CHANGED
@@ -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
data/lib/ffi/types.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module FFI
2
2
  # TypeDefs = Hash.new
3
3
  def self.add_typedef(current, add)
4
- if current.kind_of? Integer
4
+ if current.kind_of?(FFI::Type)
5
5
  code = current
6
6
  else
7
7
  code = TypeDefs[current]
@@ -13,8 +13,7 @@ module FFI
13
13
  def self.find_type(name, type_map = nil)
14
14
  type_map = TypeDefs if type_map.nil?
15
15
  code = type_map[name]
16
- code = name if !code && name.kind_of?(Integer)
17
- code = name if !code && name.kind_of?(FFI::CallbackInfo)
16
+ code = name if !code && name.kind_of?(FFI::Type)
18
17
  raise TypeError, "Unable to resolve type '#{name}'" unless code
19
18
  return code
20
19
  end
@@ -92,7 +91,11 @@ module FFI
92
91
  add_typedef(NativeType::BUFFER_IN, :buffer_in)
93
92
  add_typedef(NativeType::BUFFER_OUT, :buffer_out)
94
93
  add_typedef(NativeType::BUFFER_INOUT, :buffer_inout)
94
+
95
95
  add_typedef(NativeType::VARARGS, :varargs)
96
+
97
+ add_typedef(NativeType::ENUM, :enum)
98
+ add_typedef(NativeType::BOOL, :bool)
96
99
 
97
100
  # Use for a C struct with a char [] embedded inside.
98
101
  add_typedef(NativeType::CHAR_ARRAY, :char_array)
data/lib/ffi/variadic.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module FFI
2
2
  class VariadicInvoker
3
- def VariadicInvoker.new(library, function, arg_types, ret_type, options)
4
- invoker = self.__new(library, function, ret_type, options[:convention].to_s)
3
+ def VariadicInvoker.new(function, arg_types, rb_ret_type, ret_type, options)
4
+ invoker = self.__new(function, rb_ret_type, ret_type, options[:convention].to_s, options[:enums])
5
5
  invoker.init(arg_types, options[:type_map])
6
6
  invoker
7
7
  end
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'
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+ describe "Function with primitive boolean arguments and return values" do
3
+ module LibTest
4
+ extend FFI::Library
5
+ ffi_lib TestLibrary::PATH
6
+ attach_function :bool_return_true, [ ], :bool
7
+ attach_function :bool_return_false, [ ], :bool
8
+ attach_function :bool_return_val, [ :bool ], :bool
9
+ attach_function :bool_reverse_val, [ :bool ], :bool
10
+ end
11
+ it "bools" do
12
+ LibTest.bool_return_true.should == true
13
+ LibTest.bool_return_false.should == false
14
+
15
+ LibTest.bool_return_val(true).should == true
16
+ LibTest.bool_return_val(false).should == false
17
+
18
+ LibTest.bool_reverse_val(true).should == false
19
+ LibTest.bool_reverse_val(false).should == true
20
+ end
21
+ it "raise error on invalid types" do
22
+ lambda { LibTest.bool_return_val(nil) }.should raise_error(::TypeError)
23
+ end
24
+ end
@@ -37,21 +37,30 @@ describe "Callback" do
37
37
  callback :cbVrU16, [ ], :ushort
38
38
  callback :cbVrS32, [ ], :int
39
39
  callback :cbVrU32, [ ], :uint
40
+ callback :cbVrL, [ ], :long
41
+ callback :cbVrUL, [ ], :ulong
40
42
  callback :cbVrS64, [ ], :long_long
41
43
  callback :cbVrU64, [ ], :ulong_long
42
44
  callback :cbVrP, [], :pointer
45
+ callback :cbVrZ, [], :bool
43
46
  callback :cbCrV, [ :char ], :void
44
47
  callback :cbSrV, [ :short ], :void
45
48
  callback :cbIrV, [ :int ], :void
49
+ callback :cbLrV, [ :long ], :void
50
+ callback :cbULrV, [ :ulong ], :void
46
51
  callback :cbLrV, [ :long_long ], :void
52
+
47
53
  attach_function :testCallbackVrS8, :testClosureVrB, [ :cbVrS8 ], :char
48
54
  attach_function :testCallbackVrU8, :testClosureVrB, [ :cbVrU8 ], :uchar
49
55
  attach_function :testCallbackVrS16, :testClosureVrS, [ :cbVrS16 ], :short
50
56
  attach_function :testCallbackVrU16, :testClosureVrS, [ :cbVrU16 ], :ushort
51
57
  attach_function :testCallbackVrS32, :testClosureVrI, [ :cbVrS32 ], :int
52
58
  attach_function :testCallbackVrU32, :testClosureVrI, [ :cbVrU32 ], :uint
53
- attach_function :testCallbackVrS64, :testClosureVrL, [ :cbVrS64 ], :long_long
54
- attach_function :testCallbackVrU64, :testClosureVrL, [ :cbVrU64 ], :ulong_long
59
+ attach_function :testCallbackVrL, :testClosureVrL, [ :cbVrL ], :long
60
+ attach_function :testCallbackVrZ, :testClosureVrZ, [ :cbVrZ ], :bool
61
+ attach_function :testCallbackVrUL, :testClosureVrL, [ :cbVrUL ], :ulong
62
+ attach_function :testCallbackVrS64, :testClosureVrLL, [ :cbVrS64 ], :long_long
63
+ attach_function :testCallbackVrU64, :testClosureVrLL, [ :cbVrU64 ], :ulong_long
55
64
  attach_function :testCallbackVrP, :testClosureVrP, [ :cbVrP ], :pointer
56
65
  attach_function :testCallbackCrV, :testClosureBrV, [ :cbCrV, :char ], :void
57
66
  attach_variable :cbVrS8, :gvar_pointer, :cbVrS8
@@ -122,7 +131,6 @@ describe "Callback" do
122
131
  it "returning :ushort (-1)" do
123
132
  LibTest.testCallbackVrU16 { -1 }.should == 0xffff
124
133
  end
125
-
126
134
  it "returning :int (0)" do
127
135
  LibTest.testCallbackVrS32 { 0 }.should == 0
128
136
  end
@@ -136,7 +144,6 @@ describe "Callback" do
136
144
  it "returning :int (-1)" do
137
145
  LibTest.testCallbackVrS32 { -1 }.should == -1
138
146
  end
139
-
140
147
  it "returning :uint (0)" do
141
148
  LibTest.testCallbackVrU32 { 0 }.should == 0
142
149
  end
@@ -153,7 +160,39 @@ describe "Callback" do
153
160
  it "Callback returning :uint (-1)" do
154
161
  LibTest.testCallbackVrU32 { -1 }.should == 0xffffffff
155
162
  end
156
-
163
+ it "returning :long (0)" do
164
+ LibTest.testCallbackVrL { 0 }.should == 0
165
+ end
166
+ it "returning :long (0x7fffffff)" do
167
+ LibTest.testCallbackVrL { 0x7fffffff }.should == 0x7fffffff
168
+ end
169
+ # test wrap around
170
+ it "returning :long (-0x80000000)" do
171
+ LibTest.testCallbackVrL { -0x80000000 }.should == -0x80000000
172
+ end
173
+ it "returning :long (-1)" do
174
+ LibTest.testCallbackVrL { -1 }.should == -1
175
+ end
176
+ it "returning :ulong (0)" do
177
+ LibTest.testCallbackVrUL { 0 }.should == 0
178
+ end
179
+ it "returning :ulong (0x7fffffff)" do
180
+ LibTest.testCallbackVrUL { 0x7fffffff }.should == 0x7fffffff
181
+ end
182
+ # test wrap around
183
+ it "returning :ulong (0x80000000)" do
184
+ LibTest.testCallbackVrUL { 0x80000000 }.should == 0x80000000
185
+ end
186
+ it "returning :ulong (0xffffffff)" do
187
+ LibTest.testCallbackVrUL { 0xffffffff }.should == 0xffffffff
188
+ end
189
+ it "Callback returning :ulong (-1)" do
190
+ if FFI::Platform::LONG_SIZE == 32
191
+ LibTest.testCallbackVrUL { -1 }.should == 0xffffffff
192
+ else
193
+ LibTest.testCallbackVrUL { -1 }.should == 0xffffffffffffffff
194
+ end
195
+ end
157
196
  it "returning :long_long (0)" do
158
197
  LibTest.testCallbackVrS64 { 0 }.should == 0
159
198
  end
@@ -167,11 +206,14 @@ describe "Callback" do
167
206
  it "returning :long_long (-1)" do
168
207
  LibTest.testCallbackVrS64 { -1 }.should == -1
169
208
  end
209
+ it "returning bool" do
210
+ LibTest.testCallbackVrZ { true }.should be_true
211
+ end
170
212
  it "returning :pointer (nil)" do
171
213
  LibTest.testCallbackVrP { nil }.null?.should be_true
172
214
  end
173
215
  it "returning :pointer (MemoryPointer)" do
174
- p = MemoryPointer.new :long
216
+ p = FFI::MemoryPointer.new :long
175
217
  LibTest.testCallbackVrP { p }.should == p
176
218
  end
177
219
 
@@ -187,6 +229,113 @@ describe "Callback" do
187
229
  end
188
230
  end
189
231
 
232
+ describe 'when inlined' do
233
+ it 'could be anonymous' do
234
+ module LibTest
235
+ extend FFI::Library
236
+ attach_function :testCallbackVrS8, :testClosureVrB, [ callback([ ], :char) ], :char
237
+ end
238
+ LibTest.testCallbackVrS8 { 0 }.should == 0
239
+ end
240
+ end
241
+
242
+ describe "as return value" do
243
+
244
+ it "should not blow up when a callback is defined that returns a callback" do
245
+ module LibTest
246
+ extend FFI::Library
247
+ callback :cb_return_type_1, [ :short ], :short
248
+ callback :cb_lookup_1, [ :short ], :cb_return_type_1
249
+ attach_function :testReturnsCallback_1, :testReturnsClosure, [ :cb_lookup_1, :short ], :cb_return_type_1
250
+ end
251
+ end
252
+
253
+ it "should return a callback" do
254
+ module LibTest
255
+ extend FFI::Library
256
+ callback :cb_return_type, [ :int ], :int
257
+ callback :cb_lookup, [ ], :cb_return_type
258
+ attach_function :testReturnsCallback, :testReturnsClosure, [ :cb_lookup, :int ], :int
259
+ end
260
+
261
+ lookup_proc_called = false
262
+ return_proc_called = false
263
+
264
+ return_proc = Proc.new do |a|
265
+ return_proc_called = true
266
+ a * 2
267
+ end
268
+ lookup_proc = Proc.new do
269
+ lookup_proc_called = true
270
+ return_proc
271
+ end
272
+
273
+ val = LibTest.testReturnsCallback(lookup_proc, 0x1234)
274
+ val.should == 0x1234 * 2
275
+ lookup_proc_called.should be_true
276
+ return_proc_called.should be_true
277
+ end
278
+
279
+ it "should return a method callback" do
280
+ module LibTest
281
+ extend FFI::Library
282
+ callback :cb_return_type, [ :int ], :int
283
+ callback :cb_lookup, [ ], :cb_return_type
284
+ attach_function :testReturnsCallback, :testReturnsClosure, [ :cb_lookup, :int ], :int
285
+ end
286
+ module MethodCallback
287
+ def self.lookup
288
+ method(:perform)
289
+ end
290
+ def self.perform num
291
+ num * 2
292
+ end
293
+ end
294
+
295
+ LibTest.testReturnsCallback(MethodCallback.method(:lookup), 0x1234).should == 0x2468
296
+ end
297
+
298
+ it 'should not blow up when a callback takes a callback as argument' do
299
+ module LibTest
300
+ extend FFI::Library
301
+ callback :cb_argument, [ :int ], :int
302
+ callback :cb_with_cb_argument, [ :cb_argument, :int ], :int
303
+ attach_function :testCallbackAsArgument, :testArgumentClosure, [ :cb_with_cb_argument, :int ], :int
304
+ end
305
+ end
306
+ it 'should be able to use the callback argument' do
307
+ module LibTest
308
+ extend FFI::Library
309
+ callback :cb_argument, [ :int ], :int
310
+ callback :cb_with_cb_argument, [ :cb_argument, :int ], :int
311
+ attach_function :testCallbackAsArgument, :testArgumentClosure, [ :cb_with_cb_argument, :cb_argument, :int ], :int
312
+ end
313
+ callback_arg_called = false
314
+ callback_with_callback_arg_called = false
315
+ callback_arg = Proc.new do |val|
316
+ callback_arg_called = true
317
+ val * 2
318
+ end
319
+ callback_with_callback_arg = Proc.new do |cb, val|
320
+ callback_with_callback_arg_called = true
321
+ cb.call(val)
322
+ end
323
+ val = LibTest.testCallbackAsArgument(callback_with_callback_arg, callback_arg, 0xff1)
324
+ val.should == 0xff1 * 2
325
+ callback_arg_called.should be_true
326
+ callback_with_callback_arg_called.should be_true
327
+ end
328
+ it 'function returns callable object' do
329
+ module LibTest
330
+ extend FFI::Library
331
+ callback :funcptr, [ :int ], :int
332
+ attach_function :testReturnsFunctionPointer, [ ], :funcptr
333
+ end
334
+ f = LibTest.testReturnsFunctionPointer
335
+ f.call(3).should == 6
336
+ end
337
+ end
338
+
190
339
  end
191
340
  describe "primitive argument" do
192
341
  #
@@ -199,16 +348,27 @@ describe "primitive argument" do
199
348
  callback :cbU8rV, [ :uchar ], :void
200
349
  callback :cbS16rV, [ :short ], :void
201
350
  callback :cbU16rV, [ :ushort ], :void
351
+
352
+ callback :cbZrV, [ :bool ], :void
202
353
  callback :cbS32rV, [ :int ], :void
203
354
  callback :cbU32rV, [ :uint ], :void
355
+
356
+ callback :cbLrV, [ :long ], :void
357
+ callback :cbULrV, [ :ulong ], :void
358
+
204
359
  callback :cbS64rV, [ :long_long ], :void
205
360
  attach_function :testCallbackCrV, :testClosureBrV, [ :cbS8rV, :char ], :void
206
361
  attach_function :testCallbackU8rV, :testClosureBrV, [ :cbU8rV, :uchar ], :void
207
362
  attach_function :testCallbackSrV, :testClosureSrV, [ :cbS16rV, :short ], :void
208
363
  attach_function :testCallbackU16rV, :testClosureSrV, [ :cbU16rV, :ushort ], :void
364
+ attach_function :testCallbackZrV, :testClosureZrV, [ :cbZrV, :bool ], :void
209
365
  attach_function :testCallbackIrV, :testClosureIrV, [ :cbS32rV, :int ], :void
210
366
  attach_function :testCallbackU32rV, :testClosureIrV, [ :cbU32rV, :uint ], :void
211
- attach_function :testCallbackLrV, :testClosureLrV, [ :cbS64rV, :long_long ], :void
367
+
368
+ attach_function :testCallbackLrV, :testClosureLrV, [ :cbLrV, :long ], :void
369
+ attach_function :testCallbackULrV, :testClosureULrV, [ :cbULrV, :ulong ], :void
370
+
371
+ attach_function :testCallbackLLrV, :testClosureLLrV, [ :cbS64rV, :long_long ], :void
212
372
  end
213
373
  it ":char (0) argument" do
214
374
  v = 0xdeadbeef
@@ -230,7 +390,6 @@ describe "primitive argument" do
230
390
  LibTest.testCallbackCrV(-1) { |i| v = i }
231
391
  v.should == -1
232
392
  end
233
-
234
393
  it ":uchar (0) argument" do
235
394
  v = 0xdeadbeef
236
395
  LibTest.testCallbackU8rV(0) { |i| v = i }
@@ -272,7 +431,6 @@ describe "primitive argument" do
272
431
  LibTest.testCallbackSrV(-1) { |i| v = i }
273
432
  v.should == -1
274
433
  end
275
-
276
434
  it ":ushort (0) argument" do
277
435
  v = 0xdeadbeef
278
436
  LibTest.testCallbackU16rV(0) { |i| v = i }
@@ -293,7 +451,11 @@ describe "primitive argument" do
293
451
  LibTest.testCallbackU16rV(0xffff) { |i| v = i }
294
452
  v.should == 0xffff
295
453
  end
296
-
454
+ it ":bool (true) argument" do
455
+ v = false
456
+ LibTest.testCallbackZrV(true) { |i| v = i }
457
+ v.should be_true
458
+ end
297
459
  it ":int (0) argument" do
298
460
  v = 0xdeadbeef
299
461
  LibTest.testCallbackIrV(0) { |i| v = i }
@@ -314,7 +476,6 @@ describe "primitive argument" do
314
476
  LibTest.testCallbackIrV(-1) { |i| v = i }
315
477
  v.should == -1
316
478
  end
317
-
318
479
  it ":uint (0) argument" do
319
480
  v = 0xdeadbeef
320
481
  LibTest.testCallbackU32rV(0) { |i| v = i }
@@ -335,26 +496,65 @@ describe "primitive argument" do
335
496
  LibTest.testCallbackU32rV(0xffffffff) { |i| v = i }
336
497
  v.should == 0xffffffff
337
498
  end
338
-
339
- it ":long_long (0) argument" do
499
+ it ":long (0) argument" do
340
500
  v = 0xdeadbeef
341
501
  LibTest.testCallbackLrV(0) { |i| v = i }
342
502
  v.should == 0
343
503
  end
504
+ it ":long (0x7fffffff) argument" do
505
+ v = 0xdeadbeef
506
+ LibTest.testCallbackLrV(0x7fffffff) { |i| v = i }
507
+ v.should == 0x7fffffff
508
+ end
509
+ it ":long (-0x80000000) argument" do
510
+ v = 0xdeadbeef
511
+ LibTest.testCallbackLrV(-0x80000000) { |i| v = i }
512
+ v.should == -0x80000000
513
+ end
514
+ it ":long (-1) argument" do
515
+ v = 0xdeadbeef
516
+ LibTest.testCallbackLrV(-1) { |i| v = i }
517
+ v.should == -1
518
+ end
519
+ it ":ulong (0) argument" do
520
+ v = 0xdeadbeef
521
+ LibTest.testCallbackULrV(0) { |i| v = i }
522
+ v.should == 0
523
+ end
524
+ it ":ulong (0x7fffffff) argument" do
525
+ v = 0xdeadbeef
526
+ LibTest.testCallbackULrV(0x7fffffff) { |i| v = i }
527
+ v.should == 0x7fffffff
528
+ end
529
+ it ":ulong (0x80000000) argument" do
530
+ v = 0xdeadbeef
531
+ LibTest.testCallbackULrV(0x80000000) { |i| v = i }
532
+ v.should == 0x80000000
533
+ end
534
+ it ":ulong (0xffffffff) argument" do
535
+ v = 0xdeadbeef
536
+ LibTest.testCallbackULrV(0xffffffff) { |i| v = i }
537
+ v.should == 0xffffffff
538
+ end
539
+ it ":long_long (0) argument" do
540
+ v = 0xdeadbeef
541
+ LibTest.testCallbackLLrV(0) { |i| v = i }
542
+ v.should == 0
543
+ end
344
544
  it ":long_long (0x7fffffffffffffff) argument" do
345
545
  v = 0xdeadbeef
346
- LibTest.testCallbackLrV(0x7fffffffffffffff) { |i| v = i }
546
+ LibTest.testCallbackLLrV(0x7fffffffffffffff) { |i| v = i }
347
547
  v.should == 0x7fffffffffffffff
348
548
  end
349
549
  it ":long_long (-0x8000000000000000) argument" do
350
550
  v = 0xdeadbeef
351
- LibTest.testCallbackLrV(-0x8000000000000000) { |i| v = i }
551
+ LibTest.testCallbackLLrV(-0x8000000000000000) { |i| v = i }
352
552
  v.should == -0x8000000000000000
353
553
  end
354
554
  it ":long_long (-1) argument" do
355
555
  v = 0xdeadbeef
356
- LibTest.testCallbackLrV(-1) { |i| v = i }
556
+ LibTest.testCallbackLLrV(-1) { |i| v = i }
357
557
  v.should == -1
358
558
  end
359
559
 
360
- end unless true
560
+ end # unless true