ffi 0.1.1 → 0.2.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 (62) hide show
  1. data/Rakefile +52 -29
  2. data/ext/AbstractMemory.c +72 -28
  3. data/ext/AutoPointer.c +54 -0
  4. data/ext/AutoPointer.h +18 -0
  5. data/ext/Buffer.c +21 -17
  6. data/ext/Callback.c +81 -43
  7. data/ext/Callback.h +1 -1
  8. data/ext/Invoker.c +465 -108
  9. data/ext/MemoryPointer.c +25 -90
  10. data/ext/NativeLibrary.c +90 -0
  11. data/ext/NativeLibrary.h +22 -0
  12. data/ext/Platform.c +21 -2
  13. data/ext/Pointer.c +107 -0
  14. data/ext/Pointer.h +21 -0
  15. data/ext/Types.c +16 -5
  16. data/ext/Types.h +3 -1
  17. data/ext/compat.h +14 -0
  18. data/ext/extconf.rb +13 -1
  19. data/ext/ffi.c +11 -1
  20. data/ext/ffi.mk +3 -3
  21. data/ext/libffi.darwin.mk +19 -8
  22. data/gen/Rakefile +12 -0
  23. data/lib/ffi/autopointer.rb +61 -0
  24. data/lib/ffi/errno.rb +8 -0
  25. data/lib/ffi/ffi.rb +38 -201
  26. data/lib/ffi/io.rb +7 -0
  27. data/lib/ffi/library.rb +116 -0
  28. data/lib/ffi/managedstruct.rb +55 -0
  29. data/lib/ffi/memorypointer.rb +3 -96
  30. data/lib/ffi/platform.rb +8 -5
  31. data/lib/ffi/pointer.rb +105 -0
  32. data/lib/ffi/struct.rb +97 -42
  33. data/lib/ffi/tools/const_generator.rb +177 -0
  34. data/lib/ffi/tools/generator.rb +58 -0
  35. data/lib/ffi/tools/generator_task.rb +35 -0
  36. data/lib/ffi/tools/struct_generator.rb +194 -0
  37. data/lib/ffi/tools/types_generator.rb +123 -0
  38. data/lib/ffi/types.rb +150 -0
  39. data/lib/ffi/variadic.rb +30 -0
  40. data/nbproject/Makefile-Default.mk +6 -3
  41. data/nbproject/Makefile-impl.mk +5 -5
  42. data/nbproject/Package-Default.bash +72 -0
  43. data/nbproject/configurations.xml +139 -25
  44. data/nbproject/private/configurations.xml +1 -1
  45. data/nbproject/project.xml +4 -0
  46. data/samples/gettimeofday.rb +6 -2
  47. data/samples/inotify.rb +59 -0
  48. data/samples/pty.rb +75 -0
  49. data/specs/buffer_spec.rb +64 -9
  50. data/specs/callback_spec.rb +308 -4
  51. data/specs/errno_spec.rb +13 -0
  52. data/specs/library_spec.rb +55 -0
  53. data/specs/managed_struct_spec.rb +40 -0
  54. data/specs/number_spec.rb +183 -0
  55. data/specs/pointer_spec.rb +126 -0
  56. data/specs/rbx/memory_pointer_spec.rb +7 -7
  57. data/specs/spec_helper.rb +7 -0
  58. data/specs/string_spec.rb +34 -0
  59. data/specs/struct_spec.rb +223 -0
  60. data/specs/typedef_spec.rb +48 -0
  61. data/specs/variadic_spec.rb +84 -0
  62. metadata +270 -237
@@ -0,0 +1,7 @@
1
+ module FFI
2
+ module IO
3
+ def self.for_fd(fd, mode = "r")
4
+ ::IO.for_fd(fd, mode)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,116 @@
1
+ module FFI::Library
2
+ DEFAULT = FFI::DynamicLibrary.open(nil, FFI::DynamicLibrary::RTLD_LAZY)
3
+
4
+ # TODO: Rubinius does *names here and saves the array. Multiple libs?
5
+ def ffi_lib(*names)
6
+ mapped_names = names.map { |name| FFI.map_library_name(name) }
7
+ errors = Hash.new
8
+ ffi_libs = mapped_names.map do |name|
9
+ begin
10
+ FFI::DynamicLibrary.open(name, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_LOCAL)
11
+ rescue LoadError => ex
12
+ errors[name] = ex
13
+ nil
14
+ end
15
+ end.compact
16
+ raise LoadError, "Could not open any of [#{mapped_names.join(", ")}]" if ffi_libs.empty?
17
+ @ffi_libs = ffi_libs
18
+ end
19
+ def ffi_convention(convention)
20
+ @ffi_convention = convention
21
+ end
22
+ ##
23
+ # Attach C function +name+ to this module.
24
+ #
25
+ # If you want to provide an alternate name for the module function, supply
26
+ # it after the +name+, otherwise the C function name will be used.#
27
+ #
28
+ # After the +name+, the C function argument types are provided as an Array.
29
+ #
30
+ # The C function return type is provided last.
31
+
32
+ def attach_function(mname, a3, a4, a5=nil)
33
+ cname, arg_types, ret_type = a5 ? [ a3, a4, a5 ] : [ mname.to_s, a3, a4 ]
34
+ libraries = defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
35
+ convention = defined?(@ffi_convention) ? @ffi_convention : :default
36
+
37
+ # Convert :foo to the native type
38
+ callback_count = 0
39
+ arg_types.map! { |e|
40
+ begin
41
+ find_type(e)
42
+ rescue FFI::TypeError => ex
43
+ if defined?(@ffi_callbacks) && @ffi_callbacks.has_key?(e)
44
+ callback_count += 1
45
+ @ffi_callbacks[e]
46
+ elsif e.is_a?(Class) && e < FFI::Struct
47
+ FFI::NativeType::POINTER
48
+ else
49
+ raise ex
50
+ end
51
+ end
52
+ }
53
+ options = Hash.new
54
+ options[:convention] = convention
55
+ options[:type_map] = @ffi_typedefs if defined?(@ffi_typedefs)
56
+ # Try to locate the function in any of the libraries
57
+ invokers = []
58
+ libraries.each do |lib|
59
+ begin
60
+ invokers << FFI.create_invoker(lib, cname.to_s, arg_types, find_type(ret_type), options)
61
+ rescue LoadError => ex
62
+ end if invokers.empty?
63
+ end
64
+ invoker = invokers.compact.shift
65
+ raise FFI::NotFoundError.new(cname.to_s, libraries.map { |lib| lib.name }) unless invoker
66
+
67
+ # Setup the parameter list for the module function as (a1, a2)
68
+ arity = arg_types.length
69
+ params = (1..arity).map {|i| "a#{i}" }.join(",")
70
+
71
+ # Always use rest args for functions with callback parameters
72
+ if callback_count > 0 || invoker.kind_of?(FFI::VariadicInvoker)
73
+ params = "*args, &block"
74
+ end
75
+ call = arity <= 3 && callback_count < 1 && !invoker.kind_of?(FFI::VariadicInvoker)? "call#{arity}" : "call"
76
+
77
+ #
78
+ # Attach the invoker to this module as 'mname'.
79
+ #
80
+ self.module_eval <<-code
81
+ @@#{mname} = invoker
82
+ def self.#{mname}(#{params})
83
+ @@#{mname}.#{call}(#{params})
84
+ end
85
+ def #{mname}(#{params})
86
+ @@#{mname}.#{call}(#{params})
87
+ end
88
+ code
89
+ invoker
90
+ end
91
+ def callback(name, args, ret)
92
+ @ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
93
+ @ffi_callbacks[name] = FFI::CallbackInfo.new(find_type(ret), args.map { |e| find_type(e) })
94
+ end
95
+ def typedef(current, add)
96
+ @ffi_typedefs = Hash.new unless defined?(@ffi_typedefs)
97
+ if current.kind_of? Integer
98
+ code = current
99
+ else
100
+ code = @ffi_typedefs[current] || FFI.find_type(current)
101
+ end
102
+
103
+ @ffi_typedefs[add] = code
104
+ end
105
+ def find_type(name)
106
+ code = if defined?(@ffi_typedefs)
107
+ @ffi_typedefs[name]
108
+ end
109
+ code = name if !code && name.kind_of?(FFI::CallbackInfo)
110
+ if code.nil? || code.kind_of?(Symbol)
111
+ FFI.find_type(name)
112
+ else
113
+ code
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,55 @@
1
+ module FFI
2
+ #
3
+ # FFI::ManagedStruct allows custom garbage-collection of your FFI::Structs.
4
+ #
5
+ # The typical use case would be when interacting with a library
6
+ # that has a nontrivial memory management design, such as a linked
7
+ # list or a binary tree.
8
+ #
9
+ # When the Struct instance is garbage collected, FFI::ManagedStruct will
10
+ # invoke the class's release() method during object finalization.
11
+ #
12
+ # Example usage:
13
+ # module MyLibrary
14
+ # ffi_lib "libmylibrary"
15
+ # attach_function :new_dlist, [], :pointer
16
+ # attach_function :destroy_dlist, [:pointer], :void
17
+ # end
18
+ #
19
+ # class DoublyLinkedList < FFI::ManagedStruct
20
+ # @@@
21
+ # struct do |s|
22
+ # s.name 'struct dlist'
23
+ # s.include 'dlist.h'
24
+ # s.field :head, :pointer
25
+ # s.field :tail, :pointer
26
+ # end
27
+ # @@@
28
+ #
29
+ # def self.release ptr
30
+ # MyLibrary.destroy_dlist(ptr)
31
+ # end
32
+ # end
33
+ #
34
+ # begin
35
+ # ptr = DoublyLinkedList.new(MyLibrary.new_dlist)
36
+ # # do something with the list
37
+ # end
38
+ # # struct is out of scope, and will be GC'd using DoublyLinkedList#release
39
+ #
40
+ #
41
+ class ManagedStruct < FFI::Struct
42
+
43
+ # call-seq:
44
+ # ManagedStruct.new(pointer)
45
+ # ManagedStruct.new
46
+ #
47
+ # When passed a pointer, create a new ManagedStruct which will invoke the class method release() on
48
+ def initialize(pointer=nil)
49
+ raise NoMethodError, "release() not implemented for class #{self}" unless self.class.respond_to? :release
50
+ raise ArgumentError, "Must supply a pointer to memory for the Struct" unless pointer
51
+ super FFI::AutoPointer.new(pointer, self.class.method(:release))
52
+ end
53
+
54
+ end
55
+ end
@@ -1,3 +1,4 @@
1
+ require 'ffi/pointer'
1
2
  module FFI
2
3
  class MemoryPointer
3
4
  # call-seq:
@@ -69,101 +70,7 @@ module FFI
69
70
  raise ArgumentError, "unknown type size" unless @type_size
70
71
  self + (which * @type_size)
71
72
  end
72
- # Write +obj+ as a C int at the memory pointed to.
73
- def write_int(obj)
74
- put_int32(0, obj)
75
- end
76
-
77
- # Read a C int from the memory pointed to.
78
- def read_int
79
- get_int32(0)
80
- end
81
-
82
- # Write +obj+ as a C long at the memory pointed to.
83
- def write_long(obj)
84
- put_long(0, obj)
85
- end
86
-
87
- # Read a C long from the memory pointed to.
88
- def read_long
89
- get_long(0)
90
- end
91
- # Write +obj+ as a C long long at the memory pointed to.
92
- def write_long_long(obj)
93
- put_int64(0, obj)
94
- end
95
-
96
- # Read a C long long from the memory pointed to.
97
- def read_long_long
98
- get_int64(0)
99
- end
100
- def read_pointer
101
- get_pointer(0)
102
- end
103
- def read_float
104
- get_float32(0)
105
- end
106
- def write_float(obj)
107
- put_float32(0, obj)
108
- end
109
-
110
- def read_string(len=nil)
111
- if len
112
- get_string(0, len)
113
- else
114
- get_string(0)
115
- end
116
- end
117
- def read_string_length(len)
118
- get_string(0, len)
119
- end
120
- def read_string_to_null
121
- get_string(0)
122
- end
123
- def write_string_length(str, len)
124
- put_string(0, str, len)
125
- end
126
- def write_string(str, len=nil)
127
- len = str.size unless len
128
- # Write the string data without NUL termination
129
- put_string(0, str, len)
130
- end
131
- def read_array_of_type(type, reader, length)
132
- ary = []
133
- size = FFI.type_size(type)
134
- tmp = self
135
- length.times {
136
- ary << tmp.send(reader)
137
- tmp += size
138
- }
139
- ary
140
- end
141
-
142
- def write_array_of_type(type, writer, ary)
143
- size = FFI.type_size(type)
144
- tmp = self
145
- ary.each {|i|
146
- tmp.send(writer, i)
147
- tmp += size
148
- }
149
- self
150
- end
151
- def read_array_of_int(length)
152
- get_array_of_int32(0, length)
153
- end
154
-
155
- def write_array_of_int(ary)
156
- put_array_of_int32(0, ary)
157
- end
158
-
159
- def read_array_of_long(length)
160
- get_array_of_long(0, length)
161
- end
162
-
163
- def write_array_of_long(ary)
164
- put_array_of_long(0, ary)
165
- end
166
- end
73
+ end
167
74
  end
168
75
 
169
- MemoryPointer = FFI::MemoryPointer
76
+ MemoryPointer = FFI::MemoryPointer
@@ -20,10 +20,12 @@ module FFI
20
20
  raise FFI::PlatformError, "Unknown operating system: #{OS_}"
21
21
  end
22
22
  ARCH = case CPU.downcase
23
- when /i?86|x86|i86pc/
24
- "i386"
25
23
  when /amd64|x86_64/
26
24
  "x86_64"
25
+ when /i?86|x86|i86pc/
26
+ "i386"
27
+ when /ppc|powerpc/
28
+ "powerpc"
27
29
  else
28
30
  raise FFI::PlatformError, "Unknown cpu architecture: #{ARCH_}"
29
31
  end
@@ -39,6 +41,7 @@ module FFI
39
41
  IS_OPENBSD = is_os("openbsd")
40
42
  IS_WINDOWS = is_os("windows")
41
43
  IS_BSD = IS_MAC || IS_FREEBSD || IS_OPENBSD
44
+ CONF_DIR = File.dirname(__FILE__)
42
45
  public
43
46
  LIBC = if IS_WINDOWS
44
47
  "msvcrt"
@@ -50,11 +53,11 @@ module FFI
50
53
  LIBPREFIX = IS_WINDOWS ? '' : 'lib'
51
54
  LIBSUFFIX = case OS
52
55
  when /darwin/
53
- '.dylib'
56
+ 'dylib'
54
57
  when /linux|bsd|solaris/
55
- '.so'
58
+ 'so'
56
59
  when /win/
57
- '.dll'
60
+ 'dll'
58
61
  else
59
62
  raise PlatformError, "Cannot determine shared library extension for #{OS}"
60
63
  end
@@ -0,0 +1,105 @@
1
+ require 'ffi/platform'
2
+ module FFI
3
+ class Pointer
4
+ SIZE = Platform::ADDRESS_SIZE / 8
5
+
6
+ # Return the size of a pointer on the current platform, in bytes
7
+ def self.size
8
+ SIZE
9
+ end
10
+ # Write +obj+ as a C int at the memory pointed to.
11
+ def write_int(obj)
12
+ put_int32(0, obj)
13
+ end
14
+
15
+ # Read a C int from the memory pointed to.
16
+ def read_int
17
+ get_int32(0)
18
+ end
19
+
20
+ # Write +obj+ as a C long at the memory pointed to.
21
+ def write_long(obj)
22
+ put_long(0, obj)
23
+ end
24
+
25
+ # Read a C long from the memory pointed to.
26
+ def read_long
27
+ get_long(0)
28
+ end
29
+ # Write +obj+ as a C long long at the memory pointed to.
30
+ def write_long_long(obj)
31
+ put_int64(0, obj)
32
+ end
33
+
34
+ # Read a C long long from the memory pointed to.
35
+ def read_long_long
36
+ get_int64(0)
37
+ end
38
+ def read_pointer
39
+ get_pointer(0)
40
+ end
41
+ def read_float
42
+ get_float32(0)
43
+ end
44
+ def write_float(obj)
45
+ put_float32(0, obj)
46
+ end
47
+
48
+ def read_string(len=nil)
49
+ if len
50
+ get_string(0, len)
51
+ else
52
+ get_string(0)
53
+ end
54
+ end
55
+ def read_string_length(len)
56
+ get_string(0, len)
57
+ end
58
+ def read_string_to_null
59
+ get_string(0)
60
+ end
61
+ def write_string_length(str, len)
62
+ put_string(0, str, len)
63
+ end
64
+ def write_string(str, len=nil)
65
+ len = str.size unless len
66
+ # Write the string data without NUL termination
67
+ put_string(0, str, len)
68
+ end
69
+ def read_array_of_type(type, reader, length)
70
+ ary = []
71
+ size = FFI.type_size(type)
72
+ tmp = self
73
+ length.times {
74
+ ary << tmp.send(reader)
75
+ tmp += size
76
+ }
77
+ ary
78
+ end
79
+
80
+ def write_array_of_type(type, writer, ary)
81
+ size = FFI.type_size(type)
82
+ tmp = self
83
+ ary.each {|i|
84
+ tmp.send(writer, i)
85
+ tmp += size
86
+ }
87
+ self
88
+ end
89
+ def read_array_of_int(length)
90
+ get_array_of_int32(0, length)
91
+ end
92
+
93
+ def write_array_of_int(ary)
94
+ put_array_of_int32(0, ary)
95
+ end
96
+
97
+ def read_array_of_long(length)
98
+ get_array_of_long(0, length)
99
+ end
100
+
101
+ def write_array_of_long(ary)
102
+ put_array_of_long(0, ary)
103
+ end
104
+ end
105
+ end
@@ -14,10 +14,6 @@ module FFI
14
14
  end
15
15
  end
16
16
  class StructLayoutBuilder
17
- LONG_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::LONG_SIZE
18
- ADDRESS_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::ADDRESS_SIZE
19
- FLOAT_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::ADDRESS_SIZE
20
- DOUBLE_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::ADDRESS_SIZE
21
17
  class Field
22
18
  def initialize(off)
23
19
  @off = off
@@ -38,6 +34,7 @@ module FFI
38
34
  end
39
35
  class Signed8 < Field
40
36
  def self.size; 8; end
37
+ def self.align; Platform::INT8_ALIGN; end
41
38
  def put(ptr, val)
42
39
  ptr.put_int8(@off, val)
43
40
  end
@@ -47,6 +44,7 @@ module FFI
47
44
  end
48
45
  class Unsigned8 < Field
49
46
  def self.size; 8; end
47
+ def self.align; Platform::INT8_ALIGN; end
50
48
  def put(ptr, val)
51
49
  ptr.put_uint8(@off, val)
52
50
  end
@@ -56,6 +54,7 @@ module FFI
56
54
  end
57
55
  class Signed16 < Field
58
56
  def self.size; 16; end
57
+ def self.align; Platform::INT16_ALIGN; end
59
58
  def put(ptr, val)
60
59
  ptr.put_int16(@off, val)
61
60
  end
@@ -65,6 +64,7 @@ module FFI
65
64
  end
66
65
  class Unsigned16 < Field
67
66
  def self.size; 16; end
67
+ def self.align; Platform::INT16_ALIGN; end
68
68
  def put(ptr, val)
69
69
  ptr.put_uint16(@off, val)
70
70
  end
@@ -74,6 +74,7 @@ module FFI
74
74
  end
75
75
  class Signed32 < Field
76
76
  def self.size; 32; end
77
+ def self.align; Platform::INT32_ALIGN; end
77
78
  def put(ptr, val)
78
79
  ptr.put_int32(@off, val)
79
80
  end
@@ -83,6 +84,7 @@ module FFI
83
84
  end
84
85
  class Unsigned32 < Field
85
86
  def self.size; 32; end
87
+ def self.align; Platform::INT32_ALIGN; end
86
88
  def put(ptr, val)
87
89
  ptr.put_uint32(@off, val)
88
90
  end
@@ -92,7 +94,7 @@ module FFI
92
94
  end
93
95
  class Signed64 < Field
94
96
  def self.size; 64; end
95
- def self.align; LONG_ALIGN; end
97
+ def self.align; Platform::INT64_ALIGN; end
96
98
  def put(ptr, val)
97
99
  ptr.put_int64(@off, val)
98
100
  end
@@ -102,7 +104,7 @@ module FFI
102
104
  end
103
105
  class Unsigned64 < Field
104
106
  def self.size; 64; end
105
- def self.align; LONG_ALIGN; end
107
+ def self.align; Platform::INT64_ALIGN; end
106
108
  def put(ptr, val)
107
109
  ptr.put_uint64(@off, val)
108
110
  end
@@ -110,6 +112,47 @@ module FFI
110
112
  ptr.get_uint64(@off)
111
113
  end
112
114
  end
115
+ class FloatField < Field
116
+ def self.size; Platform::FLOAT_SIZE; end
117
+ def self.align; Platform::FLOAT_ALIGN; end
118
+ def put(ptr, val)
119
+ ptr.put_float32(@off, val)
120
+ end
121
+ def get(ptr)
122
+ ptr.get_float32(@off)
123
+ end
124
+ end
125
+ class DoubleField < Field
126
+ def self.size; Platform::DOUBLE_SIZE; end
127
+ def self.align; Platform::DOUBLE_ALIGN; end
128
+ def put(ptr, val)
129
+ ptr.put_float64(@off, val)
130
+ end
131
+ def get(ptr)
132
+ ptr.get_float64(@off)
133
+ end
134
+ end
135
+ class PointerField < Field
136
+ def self.size; Platform::ADDRESS_SIZE; end
137
+ def self.align; Platform::ADDRESS_ALIGN; end
138
+ def put(ptr, val)
139
+ ptr.put_pointer(@off, val)
140
+ end
141
+ def get(ptr)
142
+ ptr.get_pointer(@off)
143
+ end
144
+ end
145
+ class StringField < Field
146
+ def self.size; Platform::ADDRESS_SIZE; end
147
+ def self.align; Platform::ADDRESS_ALIGN; end
148
+ def put(ptr, val)
149
+ raise ArgumentError, "Cannot set :string fields"
150
+ end
151
+ def get(ptr)
152
+ strp = ptr.get_pointer(@off)
153
+ (strp.nil? || strp.null?) ? nil : strp.get_string(0)
154
+ end
155
+ end
113
156
  def initialize
114
157
  @fields = {}
115
158
  @size = 0
@@ -136,6 +179,14 @@ module FFI
136
179
  Signed64
137
180
  when :ulong_long, NativeType::UINT64
138
181
  Unsigned64
182
+ when :float, NativeType::FLOAT32
183
+ FloatField
184
+ when :double, NativeType::FLOAT64
185
+ DoubleField
186
+ when :pointer, NativeType::POINTER
187
+ PointerField
188
+ when :string, NativeType::STRING
189
+ StringField
139
190
  else
140
191
  raise ArgumentError, "Unknown type: #{type}"
141
192
  end
@@ -202,62 +253,66 @@ module FFI
202
253
  @pointer.clear
203
254
  self
204
255
  end
256
+ def to_ptr
257
+ @pointer
258
+ end
259
+ def self.in
260
+ :buffer_in
261
+ end
262
+ def self.out
263
+ :buffer_out
264
+ end
205
265
  end
206
266
  class Struct < BaseStruct
207
- def self.jruby_layout(spec)
267
+ private
268
+ def self.enclosing_module
269
+ begin
270
+ mod = self.name.split("::")[0..-2].inject(Object) { |obj, c| obj.const_get(c) }
271
+ mod.respond_to?(:find_type) ? mod : nil
272
+ rescue Exception => ex
273
+ nil
274
+ end
275
+ end
276
+ def self.find_type(type, mod = nil)
277
+ return mod ? mod.find_type(type) : FFI.find_type(type)
278
+ end
279
+ def self.hash_layout(spec)
208
280
  raise "Ruby version not supported" if RUBY_VERSION =~ /1.8.*/
209
281
  builder = FFI::StructLayoutBuilder.new
282
+ mod = enclosing_module
210
283
  spec[0].each do |name,type|
211
- builder.add_field(name, FFI.find_type(type))
284
+ builder.add_field(name, find_type(type, mod))
212
285
  end
213
286
  builder.build
214
287
  end
215
- def self.rubinius_layout(spec)
288
+ def self.array_layout(spec)
216
289
  builder = FFI::StructLayoutBuilder.new
290
+ mod = enclosing_module
217
291
  i = 0
218
292
  while i < spec.size
219
- name, type, offset = spec[i, 3]
220
-
221
- code = FFI.find_type(type)
222
- builder.add_field(name, code, offset)
223
- i += 3
293
+ name, type = spec[i, 2]
294
+ i += 2
295
+ code = find_type(type, mod)
296
+ # If the next param is a Fixnu, it specifies the offset
297
+ if spec[i].kind_of?(Fixnum)
298
+ offset = spec[i]
299
+ i += 1
300
+ builder.add_field(name, code, offset)
301
+ else
302
+ builder.add_field(name, code)
303
+ end
224
304
  end
225
305
  builder.build
226
306
  end
307
+ public
227
308
  def self.layout(*spec)
228
-
309
+
229
310
  return @layout if spec.size == 0
230
- cspec = spec[0].kind_of?(Hash) ? jruby_layout(spec) : rubinius_layout(spec)
311
+ cspec = spec[0].kind_of?(Hash) ? hash_layout(spec) : array_layout(spec)
231
312
 
232
313
  @layout = cspec unless self == FFI::Struct
233
314
  @size = cspec.size
234
315
  return cspec
235
316
  end
236
- def self.config(base, *fields)
237
- config = Config::CONFIG
238
- @size = config["#{base}.sizeof"]
239
-
240
- builder = StructLayoutBuilder.new
241
-
242
- fields.each do |field|
243
- offset = config["#{base}.#{field}.offset"]
244
- size = config["#{base}.#{field}.size"]
245
- type = config["#{base}.#{field}.type"]
246
- type = type ? type.to_sym : FFI.size_to_type(size)
247
-
248
- code = FFI.find_type type
249
- if (code == NativeType::CHAR_ARRAY)
250
- builder.add_char_array(field.to_s, size, offset)
251
- else
252
- builder.add_field(field.to_s, code, offset)
253
- end
254
- end
255
- cspec = builder.build
256
-
257
- @layout = cspec
258
- @size = cspec.size if @size < cspec.size
259
-
260
- return cspec
261
- end
262
317
  end
263
318
  end