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.
- data/README.rdoc +51 -1
- data/Rakefile +38 -28
- data/ext/ffi_c/AbstractMemory.c +74 -70
- data/ext/ffi_c/AbstractMemory.h +8 -4
- data/ext/ffi_c/AutoPointer.c +8 -9
- data/ext/ffi_c/AutoPointer.h +2 -2
- data/ext/ffi_c/Buffer.c +42 -24
- data/ext/ffi_c/Callback.c +85 -33
- data/ext/ffi_c/Callback.h +11 -5
- data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
- data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
- data/ext/ffi_c/Invoker.c +152 -192
- data/ext/ffi_c/LastError.c +135 -0
- data/ext/ffi_c/LastError.h +18 -0
- data/ext/ffi_c/MemoryPointer.c +27 -20
- data/ext/ffi_c/MemoryPointer.h +3 -3
- data/ext/ffi_c/NullPointer.c +51 -47
- data/ext/ffi_c/Platform.c +9 -10
- data/ext/ffi_c/Platform.h +1 -1
- data/ext/ffi_c/Pointer.c +52 -21
- data/ext/ffi_c/Pointer.h +8 -6
- data/ext/ffi_c/Struct.c +70 -61
- data/ext/ffi_c/Struct.h +2 -2
- data/ext/ffi_c/Type.c +230 -0
- data/ext/ffi_c/Type.h +28 -0
- data/ext/ffi_c/Types.c +48 -6
- data/ext/ffi_c/Types.h +8 -2
- data/ext/ffi_c/endian.h +40 -0
- data/ext/ffi_c/extconf.rb +6 -5
- data/ext/ffi_c/ffi.c +21 -44
- data/ext/ffi_c/libffi.bsd.mk +34 -0
- data/ext/ffi_c/libffi.darwin.mk +30 -10
- data/ext/ffi_c/libffi.gnu.mk +29 -0
- data/ext/ffi_c/libffi.mk +4 -2
- data/ext/ffi_c/rbffi.h +6 -8
- data/gen/Rakefile +12 -0
- data/lib/ffi/autopointer.rb +1 -1
- data/lib/ffi/enum.rb +78 -0
- data/lib/ffi/ffi.rb +5 -6
- data/lib/ffi/io.rb +15 -1
- data/lib/ffi/library.rb +79 -18
- data/lib/ffi/pointer.rb +2 -2
- data/lib/ffi/struct.rb +68 -14
- data/lib/ffi/types.rb +6 -3
- data/lib/ffi/variadic.rb +2 -2
- data/lib/ffi.rb +10 -1
- data/spec/ffi/bool_spec.rb +24 -0
- data/spec/ffi/callback_spec.rb +217 -17
- data/spec/ffi/enum_spec.rb +164 -0
- data/spec/ffi/managed_struct_spec.rb +6 -1
- data/spec/ffi/number_spec.rb +30 -0
- data/spec/ffi/pointer_spec.rb +33 -8
- data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
- data/spec/ffi/spec_helper.rb +5 -1
- data/spec/ffi/string_spec.rb +65 -4
- data/spec/ffi/struct_callback_spec.rb +41 -0
- data/spec/ffi/struct_initialize_spec.rb +30 -0
- data/spec/ffi/struct_spec.rb +44 -21
- metadata +31 -69
- data/ext/ffi_c/ffi.mk +0 -23
- data/nbproject/Makefile-Default.mk +0 -57
- data/nbproject/Makefile-impl.mk +0 -123
- data/nbproject/Package-Default.bash +0 -72
- data/nbproject/configurations.xml +0 -293
- data/nbproject/private/configurations.xml +0 -22
- data/nbproject/private/private.xml +0 -7
- data/nbproject/project.properties +0 -0
- data/nbproject/project.xml +0 -15
- data/samples/getlogin.rb +0 -7
- data/samples/getpid.rb +0 -7
- data/samples/gettimeofday.rb +0 -17
- data/samples/hello.rb +0 -6
- data/samples/inotify.rb +0 -59
- data/samples/pty.rb +0 -75
- data/samples/qsort.rb +0 -20
- 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}
|
|
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
|
|
85
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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?
|
|
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?(
|
|
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(
|
|
4
|
-
invoker = self.__new(
|
|
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
|
@@ -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
|
data/spec/ffi/callback_spec.rb
CHANGED
|
@@ -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 :
|
|
54
|
-
attach_function :
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|