gir_ffi 0.10.2 → 0.11.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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +13 -0
  3. data/Gemfile +9 -4
  4. data/README.md +3 -2
  5. data/Rakefile +2 -1
  6. data/lib/ffi-glib/byte_array.rb +1 -1
  7. data/lib/ffi-glib/main_loop.rb +2 -1
  8. data/lib/ffi-glib/strv.rb +5 -2
  9. data/lib/ffi-glib/variant.rb +3 -5
  10. data/lib/ffi-glib.rb +4 -0
  11. data/lib/ffi-gobject/closure.rb +8 -10
  12. data/lib/ffi-gobject/object.rb +9 -6
  13. data/lib/ffi-gobject/param_spec.rb +4 -0
  14. data/lib/ffi-gobject/value.rb +13 -16
  15. data/lib/ffi-gobject_introspection/gobject_type_init.rb +18 -0
  16. data/lib/ffi-gobject_introspection/i_callable_info.rb +1 -5
  17. data/lib/ffi-gobject_introspection/i_constant_info.rb +3 -3
  18. data/lib/ffi-gobject_introspection/i_repository.rb +3 -47
  19. data/lib/ffi-gobject_introspection/i_vfunc_info.rb +3 -11
  20. data/lib/ffi-gobject_introspection/lib.rb +8 -31
  21. data/lib/{gir_ffi-base/glib → ffi-gobject_introspection}/strv.rb +9 -13
  22. data/lib/ffi-gobject_introspection.rb +47 -2
  23. data/lib/gir_ffi/allocation_helper.rb +1 -19
  24. data/lib/gir_ffi/arg_helper.rb +36 -26
  25. data/lib/{gir_ffi-base/glib → gir_ffi}/boolean.rb +7 -5
  26. data/lib/gir_ffi/boxed_base.rb +5 -23
  27. data/lib/gir_ffi/builder.rb +3 -3
  28. data/lib/gir_ffi/builders/argument_builder.rb +7 -8
  29. data/lib/gir_ffi/builders/base_argument_builder.rb +0 -1
  30. data/lib/gir_ffi/builders/callback_argument_builder.rb +2 -2
  31. data/lib/gir_ffi/builders/callback_return_value_builder.rb +21 -13
  32. data/lib/gir_ffi/builders/field_builder.rb +4 -10
  33. data/lib/gir_ffi/builders/module_builder.rb +6 -4
  34. data/lib/gir_ffi/builders/object_builder.rb +16 -16
  35. data/lib/gir_ffi/builders/struct_builder.rb +4 -6
  36. data/lib/gir_ffi/builders/struct_like.rb +1 -1
  37. data/lib/gir_ffi/builders/user_defined_builder.rb +83 -23
  38. data/lib/gir_ffi/builders/vfunc_argument_builder.rb +12 -17
  39. data/lib/gir_ffi/class_base.rb +0 -4
  40. data/lib/gir_ffi/core.rb +16 -13
  41. data/lib/gir_ffi/enum_base.rb +2 -41
  42. data/lib/gir_ffi/enum_like_base.rb +48 -0
  43. data/lib/gir_ffi/ffi_ext/pointer.rb +1 -1
  44. data/lib/gir_ffi/flags_base.rb +2 -41
  45. data/lib/gir_ffi/in_out_pointer.rb +1 -1
  46. data/lib/gir_ffi/in_pointer.rb +4 -4
  47. data/lib/gir_ffi/info_ext/i_type_info.rb +14 -5
  48. data/lib/gir_ffi/info_ext/i_vfunc_info.rb +8 -0
  49. data/lib/gir_ffi/module_base.rb +4 -0
  50. data/lib/gir_ffi/receiver_argument_info.rb +1 -1
  51. data/lib/gir_ffi/sized_array.rb +6 -6
  52. data/lib/gir_ffi/struct_base.rb +1 -6
  53. data/lib/gir_ffi/struct_like_base.rb +54 -45
  54. data/lib/gir_ffi/type_map.rb +6 -7
  55. data/lib/gir_ffi/union_base.rb +1 -1
  56. data/lib/gir_ffi/{user_defined_type_info.rb → user_defined_object_info.rb} +1 -2
  57. data/lib/gir_ffi/user_defined_property_info.rb +80 -2
  58. data/lib/gir_ffi/version.rb +1 -1
  59. data/lib/gir_ffi-base/gobject/lib.rb +0 -1
  60. data/lib/gir_ffi-base/gobject.rb +3 -5
  61. data/lib/gir_ffi-base.rb +3 -8
  62. data/tasks/test.rake +17 -3
  63. data/test/base_test_helper.rb +39 -23
  64. data/test/ffi-glib/closure_test.rb +37 -0
  65. data/test/ffi-glib/main_loop_test.rb +24 -0
  66. data/test/ffi-glib/ruby_closure_test.rb +0 -5
  67. data/test/ffi-gobject/object_test.rb +6 -10
  68. data/test/ffi-gobject/param_spec_test.rb +17 -5
  69. data/test/ffi-gobject/value_test.rb +15 -6
  70. data/test/ffi-gobject_introspection/gobject_type_init_test.rb +25 -0
  71. data/test/ffi-gobject_introspection/i_base_info_test.rb +1 -1
  72. data/test/ffi-gobject_introspection/i_repository_test.rb +18 -0
  73. data/test/ffi-gobject_introspection/i_vfunc_info_test.rb +40 -0
  74. data/test/{gir_ffi-base/glib → ffi-gobject_introspection}/strv_test.rb +8 -8
  75. data/test/gir_ffi/allocation_helper_test.rb +35 -0
  76. data/test/gir_ffi/arg_helper_test.rb +102 -7
  77. data/test/gir_ffi/boolean_test.rb +34 -0
  78. data/test/gir_ffi/boxed_base_test.rb +46 -6
  79. data/test/gir_ffi/builder_test.rb +88 -29
  80. data/test/gir_ffi/builders/argument_builder_test.rb +19 -0
  81. data/test/gir_ffi/builders/callback_argument_builder_test.rb +17 -0
  82. data/test/gir_ffi/builders/callback_return_value_builder_test.rb +1 -1
  83. data/test/gir_ffi/builders/field_builder_test.rb +2 -1
  84. data/test/gir_ffi/builders/struct_builder_test.rb +42 -25
  85. data/test/gir_ffi/builders/user_defined_builder_test.rb +365 -17
  86. data/test/gir_ffi/builders/vfunc_argument_builder_test.rb +100 -0
  87. data/test/gir_ffi/builders/vfunc_builder_test.rb +5 -3
  88. data/test/{gir_ffi_test.rb → gir_ffi/core_test.rb} +8 -6
  89. data/test/gir_ffi/in_out_pointer_test.rb +1 -1
  90. data/test/gir_ffi/receiver_argument_info_test.rb +32 -0
  91. data/test/gir_ffi/sized_array_test.rb +34 -0
  92. data/test/gir_ffi/struct_base_test.rb +4 -32
  93. data/test/gir_ffi/struct_like_base_test.rb +164 -0
  94. data/test/gir_ffi/union_base_test.rb +4 -20
  95. data/test/gir_ffi/{user_defined_type_info_test.rb → user_defined_object_info_test.rb} +10 -10
  96. data/test/gir_ffi/user_defined_property_info_test.rb +22 -5
  97. data/test/gir_ffi/version_test.rb +1 -1
  98. data/test/integration/callback_exceptions_test.rb +2 -0
  99. data/test/integration/derived_classes_test.rb +2 -0
  100. data/test/integration/generated_everything_test.rb +22 -0
  101. data/test/integration/generated_gimarshallingtests_test.rb +23 -21
  102. data/test/integration/generated_gio_test.rb +2 -0
  103. data/test/integration/generated_glib_test.rb +2 -0
  104. data/test/integration/generated_gst_test.rb +2 -0
  105. data/test/integration/generated_gtop_test.rb +2 -0
  106. data/test/integration/generated_regress_test.rb +113 -29
  107. data/test/integration/generated_secret_test.rb +2 -0
  108. data/test/integration/generated_warnlib_test.rb +2 -0
  109. data/test/integration/method_lookup_test.rb +2 -0
  110. data/test/introspection_test_helper.rb +15 -0
  111. metadata +21 -27
  112. data/lib/gir_ffi-base/glib.rb +0 -8
  113. data/test/gir_ffi-base/glib/boolean_test.rb +0 -34
@@ -10,45 +10,28 @@ module GirFFI
10
10
  module ArgHelper
11
11
  OBJECT_STORE = ObjectStore.new
12
12
 
13
- def self.ptr_to_utf8_length(ptr, len)
14
- ptr.null? ? nil : ptr.read_string(len)
15
- end
16
-
17
13
  def self.check_error(errpp)
18
14
  err = GLib::Error.wrap(errpp.read_pointer)
19
15
  raise GLibError, err if err
20
16
  end
21
17
 
22
18
  def self.check_fixed_array_size(size, arr, name)
23
- unless arr.size == size
19
+ unless arr.size.equal? size
24
20
  raise ArgumentError, "#{name} should have size #{size}"
25
21
  end
26
22
  end
27
23
 
28
- def self.cast_from_pointer(type, it)
24
+ # NOTE: Only used in List, SList and HashTable classes.
25
+ # TODO: Stop using basic types and instead cast type to an ITypeInfo
26
+ # look-alike.
27
+ def self.cast_from_pointer(type, ptr)
29
28
  case type
30
- when :utf8, :filename
31
- it.to_utf8
32
- when :gint32, :gint8
33
- cast_pointer_to_int32 it
29
+ when Symbol
30
+ cast_from_simple_type_pointer(type, ptr)
34
31
  when Class
35
- type.wrap it
36
- when :guint32
37
- it.address
32
+ type.wrap ptr
38
33
  when Array
39
- main_type, subtype = *type
40
- raise "Unexpected main type #{main_type}" if main_type != :pointer
41
- case subtype
42
- when Array
43
- container_type, *element_type = *subtype
44
- raise "Unexpected container type #{container_type}" if container_type != :ghash
45
- GLib::HashTable.wrap(element_type, it)
46
- else
47
- raise "Unexpected subtype #{subtype}"
48
- end
49
-
50
- else
51
- raise "Don't know how to cast #{type}"
34
+ cast_from_complex_type_pointer(type, ptr)
52
35
  end
53
36
  end
54
37
 
@@ -67,5 +50,32 @@ module GirFFI
67
50
  def self.store(obj)
68
51
  OBJECT_STORE.store(obj)
69
52
  end
53
+
54
+ def self.cast_from_simple_type_pointer(type, ptr)
55
+ case type
56
+ when :utf8, :filename
57
+ ptr.to_utf8
58
+ when :gint32, :gint8
59
+ cast_pointer_to_int32 ptr
60
+ when :guint32
61
+ ptr.address
62
+ else
63
+ raise "Don't know how to cast #{type}"
64
+ end
65
+ end
66
+
67
+ def self.cast_from_complex_type_pointer(type, ptr)
68
+ main_type, (container_type, *element_type) = *type
69
+ case main_type
70
+ when :pointer
71
+ case container_type
72
+ when :ghash
73
+ return GLib::HashTable.wrap(element_type, ptr)
74
+ end
75
+ end
76
+ raise "Don't know how to cast #{type}"
77
+ end
78
+
79
+ private_class_method :cast_from_complex_type_pointer, :cast_from_simple_type_pointer
70
80
  end
71
81
  end
@@ -1,19 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
  require 'ffi'
3
- require 'gir_ffi-base/glib'
4
3
 
5
- module GLib
6
- # Implementation of gboolean
4
+ module GirFFI
5
+ # Class representing a boolean (natively, an int).
7
6
  class Boolean
8
7
  extend FFI::DataConverter
9
8
  native_type FFI::Type::INT
10
9
 
10
+ FROM_NATIVE = { 0 => false, 1 => true }.freeze
11
+ TO_NATIVE = FROM_NATIVE.invert
12
+
11
13
  def self.from_native(value, _context)
12
- value != 0 ? true : false
14
+ FROM_NATIVE.fetch(value)
13
15
  end
14
16
 
15
17
  def self.to_native(value, _context)
16
- value ? 1 : 0
18
+ TO_NATIVE.fetch(value)
17
19
  end
18
20
 
19
21
  def self.size
@@ -5,50 +5,32 @@ module GirFFI
5
5
  # Base class for generated classes representing boxed types.
6
6
  class BoxedBase < StructBase
7
7
  def initialize
8
- store_pointer(self.class::Struct.new.to_ptr)
8
+ store_pointer(nil)
9
9
  end
10
10
 
11
- def self.make_finalizer(struct, gtype)
11
+ def self.make_finalizer(struct)
12
12
  proc do
13
13
  if struct.owned?
14
- struct.owned = false
14
+ struct.owned = nil
15
15
  GObject.boxed_free gtype, struct.to_ptr
16
16
  end
17
17
  end
18
18
  end
19
19
 
20
- # Wrap value and take ownership of it
21
- def self.wrap_own(val)
22
- wrap(val).tap { |it| it && it.struct.owned = true }
23
- end
24
-
25
- # Create an unowned copy of the struct represented by val
26
- def self.copy_from(val)
27
- copy from(val)
28
- end
29
-
30
- # Wrap an owned copy of the struct represented by val
31
- def self.wrap_copy(val)
32
- # TODO: Is this needed? We may get away with just copying on transfer away from us.
33
- copy(wrap(val)).tap { |it| it && it.struct.owned = true }
34
- end
35
-
36
20
  def self.copy(val)
37
- return unless val
38
21
  ptr = GObject.boxed_copy(gtype, val)
39
22
  wrap(ptr)
40
23
  end
41
24
 
42
25
  private
43
26
 
44
- def store_pointer(ptr)
27
+ def store_pointer(*)
45
28
  super
46
29
  make_finalizer
47
30
  end
48
31
 
49
32
  def make_finalizer
50
- gtype = self.class.gtype
51
- ObjectSpace.define_finalizer self, self.class.make_finalizer(@struct, gtype)
33
+ ObjectSpace.define_finalizer self, self.class.make_finalizer(struct)
52
34
  end
53
35
  end
54
36
  end
@@ -29,9 +29,9 @@ module GirFFI
29
29
  end
30
30
 
31
31
  def self.build_module(namespace, version = nil)
32
- module_name = namespace.gsub(/^./, &:upcase)
33
- if Kernel.const_defined? module_name
34
- modul = Kernel.const_get module_name
32
+ module_name = namespace.sub(/\A./, &:upcase)
33
+ if const_defined? module_name
34
+ modul = const_get module_name
35
35
  unless modul.const_defined? :GIR_FFI_BUILDER
36
36
  raise "The module #{module_name} was already defined elsewhere"
37
37
  end
@@ -14,7 +14,6 @@ module GirFFI
14
14
  name if has_input_value? && !helper_argument?
15
15
  end
16
16
 
17
- # TODO: Improve this so each method can only have one block argument.
18
17
  def block_argument?
19
18
  specialized_type_tag == :callback
20
19
  end
@@ -90,7 +89,7 @@ module GirFFI
90
89
  base = pointer_to_value_method_call call_argument_name, type_spec
91
90
  if needs_out_conversion?
92
91
  outgoing_convertor(base).conversion
93
- elsif allocated_by_them?
92
+ elsif allocated_by_them? && specialized_type_tag != :void
94
93
  pointer_to_value_method_call base, sub_type_spec
95
94
  else
96
95
  base
@@ -98,7 +97,7 @@ module GirFFI
98
97
  end
99
98
 
100
99
  def outgoing_convertor(base)
101
- FullCToRubyConvertor.new(@type_info, base, length_argument_name,
100
+ FullCToRubyConvertor.new(type_info, base, length_argument_name,
102
101
  ownership_transfer: @arginfo.ownership_transfer)
103
102
  end
104
103
 
@@ -111,11 +110,11 @@ module GirFFI
111
110
  end
112
111
 
113
112
  def needs_out_conversion?
114
- @type_info.needs_c_to_ruby_conversion_for_functions?
113
+ type_info.needs_c_to_ruby_conversion_for_functions?
115
114
  end
116
115
 
117
116
  def gvalue?
118
- @type_info.gvalue?
117
+ type_info.gvalue?
119
118
  end
120
119
 
121
120
  # Check if an out argument needs to be allocated by them, the callee. Since
@@ -123,7 +122,7 @@ module GirFFI
123
122
  # is a pointer. For example, an out parameter of type gint8* will always
124
123
  # be allocated by the caller (that's us).
125
124
  def allocated_by_them?
126
- !@arginfo.caller_allocates? && @type_info.pointer?
125
+ !@arginfo.caller_allocates? && type_info.pointer?
127
126
  end
128
127
 
129
128
  def length_argument_name
@@ -197,8 +196,8 @@ module GirFFI
197
196
  NullConvertor.new(DESTROY_NOTIFIER)
198
197
  elsif closure?
199
198
  ClosureToPointerConvertor.new(pre_convertor_argument, @is_closure)
200
- elsif @type_info.needs_ruby_to_c_conversion_for_functions?
201
- RubyToCConvertor.new(@type_info, pre_convertor_argument,
199
+ elsif type_info.needs_ruby_to_c_conversion_for_functions?
200
+ RubyToCConvertor.new(type_info, pre_convertor_argument,
202
201
  ownership_transfer: ownership_transfer)
203
202
  else
204
203
  NullConvertor.new(pre_convertor_argument)
@@ -38,7 +38,6 @@ module GirFFI
38
38
  end
39
39
 
40
40
  def specialized_type_tag
41
- # SMELL: Law of Demeter, due to this being arginfo.argument_type.flattened_tag
42
41
  type_info.flattened_tag
43
42
  end
44
43
 
@@ -144,8 +144,8 @@ module GirFFI
144
144
 
145
145
  def out_parameter_preparation
146
146
  value = if allocated_by_us?
147
- ffi_type = TypeMap.type_specification_to_ffi_type type_spec[1]
148
- "GirFFI::AllocationHelper.allocate(#{ffi_type.inspect})" \
147
+ ffi_type = TypeMap.type_specification_to_ffi_type type_spec.last
148
+ "FFI::MemoryPointer.new(#{ffi_type.inspect})" \
149
149
  ".tap { |ptr| #{method_argument_name}.put_pointer 0, ptr }"
150
150
  else
151
151
  method_argument_name
@@ -9,16 +9,14 @@ module GirFFI
9
9
  class CallbackReturnValueBuilder < BaseReturnValueBuilder
10
10
  def post_conversion
11
11
  if has_post_conversion?
12
- if type_info.flattened_tag == :object
13
- ["#{post_converted_name} = #{post_convertor.conversion}.to_ptr"]
14
- else
15
- ["#{post_converted_name} = #{post_convertor.conversion}"]
16
- end
12
+ optional_outgoing_ref + base_post_conversion
17
13
  else
18
14
  []
19
15
  end
20
16
  end
21
17
 
18
+ private
19
+
22
20
  def has_post_conversion?
23
21
  relevant? && needs_ruby_to_c_conversion?
24
22
  end
@@ -27,19 +25,29 @@ module GirFFI
27
25
  type_info.needs_ruby_to_c_conversion_for_callbacks?
28
26
  end
29
27
 
30
- private
31
-
32
- def post_convertor
33
- @post_convertor ||= RubyToCConvertor.new(type_info, post_convertor_argument)
28
+ def optional_outgoing_ref
29
+ if outgoing_ref_needed?
30
+ ["#{capture_variable_name}.ref"]
31
+ else
32
+ []
33
+ end
34
34
  end
35
35
 
36
- def post_convertor_argument
37
- if ownership_transfer == :everything && specialized_type_tag == :object
38
- "#{capture_variable_name}.ref"
36
+ def base_post_conversion
37
+ if specialized_type_tag == :object
38
+ ["#{post_converted_name} = #{post_convertor.conversion}.to_ptr"]
39
39
  else
40
- capture_variable_name
40
+ ["#{post_converted_name} = #{post_convertor.conversion}"]
41
41
  end
42
42
  end
43
+
44
+ def post_convertor
45
+ @post_convertor ||= RubyToCConvertor.new(type_info, capture_variable_name)
46
+ end
47
+
48
+ def outgoing_ref_needed?
49
+ ownership_transfer == :everything && specialized_type_tag == :object
50
+ end
43
51
  end
44
52
  end
45
53
  end
@@ -229,8 +229,9 @@ module GirFFI
229
229
 
230
230
  attr_reader :info
231
231
 
232
- def initialize(field_info)
232
+ def initialize(field_info, container_class)
233
233
  @info = field_info
234
+ @container_class = container_class
234
235
  end
235
236
 
236
237
  def build
@@ -285,13 +286,7 @@ module GirFFI
285
286
  @field_type_tag ||= field_type.tag_or_class
286
287
  end
287
288
 
288
- def container_class
289
- @container_class ||= container_module.const_get(container_info.safe_name)
290
- end
291
-
292
- def container_module
293
- @container_module ||= Object.const_get(container_info.safe_namespace)
294
- end
289
+ attr_reader :container_class
295
290
 
296
291
  def container_info
297
292
  @container_info ||= info.container
@@ -310,9 +305,8 @@ module GirFFI
310
305
  field_argument_info)
311
306
  end
312
307
 
313
- # rubocop:disable Style/ZeroLengthPredicate
314
308
  def hidden_struct_type?
315
- field_type.flattened_tag == :struct && field_type.interface.size == 0
309
+ field_type.hidden_struct_type?
316
310
  end
317
311
  end
318
312
  end
@@ -32,6 +32,10 @@ module GirFFI
32
32
  true
33
33
  end
34
34
 
35
+ def method_available?(method)
36
+ function_introspection_data(method.to_s) and true
37
+ end
38
+
35
39
  def build_namespaced_class(classname)
36
40
  info = find_namespaced_class_info(classname)
37
41
  Builder.build_class info
@@ -109,11 +113,9 @@ module GirFFI
109
113
  end
110
114
 
111
115
  def gir
112
- unless defined? @gir
113
- @gir = GObjectIntrospection::IRepository.default
114
- @gir.require @namespace, @version
116
+ @gir ||= GObjectIntrospection::IRepository.default.tap do |it|
117
+ it.require @namespace, @version
115
118
  end
116
- @gir
117
119
  end
118
120
  end
119
121
  end
@@ -79,12 +79,7 @@ module GirFFI
79
79
  end
80
80
 
81
81
  def parent_info
82
- unless defined? @parent_info
83
- @parent_info = if (parent = info.parent) && parent != info
84
- parent
85
- end
86
- end
87
- @parent_info
82
+ info.parent
88
83
  end
89
84
 
90
85
  def superclass
@@ -105,7 +100,7 @@ module GirFFI
105
100
 
106
101
  def setup_field_accessors
107
102
  eligible_fields.each do |finfo|
108
- FieldBuilder.new(finfo).build
103
+ FieldBuilder.new(finfo, klass).build
109
104
  end
110
105
  end
111
106
 
@@ -119,9 +114,7 @@ module GirFFI
119
114
  # TODO: Create object responsible for creating these invokers
120
115
  def setup_vfunc_invokers
121
116
  info.vfuncs.each do |vfinfo|
122
- if (invoker = vfinfo.invoker)
123
- define_vfunc_invoker vfinfo.name, invoker.name
124
- end
117
+ define_vfunc_invoker vfinfo.name, vfinfo.invoker_name if vfinfo.has_invoker?
125
118
  end
126
119
  end
127
120
 
@@ -137,12 +130,19 @@ module GirFFI
137
130
  def provide_initializer
138
131
  return if info.find_method 'new'
139
132
 
140
- # FIXME: Only valid if the object descends from GObject::Object
141
- klass.class_eval "
142
- def initialize(properties = {})
143
- base_initialize(properties)
144
- end
145
- "
133
+ if info.abstract?
134
+ klass.class_eval <<-END
135
+ def initialize(*)
136
+ raise NoMethodError
137
+ end
138
+ END
139
+ else
140
+ klass.class_eval <<-END
141
+ def initialize(properties = {})
142
+ base_initialize(properties)
143
+ end
144
+ END
145
+ end
146
146
  end
147
147
 
148
148
  def setup_interfaces
@@ -16,12 +16,10 @@ module GirFFI
16
16
  def superclass
17
17
  if info.gtype_struct?
18
18
  # HACK: Inheritance chain is not expressed in GObject's code correctly.
19
- if info.full_type_name == 'GObject::InitiallyUnownedClass'
20
- return GObject::ObjectClass
21
- else
22
- type = fields.first.field_type
23
- return type.tag_or_class if type.tag == :interface
24
- end
19
+ type_name = info.full_type_name
20
+ return GObject::ObjectClass if type_name == 'GObject::InitiallyUnownedClass'
21
+ type = fields.first.field_type
22
+ return type.tag_or_class if type.tag == :interface
25
23
  end
26
24
 
27
25
  if GObject.type_fundamental(info.gtype) == GObject::TYPE_BOXED
@@ -16,7 +16,7 @@ module GirFFI
16
16
 
17
17
  def setup_field_accessors
18
18
  fields.each do |finfo|
19
- FieldBuilder.new(finfo).build
19
+ FieldBuilder.new(finfo, klass).build
20
20
  end
21
21
  end
22
22
  end
@@ -11,8 +11,8 @@ module GirFFI
11
11
  end
12
12
 
13
13
  def setup_class
14
- register_type
15
14
  setup_layout
15
+ register_type
16
16
  setup_constants
17
17
  setup_property_accessors
18
18
  setup_constructor
@@ -86,8 +86,10 @@ module GirFFI
86
86
 
87
87
  def instance_size
88
88
  size = parent_gtype.instance_size
89
- properties.each do
90
- size += FFI.type_size(:int32)
89
+ alignment = struct_class.alignment
90
+ properties.each do |prop|
91
+ type_size = FFI.type_size(prop.ffi_type)
92
+ size += [type_size, alignment].max
91
93
  end
92
94
  size
93
95
  end
@@ -109,13 +111,13 @@ module GirFFI
109
111
 
110
112
  def property_getter
111
113
  proc do |object, _property_id, value, pspec|
112
- value.set_value object.send(pspec.get_name)
114
+ value.set_value object.send(pspec.accessor_name)
113
115
  end
114
116
  end
115
117
 
116
118
  def property_setter
117
119
  proc do |object, _property_id, value, pspec|
118
- object.send("#{pspec.get_name}=", value.get_value)
120
+ object.send("#{pspec.accessor_name}=", value.get_value)
119
121
  end
120
122
  end
121
123
 
@@ -167,34 +169,92 @@ module GirFFI
167
169
  end
168
170
 
169
171
  def layout_specification
170
- parent_spec = [:parent, superclass::Struct, 0]
171
- offset = superclass::Struct.size
172
- fields_spec = properties.flat_map do |pinfo|
173
- spec = [pinfo.name.to_sym, :int32, offset]
174
- offset += FFI.type_size(:int32)
172
+ parent_spec = [:parent, superclass::Struct]
173
+ offset = parent_gtype.instance_size
174
+
175
+ alignment = superclass::Struct.alignment
176
+ fields_spec = properties.flat_map do |param_info|
177
+ field_name = param_info.accessor_name
178
+ ffi_type = param_info.ffi_type
179
+ type_size = FFI.type_size(ffi_type)
180
+ spec = [field_name, ffi_type, offset]
181
+ offset += [type_size, alignment].max
175
182
  spec
176
183
  end
177
184
  parent_spec + fields_spec
178
185
  end
179
186
 
180
- def setup_property_accessors
181
- properties.each do |pinfo|
182
- setup_accessors_for_param_info pinfo
187
+ # TODO: Move this to its own file.
188
+ # TODO: See if this or FieldTypeInfo can be merged with with
189
+ # UserDefinedPropertyInfo.
190
+ class UserDefinedPropertyFieldInfo
191
+ # Field info for user-defined property
192
+ class FieldTypeInfo
193
+ include InfoExt::ITypeInfo
194
+
195
+ def initialize(property_info)
196
+ @property_info = property_info
197
+ end
198
+
199
+ def tag
200
+ @property_info.type_tag
201
+ end
202
+
203
+ def pointer?
204
+ @property_info.pointer_type?
205
+ end
206
+
207
+ def interface_type
208
+ @property_info.interface_type_tag if tag == :interface
209
+ end
210
+
211
+ def hidden_struct_type?
212
+ false
213
+ end
214
+
215
+ def interface_class
216
+ Builder.build_by_gtype @property_info.value_type if tag == :interface
217
+ end
218
+
219
+ def interface_class_name
220
+ interface_class.name if tag == :interface
221
+ end
183
222
  end
184
- end
185
223
 
186
- def setup_accessors_for_param_info(pinfo)
187
- field_name = pinfo.name
188
- code = <<-CODE
189
- def #{field_name}
190
- @struct[:#{field_name}]
224
+ def initialize(property_info, container, offset)
225
+ @property_info = property_info
226
+ @container = container
227
+ @offset = offset
191
228
  end
192
- def #{field_name}= val
193
- @struct[:#{field_name}] = val
229
+
230
+ attr_reader :container, :offset
231
+
232
+ def name
233
+ @property_info.accessor_name
194
234
  end
195
- CODE
196
235
 
197
- klass.class_eval code
236
+ def field_type
237
+ @field_type ||= FieldTypeInfo.new @property_info
238
+ end
239
+
240
+ def related_array_length_field
241
+ nil
242
+ end
243
+
244
+ def writable?
245
+ @property_info.writable?
246
+ end
247
+ end
248
+
249
+ def setup_property_accessors
250
+ offset = parent_gtype.instance_size
251
+ alignment = struct_class.alignment
252
+ properties.each do |param_info|
253
+ field_info = UserDefinedPropertyFieldInfo.new(param_info, info, offset)
254
+ type_size = FFI.type_size(param_info.ffi_type)
255
+ offset += [type_size, alignment].max
256
+ FieldBuilder.new(field_info, klass).build
257
+ end
198
258
  end
199
259
 
200
260
  def method_introspection_data(_method)
@@ -7,8 +7,16 @@ module GirFFI
7
7
  # argument mapper for vfuncs.
8
8
  class VFuncArgumentBuilder < CallbackArgumentBuilder
9
9
  def pre_conversion
10
- if ingoing_ref_needed
11
- super + [pre_ref_count_increase]
10
+ if ingoing_ref_needed?
11
+ super + ["#{pre_converted_name}.ref"]
12
+ else
13
+ super
14
+ end
15
+ end
16
+
17
+ def post_conversion
18
+ if outgoing_ref_needed?
19
+ ["#{result_name}.ref"] + super
12
20
  else
13
21
  super
14
22
  end
@@ -16,26 +24,13 @@ module GirFFI
16
24
 
17
25
  private
18
26
 
19
- def ingoing_ref_needed
27
+ def ingoing_ref_needed?
20
28
  direction == :in &&
21
29
  ownership_transfer == :nothing &&
22
30
  specialized_type_tag == :object
23
31
  end
24
32
 
25
- def pre_ref_count_increase
26
- "#{pre_converted_name}.ref"
27
- end
28
-
29
- # SMELL: Override private method
30
- def post_convertor_argument
31
- if outgoing_ref_needed
32
- "#{super}.ref"
33
- else
34
- super
35
- end
36
- end
37
-
38
- def outgoing_ref_needed
33
+ def outgoing_ref_needed?
39
34
  direction == :out &&
40
35
  ownership_transfer == :everything &&
41
36
  specialized_type_tag == :object
@@ -31,10 +31,6 @@ module GirFFI
31
31
  other.class == self.class && to_ptr.address == other.to_ptr.address
32
32
  end
33
33
 
34
- def initialize
35
- raise NoMethodError
36
- end
37
-
38
34
  def self.setup_and_call(method, arguments, &block)
39
35
  method_name = try_in_ancestors(:setup_method, method.to_s)
40
36