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.
- data/README.rdoc +51 -1
- data/Rakefile +34 -26
- data/ext/ffi_c/AbstractMemory.c +73 -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 +19 -20
- 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 +148 -192
- data/ext/ffi_c/LastError.c +135 -0
- data/ext/ffi_c/LastError.h +18 -0
- data/ext/ffi_c/MemoryPointer.c +26 -19
- data/ext/ffi_c/MemoryPointer.h +3 -3
- data/ext/ffi_c/NullPointer.c +49 -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 +47 -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 +20 -43
- 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/lib/ffi.rb +10 -1
- 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 +78 -17
- 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/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 +19 -20
- metadata +29 -52
- data/ext/ffi_c/ffi.mk +0 -23
data/ext/ffi_c/rbffi.h
CHANGED
@@ -8,14 +8,12 @@ extern "C" {
|
|
8
8
|
#endif
|
9
9
|
|
10
10
|
#define MAX_PARAMETERS (32)
|
11
|
-
|
12
|
-
extern void
|
13
|
-
extern void
|
14
|
-
extern void
|
15
|
-
extern
|
16
|
-
extern
|
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
data/lib/ffi/autopointer.rb
CHANGED
@@ -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
|
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))
|
data/lib/ffi/enum.rb
ADDED
@@ -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
|
data/lib/ffi/ffi.rb
CHANGED
@@ -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,
|
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.
|
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(
|
89
|
+
invoker = FFI::VariadicInvoker.new(function, args, ret_type, find_type(native_ret_type), options)
|
91
90
|
else
|
92
|
-
invoker = FFI::Invoker.new(
|
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
|
data/lib/ffi/io.rb
CHANGED
@@ -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
|
+
|
data/lib/ffi/library.rb
CHANGED
@@ -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
|
15
|
+
rescue Exception => ex
|
16
|
+
errors[name] = ex
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
18
|
-
|
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] =
|
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.
|
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
|
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
|
-
|
154
|
-
|
155
|
-
|
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
|
-
|
179
|
+
|
180
|
+
def typedef(current, add, info=nil)
|
158
181
|
@ffi_typedefs = Hash.new unless defined?(@ffi_typedefs)
|
159
|
-
if current.kind_of?
|
160
|
-
|
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
|
-
|
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
|
data/lib/ffi/pointer.rb
CHANGED
@@ -52,13 +52,13 @@ module FFI
|
|
52
52
|
|
53
53
|
def read_string(len=nil)
|
54
54
|
if len
|
55
|
-
|
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
|
-
|
61
|
+
get_bytes(0, len)
|
62
62
|
end
|
63
63
|
def read_string_to_null
|
64
64
|
get_string(0)
|
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
|