gir_ffi 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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