gir_ffi 0.0.4 → 0.0.5

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/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.0.5 / 2010-12-30
2
+
3
+ * Don't create instance methods out of functions and vice versa.
4
+ * Find signals on interfaces, too.
5
+ * Implement tests for most of Everything.
6
+ * Correctly handle array + size arguments.
7
+ * Handle most other argument types.
8
+ * Various internal changes and other fixes.
9
+
1
10
  == 0.0.4 / 2010-12-14
2
11
 
3
12
  * Lots of changes to the internals.
data/Rakefile CHANGED
@@ -1,21 +1,3 @@
1
- # Look in the tasks/setup.rb file for the various options that can be
2
- # configured in this Rakefile. The .rake files in the tasks directory
3
- # are where the options are used.
4
-
5
1
  load 'tasks/setup.rb'
6
2
 
7
- ensure_in_path 'lib'
8
- require 'gir_ffi'
9
-
10
3
  task :default => 'test:run'
11
-
12
- PROJ.name = 'gir_ffi'
13
- PROJ.authors = 'Matijs van Zuijlen'
14
- PROJ.email = 'matijs@matijs.net'
15
- PROJ.url = 'http://www.github.com/mvz/ruby-gir-ffi'
16
- PROJ.version = GirFFI::VERSION
17
- PROJ.readme_file = 'README.rdoc'
18
-
19
- PROJ.exclude << ["^tmp/", "\\.swp$", "^\\.gitignore$", "^\\.autotest$"]
20
-
21
- # EOF
data/TODO.rdoc CHANGED
@@ -21,7 +21,7 @@ distinguished, based on the GIR data, from methods that take a pointer to
21
21
  any GObject.
22
22
 
23
23
  I'm currently passing the object id as the value of the 'gpointer'. Special
24
- overrided will have to be used for the cases where the 'gpointer' actually
24
+ overrides will have to be used for the cases where the 'gpointer' actually
25
25
  needs to be a GObject. I consider it an omission in GIRepository that these
26
26
  two cases are not distinguished.
27
27
 
@@ -8,68 +8,179 @@ module GirFFI
8
8
  FFI::Pointer.new(obj.object_id)
9
9
  end
10
10
 
11
+ def self.typed_array_to_inptr type, ary
12
+ return nil if ary.nil?
13
+ block = allocate_array_of_type type, ary.length
14
+ block.send "put_array_of_#{type}", 0, ary
15
+ end
16
+
17
+ def self.int32_array_to_inptr ary
18
+ typed_array_to_inptr :int32, ary
19
+ end
20
+
21
+ # TODO: Use alias.
22
+ def self.int_array_to_inptr ary
23
+ int32_array_to_inptr ary
24
+ end
25
+
26
+ def self.int16_array_to_inptr ary
27
+ typed_array_to_inptr :int16, ary
28
+ end
29
+
30
+ def self.int64_array_to_inptr ary
31
+ typed_array_to_inptr :int64, ary
32
+ end
33
+
34
+ def self.int8_array_to_inptr ary
35
+ typed_array_to_inptr :int8, ary
36
+ end
37
+
38
+ def self.utf8_to_inptr str
39
+ return nil if str.nil?
40
+ len = str.bytesize
41
+ AllocationHelper.safe_malloc(len + 1).write_string(str).put_char(len, 0)
42
+ end
43
+
44
+ def self.GType_array_to_inptr ary
45
+ case FFI.type_size(:size_t)
46
+ when 4
47
+ int32_array_to_inptr ary
48
+ when 8
49
+ int64_array_to_inptr ary
50
+ else
51
+ raise RuntimeError, "Unexpected size of :size_t"
52
+ end
53
+ end
54
+
55
+ def self.cleanup_ptr ptr
56
+ LibC.free ptr
57
+ end
58
+
59
+ def self.cleanup_ptr_ptr ptr
60
+ block = ptr.read_pointer
61
+ LibC.free ptr
62
+ LibC.free block
63
+ end
64
+
65
+ # Takes an outptr to a pointer array, and frees all pointers.
66
+ def self.cleanup_ptr_array_ptr ptr, size
67
+ return if ptr.nil?
68
+
69
+ block = ptr.read_pointer
70
+ LibC.free ptr
71
+
72
+ return if block.null?
73
+
74
+ ptrs = block.read_array_of_pointer(size)
75
+ LibC.free block
76
+
77
+ ptrs.map do |p|
78
+ LibC.free p unless p.null?
79
+ end
80
+ end
81
+
11
82
  def self.int_to_inoutptr val
12
- ptr = AllocationHelper.safe_malloc FFI.type_size(:int)
13
- ptr.write_int val
14
- return ptr
83
+ int_pointer.write_int val
84
+ end
85
+
86
+ def self.utf8_to_inoutptr str
87
+ sptr = utf8_to_inptr str
88
+ pointer_pointer.write_pointer sptr
15
89
  end
16
90
 
17
- def self.string_array_to_inoutptr ary
91
+ def self.int_array_to_inoutptr ary
92
+ block = int_array_to_inptr ary
93
+ pointer_pointer.write_pointer block
94
+ end
95
+
96
+ def self.utf8_array_to_inoutptr ary
18
97
  return nil if ary.nil?
19
98
 
20
- ptrs = ary.map {|str|
21
- len = str.bytesize
22
- AllocationHelper.safe_malloc(len + 1).write_string(str).put_char(len, 0)
23
- }
99
+ ptrs = ary.map {|str| utf8_to_inptr str}
24
100
 
25
- ptr_size = FFI.type_size(:pointer)
26
- block = AllocationHelper.safe_malloc ptr_size * ptrs.length
101
+ block = AllocationHelper.safe_malloc FFI.type_size(:pointer) * ptrs.length
27
102
  block.write_array_of_pointer ptrs
28
103
 
29
- argv = AllocationHelper.safe_malloc ptr_size
30
- argv.write_pointer block
31
- argv
104
+ pointer_pointer.write_pointer block
32
105
  end
33
106
 
34
107
  def self.double_to_inoutptr val
35
- ptr = AllocationHelper.safe_malloc FFI.type_size(:double)
36
- ptr.put_double 0, val
37
- return ptr
108
+ double_pointer.put_double 0, val
109
+ end
110
+
111
+ def self.int_pointer
112
+ AllocationHelper.safe_malloc FFI.type_size(:int)
113
+ end
114
+
115
+ def self.double_pointer
116
+ AllocationHelper.safe_malloc FFI.type_size(:double)
117
+ end
118
+
119
+ def self.pointer_pointer
120
+ AllocationHelper.safe_malloc FFI.type_size(:pointer)
121
+ end
122
+
123
+ def self.int_outptr
124
+ int_pointer.write_int 0
38
125
  end
39
126
 
40
- # Converts an outptr to an int, then frees the outptr.
127
+ def self.double_outptr
128
+ double_pointer.write_double 0.0
129
+ end
130
+
131
+ def self.pointer_outptr
132
+ pointer_pointer.write_pointer nil
133
+ end
134
+
135
+ def self.utf8_outptr
136
+ pointer_outptr
137
+ end
138
+
139
+ # Converts an outptr to a pointer.
140
+ def self.outptr_to_pointer ptr
141
+ ptr.read_pointer
142
+ end
143
+
144
+ # Converts an outptr to an int.
41
145
  def self.outptr_to_int ptr
42
- value = ptr.read_int
43
- LibC.free ptr
44
- value
146
+ ptr.read_int
45
147
  end
46
148
 
47
- # Converts an outptr to a string array, then frees pointers.
48
- def self.outptr_to_string_array ptr, size
149
+ # Converts an outptr to a string.
150
+ def self.outptr_to_utf8 ptr
49
151
  return nil if ptr.nil?
152
+ sptr = ptr.read_pointer
50
153
 
51
- block = ptr.read_pointer
52
- LibC.free ptr
154
+ sptr.null? ? nil : sptr.read_string
155
+ end
53
156
 
157
+ # Converts an outptr to a string array.
158
+ def self.outptr_to_utf8_array ptr, size
159
+ return nil if ptr.nil?
160
+ block = ptr.read_pointer
54
161
  return nil if block.null?
55
-
56
162
  ptrs = block.read_array_of_pointer(size)
57
- LibC.free block
58
163
 
59
164
  ptrs.map do |p|
60
- if p.null?
61
- nil
62
- else
63
- p.read_string.tap { LibC.free p }
64
- end
165
+ p.null? ? nil : p.read_string
65
166
  end
66
167
  end
67
168
 
68
- # Converts an outptr to a double, then frees the outptr.
169
+ # Converts an outptr to a double.
69
170
  def self.outptr_to_double ptr
70
- value = ptr.get_double 0
71
- LibC.free ptr
72
- value
171
+ ptr.get_double 0
172
+ end
173
+
174
+ # Converts an outptr to an array of int.
175
+ def self.outptr_to_int_array ptr, size
176
+ return nil if ptr.null?
177
+ block = ptr.read_pointer
178
+ return nil if block.null?
179
+ ptr_to_int_array block, size
180
+ end
181
+
182
+ def self.ptr_to_int_array ptr, size
183
+ ptr.read_array_of_int(size)
73
184
  end
74
185
 
75
186
  def self.mapped_callback_args prc=nil, &block
@@ -104,5 +215,24 @@ module GirFFI
104
215
  GirFFI::GObject.object_ref_sink(gobject)
105
216
  end
106
217
  end
218
+
219
+ def self.check_fixed_array_size size, arr, name
220
+ unless arr.size == size
221
+ raise ArgumentError, "#{name} should have size #{size}"
222
+ end
223
+ end
224
+
225
+ def self.allocate_array_of_type type, length
226
+ AllocationHelper.safe_malloc FFI.type_size(type) * length
227
+ end
228
+
229
+ # FIXME: Quasi-circular dependency on generated module
230
+ def self.object_pointer_to_object optr
231
+ tp = ::GObject.type_from_instance_pointer optr
232
+ gir = GirFFI::IRepository.default
233
+ info = gir.find_by_gtype tp
234
+ klass = GirFFI::Builder.build_class info.namespace, info.name
235
+ klass.wrap optr
236
+ end
107
237
  end
108
238
  end
@@ -31,7 +31,8 @@ module GirFFI
31
31
 
32
32
  def self.ffi_function_argument_types info
33
33
  types = info.args.map do |a|
34
- iarginfo_to_ffitype a
34
+ tp = iarginfo_to_ffitype a
35
+ tp == :string ? :pointer : tp
35
36
  end
36
37
  if info.type == :function
37
38
  types.unshift :pointer if info.method?
@@ -65,8 +66,8 @@ module GirFFI
65
66
  end
66
67
  when :boolean
67
68
  return :bool
68
- when :GType
69
- return :int32
69
+ when :GType, :size
70
+ return :size_t
70
71
  else
71
72
  return tag
72
73
  end
@@ -7,7 +7,6 @@ module GirFFI
7
7
  def_delegators :@struct, :[], :[]=, :to_ptr
8
8
 
9
9
  def initialize(*args)
10
- # TODO: Handle NULL pointer.
11
10
  @struct = ffi_structure.new(*args)
12
11
  end
13
12
 
@@ -19,13 +18,13 @@ module GirFFI
19
18
  self.class.gir_ffi_builder
20
19
  end
21
20
 
22
- def method_missing method, *arguments, &block
21
+ def setup_and_call method, *arguments, &block
23
22
  result = gir_ffi_builder.setup_instance_method method.to_s
24
23
  return super unless result
25
24
  self.send method, *arguments, &block
26
25
  end
27
26
 
28
- def self.method_missing method, *arguments, &block
27
+ def self.setup_and_call method, *arguments, &block
29
28
  result = gir_ffi_builder.setup_method method.to_s
30
29
  return super unless result
31
30
  self.send method, *arguments, &block
@@ -46,6 +45,15 @@ module GirFFI
46
45
 
47
46
  alias_method :_real_new, :new
48
47
  undef new
48
+
49
+ def wrap ptr
50
+ return nil if ptr.nil? or ptr.null?
51
+ _real_new ptr
52
+ end
53
+
54
+ def allocate
55
+ _real_new
56
+ end
49
57
  end
50
58
  end
51
59
  end
@@ -14,21 +14,18 @@ module GirFFI
14
14
  end
15
15
 
16
16
  def setup_method method
17
- definition = prepare_method method.to_s
18
-
19
- return false if definition.nil?
20
-
21
17
  klass = build_class
22
18
  meta = (class << klass; self; end)
23
- meta.class_eval definition
24
19
 
25
- true
20
+ go = method_introspection_data method
21
+ return attach_and_define_method method, go, meta
26
22
  end
27
23
 
28
24
  def setup_instance_method method
29
- definition = prepare_method method.to_s
25
+ go = instance_method_introspection_data method
26
+ result = attach_and_define_method method, go, build_class
30
27
 
31
- if definition.nil?
28
+ unless result
32
29
  if parent
33
30
  return superclass.gir_ffi_builder.setup_instance_method method
34
31
  else
@@ -36,10 +33,6 @@ module GirFFI
36
33
  end
37
34
  end
38
35
 
39
- klass = build_class
40
- klass.class_eval "undef #{method}"
41
- klass.class_eval definition
42
-
43
36
  true
44
37
  end
45
38
 
@@ -47,6 +40,13 @@ module GirFFI
47
40
  info.signals.each do |s|
48
41
  return s if s.name == signal_name
49
42
  end
43
+ if info.type == :object
44
+ info.interfaces.each do |i|
45
+ i.signals.each do |s|
46
+ return s if s.name == signal_name
47
+ end
48
+ end
49
+ end
50
50
  if info.parent
51
51
  return superclass.gir_ffi_builder.find_signal signal_name
52
52
  end
@@ -58,16 +58,11 @@ module GirFFI
58
58
  unless defined? @klass
59
59
  case info.type
60
60
  when :object, :struct
61
- instantiate_class
62
- setup_class unless already_set_up
61
+ instantiate_struct_class
63
62
  when :union
64
63
  instantiate_union_class
65
- setup_class unless already_set_up
66
64
  when :enum, :flags
67
- @klass = optionally_define_constant namespace_module, @classname do
68
- vals = info.values.map {|v| [v.name.to_sym, v.value]}.flatten
69
- lib.enum(@classname.to_sym, vals)
70
- end
65
+ instantiate_enum_class
71
66
  else
72
67
  raise NotImplementedError, "Cannot build classes of type #{info.type}"
73
68
  end
@@ -109,20 +104,29 @@ module GirFFI
109
104
  @lib ||= namespace_module.const_get :Lib
110
105
  end
111
106
 
112
- def instantiate_class
107
+ def instantiate_struct_class
113
108
  @klass = get_or_define_class namespace_module, @classname, superclass
114
109
  @structklass = get_or_define_class @klass, :Struct, FFI::Struct
110
+ setup_class unless already_set_up
115
111
  end
116
112
 
117
113
  def instantiate_union_class
118
114
  @klass = get_or_define_class namespace_module, @classname, superclass
119
115
  @structklass = get_or_define_class @klass, :Struct, FFI::Union
116
+ setup_class unless already_set_up
117
+ end
118
+
119
+ def instantiate_enum_class
120
+ @klass = optionally_define_constant namespace_module, @classname do
121
+ vals = info.values.map {|v| [v.name.to_sym, v.value]}.flatten
122
+ lib.enum(@classname.to_sym, vals)
123
+ end
120
124
  end
121
125
 
122
126
  def setup_class
123
127
  setup_layout
124
128
  setup_constants
125
- setup_instance_methods
129
+ stub_methods
126
130
  setup_gtype_getter
127
131
 
128
132
  setup_vfunc_invokers if info.type == :object
@@ -140,6 +144,8 @@ module GirFFI
140
144
  if fields.empty?
141
145
  if parent
142
146
  return [:parent, superclass.const_get(:Struct), 0]
147
+ else
148
+ return [:dummy, :char, 0]
143
149
  end
144
150
  end
145
151
 
@@ -161,20 +167,24 @@ module GirFFI
161
167
  ffitype
162
168
  end
163
169
 
164
- def setup_instance_methods
170
+ def stub_methods
165
171
  info.methods.each do |m|
166
- @klass.class_eval "
167
- def #{m.name} *args, &block
168
- method_missing :#{m.name}, *args, &block
169
- end
170
- "
172
+ @klass.class_eval method_stub(m.method? ? m.name : "self.#{m.name}", m.name)
171
173
  end
172
174
  end
173
175
 
176
+ def method_stub name, symbol
177
+ "
178
+ def #{name} *args, &block
179
+ setup_and_call :#{symbol}, *args, &block
180
+ end
181
+ "
182
+ end
183
+
174
184
  def setup_gtype_getter
175
185
  getter = info.type_init
176
186
  return if getter.nil? or getter == "intern"
177
- lib.attach_function getter.to_sym, [], :int
187
+ lib.attach_function getter.to_sym, [], :size_t
178
188
  @klass.class_eval "
179
189
  def self.get_gtype
180
190
  ::#{lib}.#{getter}
@@ -200,7 +210,7 @@ module GirFFI
200
210
  return if info.find_method 'new'
201
211
 
202
212
  (class << @klass; self; end).class_eval {
203
- alias_method :new, :_real_new
213
+ alias_method :new, :allocate
204
214
  }
205
215
  end
206
216
 
@@ -217,17 +227,21 @@ module GirFFI
217
227
  info.find_method method
218
228
  end
219
229
 
230
+ def instance_method_introspection_data method
231
+ m = method_introspection_data method
232
+ return !m.nil? && m.method? ? m : nil
233
+ end
234
+
220
235
  def function_definition go
221
236
  FunctionDefinitionBuilder.new(go, lib).generate
222
237
  end
223
238
 
224
- def prepare_method method
225
- go = method_introspection_data method
226
-
227
- return nil if go.nil?
228
-
239
+ def attach_and_define_method method, go, modul
240
+ return false if go.nil?
229
241
  Builder.attach_ffi_function lib, go
230
- function_definition go
242
+ modul.class_eval { remove_method method }
243
+ modul.class_eval function_definition(go)
244
+ true
231
245
  end
232
246
 
233
247
  def gir