gir_ffi 0.7.3 → 0.7.4

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +10 -0
  3. data/Rakefile +9 -1
  4. data/TODO.md +4 -0
  5. data/lib/ffi-glib.rb +5 -0
  6. data/lib/ffi-glib/bytes.rb +49 -0
  7. data/lib/ffi-glib/container_class_methods.rb +1 -4
  8. data/lib/ffi-glib/error.rb +17 -0
  9. data/lib/ffi-gobject/value.rb +6 -3
  10. data/lib/ffi-gobject_introspection/i_callback_info.rb +0 -1
  11. data/lib/ffi-gobject_introspection/i_constant_info.rb +10 -10
  12. data/lib/ffi-gobject_introspection/i_repository.rb +20 -20
  13. data/lib/ffi-gobject_introspection/i_vfunc_info.rb +7 -0
  14. data/lib/ffi-gobject_introspection/lib.rb +1 -7
  15. data/lib/gir_ffi/arg_helper.rb +23 -2
  16. data/lib/gir_ffi/builders/argument_builder.rb +15 -1
  17. data/lib/gir_ffi/builders/base_argument_builder.rb +1 -0
  18. data/lib/gir_ffi/builders/callback_argument_builder.rb +49 -7
  19. data/lib/gir_ffi/builders/callback_return_value_builder.rb +6 -2
  20. data/lib/gir_ffi/builders/closure_convertor.rb +1 -1
  21. data/lib/gir_ffi/builders/null_convertor.rb +1 -0
  22. data/lib/gir_ffi/builders/property_builder.rb +1 -1
  23. data/lib/gir_ffi/builders/return_value_builder.rb +1 -1
  24. data/lib/gir_ffi/builders/type_builder.rb +9 -9
  25. data/lib/gir_ffi/builders/vfunc_builder.rb +3 -1
  26. data/lib/gir_ffi/callback_base.rb +6 -0
  27. data/lib/gir_ffi/error_argument_info.rb +12 -3
  28. data/lib/gir_ffi/error_type_info.rb +21 -0
  29. data/lib/gir_ffi/ffi_ext/pointer.rb +5 -6
  30. data/lib/gir_ffi/glib_error.rb +18 -0
  31. data/lib/gir_ffi/in_pointer.rb +1 -1
  32. data/lib/gir_ffi/info_ext/i_type_info.rb +44 -30
  33. data/lib/gir_ffi/info_ext/i_vfunc_info.rb +13 -1
  34. data/lib/gir_ffi/type_map.rb +30 -29
  35. data/lib/gir_ffi/user_defined_type_info.rb +1 -0
  36. data/lib/gir_ffi/version.rb +1 -1
  37. data/lib/gir_ffi/vfunc_base.rb +1 -0
  38. data/lib/gir_ffi/zero_terminated.rb +3 -8
  39. data/test/base_test_helper.rb +1 -0
  40. data/test/ffi-glib/array_test.rb +2 -2
  41. data/test/ffi-glib/bytes_test.rb +54 -0
  42. data/test/ffi-glib/ptr_array_test.rb +2 -2
  43. data/test/ffi-gobject/value_test.rb +4 -4
  44. data/test/ffi-gobject_introspection/i_repository_test.rb +1 -1
  45. data/test/gir_ffi/builders/callback_argument_builder_test.rb +44 -0
  46. data/test/gir_ffi/builders/callback_builder_test.rb +1 -1
  47. data/test/gir_ffi/builders/callback_return_value_builder_test.rb +74 -0
  48. data/test/gir_ffi/builders/function_builder_test.rb +23 -2
  49. data/test/gir_ffi/builders/property_builder_test.rb +15 -0
  50. data/test/gir_ffi/builders/return_value_builder_test.rb +26 -26
  51. data/test/gir_ffi/builders/signal_builder_test.rb +5 -5
  52. data/test/gir_ffi/builders/union_builder_test.rb +2 -1
  53. data/test/gir_ffi/builders/vfunc_builder_test.rb +125 -4
  54. data/test/gir_ffi/error_type_info_test.rb +48 -0
  55. data/test/gir_ffi/in_pointer_test.rb +1 -1
  56. data/test/gir_ffi/sized_array_test.rb +2 -2
  57. data/test/integration/generated_gimarshallingtests_test.rb +199 -31
  58. data/test/integration/generated_regress_test.rb +37 -33
  59. metadata +214 -202
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22d6bb7bfc0aa7590953b8286894e4d0e814d70c
4
- data.tar.gz: 76f360c36de64f4ec95614b1d80fce35620841eb
3
+ metadata.gz: 1adc3c9b00a49fef5e4ae2dc6674c79c62dc56b6
4
+ data.tar.gz: 47303f482166c93c612ed7debdf2d2ed95aad752
5
5
  SHA512:
6
- metadata.gz: b850a1fbc54e68271fbd7928a42cd657743d6e95c28dfecc85851f4ad26247b80c06aacac8a1339e3b6988d2d3fd8a72f32dc4c660ccf9c1cdcac862034d2f47
7
- data.tar.gz: 712bd571f53ccf66ef8f26b85b66ccc979a9f65733c2197f0dd982fe0d2d3509c8f0bef48dd2cf289ca85632537e6ebde25828aafc55571e7d01d5f2ce1c72e6
6
+ metadata.gz: d6983eb6497add24e59e8d8041b815fccd9615e8e9d42895a8e1afbacb44c180a9e6bf63a9a719c6c5bca0552c9fb426391aefe5f668ba44669a3e425554fc2f
7
+ data.tar.gz: b904270d51f8905733777fb1ad5e9f6c8da61dd44153c078c472befcd0eee83988ebc08d95d9bb0dc3f57866cd4b4638e45046239fac63a0aa5ddc7e23ba6f49
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.4 / 2014-05-03
4
+
5
+ * Correctly handle closure data arguments originating from C
6
+ * Handle callee-allocated simple types for callbacks and functions
7
+ * Handle callback out parameters that are zero-terminated arrays
8
+ * Handle virtual functions with GError arguments
9
+ * Support the GBytes type
10
+ * Handle virtual functions returning GObjects
11
+ * Avoid overwriting methods with getters for properties with dashes in the name
12
+
3
13
  ## 0.7.3 / 2014-03-23
4
14
 
5
15
  * Restore proper handling of enums in callback arguments
data/Rakefile CHANGED
@@ -1,5 +1,13 @@
1
1
  require 'rake/clean'
2
- require 'bundler/gem_tasks'
2
+ require 'bundler/gem_helper'
3
+
4
+ class MyGemHelper < Bundler::GemHelper
5
+ def version_tag
6
+ "version-#{version}"
7
+ end
8
+ end
9
+
10
+ MyGemHelper.install_tasks
3
11
 
4
12
  begin
5
13
  require 'repl_rake'
data/TODO.md CHANGED
@@ -85,6 +85,10 @@ retrieve values from them by hand as well. Ideally, we would have `.from_ruby` a
85
85
  require a specifice VariantType to be used consistently. Special logic will have
86
86
  to be put in place for that.
87
87
 
88
+ ## Handle ownership-transfer correctly
89
+
90
+ For how to handle objects, see https://bugzilla.gnome.org/show_bug.cgi?id=657202#c1
91
+
88
92
  ## See Also
89
93
 
90
94
  dnote
@@ -5,6 +5,8 @@ GirFFI.setup :GLib
5
5
 
6
6
  require 'ffi-glib/array'
7
7
  require 'ffi-glib/byte_array'
8
+ require 'ffi-glib/bytes'
9
+ require 'ffi-glib/error'
8
10
  require 'ffi-glib/hash_table'
9
11
  require 'ffi-glib/iconv'
10
12
  require 'ffi-glib/list'
@@ -31,6 +33,9 @@ module GLib
31
33
  attach_function :g_byte_array_new, [], :pointer
32
34
  attach_function :g_byte_array_append, [:pointer, :pointer, :uint], :pointer
33
35
 
36
+ attach_function :g_bytes_get_data, [:pointer, :pointer], :pointer
37
+ attach_function :g_bytes_new, [:pointer, :size_t], :pointer
38
+
34
39
  attach_function :g_array_new, [:int, :int, :uint], :pointer
35
40
  attach_function :g_array_append_vals, [:pointer, :pointer, :uint], :pointer
36
41
  attach_function :g_array_get_element_size, [:pointer], :uint
@@ -0,0 +1,49 @@
1
+ module GLib
2
+ load_class :Bytes
3
+
4
+ # Overrides for GBytes, GLib's immutable array of bytes.
5
+ class Bytes
6
+ include Enumerable
7
+
8
+ remove_method :get_data if method_defined? :get_data
9
+
10
+ # Override for GBytes#get_data, needed due to mis-identification of the
11
+ # element-type of the resulting sized array.
12
+ def get_data
13
+ length_ptr = GirFFI::InOutPointer.for :gsize
14
+ data_ptr = Lib.g_bytes_get_data self, length_ptr
15
+ length = length_ptr.to_value
16
+ GirFFI::SizedArray.wrap(:guint8, length, data_ptr)
17
+ end
18
+
19
+ def each &block
20
+ data.each(&block)
21
+ end
22
+
23
+ def self.from it
24
+ case it
25
+ when self
26
+ it
27
+ when FFI::Pointer
28
+ wrap it
29
+ else
30
+ new it
31
+ end
32
+ end
33
+
34
+ class << self
35
+ undef new
36
+ end
37
+
38
+ def self.new arr
39
+ data = GirFFI::SizedArray.from :guint8, arr.size, arr
40
+ self.wrap Lib.g_bytes_new data.to_ptr, data.size
41
+ end
42
+
43
+ private
44
+
45
+ def data
46
+ @data ||= get_data
47
+ end
48
+ end
49
+ end
@@ -8,10 +8,7 @@ module GLib
8
8
  end
9
9
  end
10
10
 
11
- # FIXME: Drop Ruby 1.8.7 support and make first argument optional.
12
- def from *args
13
- it, typespec = *args.reverse
14
- typespec ||= :void
11
+ def from typespec = :void, it
15
12
  case it
16
13
  when nil
17
14
  nil
@@ -0,0 +1,17 @@
1
+ module GLib
2
+ load_class :Error
3
+
4
+ # Overrides for GError, used by GLib for handling non-fatal errors.
5
+ class Error
6
+ # TODO: Auto-convert strings and symbols to quarks
7
+ GIR_FFI_DOMAIN = GLib.quark_from_string("gir_ffi")
8
+
9
+ def self.from_exception ex
10
+ new_literal GIR_FFI_DOMAIN, 0, ex.message
11
+ end
12
+
13
+ def self.from it
14
+ from_exception it
15
+ end
16
+ end
17
+ end
@@ -123,8 +123,11 @@ module GObject
123
123
  end
124
124
 
125
125
  def get_enum_enhanced
126
- value = get_enum
127
- GirFFI::Builder.build_by_gtype(current_gtype).wrap(value)
126
+ current_gtype_class.wrap(get_enum)
127
+ end
128
+
129
+ def current_gtype_class
130
+ GirFFI::Builder.build_by_gtype(current_gtype)
128
131
  end
129
132
 
130
133
  def check_type_compatibility val
@@ -140,7 +143,7 @@ module GObject
140
143
  when TYPE_HASH_TABLE
141
144
  GLib::HashTable.wrap [:gpointer, :gpointer], boxed
142
145
  else
143
- boxed.wrap_by_gtype current_gtype
146
+ current_gtype_class.wrap(boxed) unless boxed.null?
144
147
  end
145
148
  end
146
149
 
@@ -4,4 +4,3 @@ module GObjectIntrospection
4
4
  class ICallbackInfo < ICallableInfo
5
5
  end
6
6
  end
7
-
@@ -2,16 +2,16 @@ module GObjectIntrospection
2
2
  # Wraps a GIConstantInfo struct; represents a constant.
3
3
  class IConstantInfo < IBaseInfo
4
4
  TYPE_TAG_TO_UNION_MEMBER = {
5
- :gint8 => :v_int8,
6
- :gint16 => :v_int16,
7
- :gint32 => :v_int32,
8
- :gint64 => :v_int64,
9
- :guint8 => :v_uint8,
10
- :guint16 => :v_uint16,
11
- :guint32 => :v_uint32,
12
- :guint64 => :v_uint64,
13
- :gdouble => :v_double,
14
- :utf8 => :v_string
5
+ gint8: :v_int8,
6
+ gint16: :v_int16,
7
+ gint32: :v_int32,
8
+ gint64: :v_int64,
9
+ guint8: :v_uint8,
10
+ guint16: :v_uint16,
11
+ guint32: :v_uint32,
12
+ guint64: :v_uint64,
13
+ gdouble: :v_double,
14
+ utf8: :v_string
15
15
  }
16
16
 
17
17
  def value_union
@@ -31,27 +31,27 @@ module GObjectIntrospection
31
31
  class IRepository
32
32
  # Map info type to class. Default is IBaseInfo.
33
33
  TYPEMAP = {
34
- :invalid => IBaseInfo,
35
- :function => IFunctionInfo,
36
- :callback => ICallbackInfo,
37
- :struct => IStructInfo,
34
+ invalid: IBaseInfo,
35
+ function: IFunctionInfo,
36
+ callback: ICallbackInfo,
37
+ struct: IStructInfo,
38
38
  # TODO: There's no GIBoxedInfo, so what does :boxed mean?
39
- :boxed => IBaseInfo,
40
- :enum => IEnumInfo,
41
- :flags => IFlagsInfo,
42
- :object => IObjectInfo,
43
- :interface => IInterfaceInfo,
44
- :constant => IConstantInfo,
45
- :invalid_was_error_domain => IBaseInfo,
46
- :union => IUnionInfo,
47
- :value => IValueInfo,
48
- :signal => ISignalInfo,
49
- :vfunc => IVFuncInfo,
50
- :property => IPropertyInfo,
51
- :field => IFieldInfo,
52
- :arg => IArgInfo,
53
- :type => ITypeInfo,
54
- :unresolved => IBaseInfo
39
+ boxed: IBaseInfo,
40
+ enum: IEnumInfo,
41
+ flags: IFlagsInfo,
42
+ object: IObjectInfo,
43
+ interface: IInterfaceInfo,
44
+ constant: IConstantInfo,
45
+ invalid_was_error_domain: IBaseInfo,
46
+ union: IUnionInfo,
47
+ value: IValueInfo,
48
+ signal: ISignalInfo,
49
+ vfunc: IVFuncInfo,
50
+ property: IPropertyInfo,
51
+ field: IFieldInfo,
52
+ arg: IArgInfo,
53
+ type: ITypeInfo,
54
+ unresolved: IBaseInfo
55
55
  }
56
56
 
57
57
  def initialize
@@ -5,12 +5,19 @@ module GObjectIntrospection
5
5
  def flags
6
6
  Lib.g_vfunc_info_get_flags @gobj
7
7
  end
8
+
9
+ def throws?
10
+ flags & 8 != 0
11
+ end
12
+
8
13
  def offset
9
14
  Lib.g_vfunc_info_get_offset @gobj
10
15
  end
16
+
11
17
  def signal
12
18
  ISignalInfo.wrap(Lib.g_vfunc_info_get_signal @gobj)
13
19
  end
20
+
14
21
  def invoker
15
22
  IFunctionInfo.wrap(Lib.g_vfunc_info_get_invoker @gobj)
16
23
  end
@@ -210,13 +210,7 @@ module GObjectIntrospection
210
210
 
211
211
  # IVFuncInfo
212
212
 
213
- enum :IVFuncInfoFlags, [
214
- :must_chain_up, (1 << 0),
215
- :must_override, (1 << 1),
216
- :must_not_override, (1 << 2)
217
- ]
218
-
219
- attach_function :g_vfunc_info_get_flags, [:pointer], :IVFuncInfoFlags
213
+ attach_function :g_vfunc_info_get_flags, [:pointer], :int
220
214
  attach_function :g_vfunc_info_get_offset, [:pointer], :int
221
215
  attach_function :g_vfunc_info_get_signal, [:pointer], :pointer
222
216
  attach_function :g_vfunc_info_get_invoker, [:pointer], :pointer
@@ -1,9 +1,30 @@
1
1
  require 'gir_ffi/allocation_helper'
2
2
  require 'gir_ffi/builder'
3
+ require 'gir_ffi/glib_error'
3
4
 
4
5
  module GirFFI
5
6
  module ArgHelper
6
- OBJECT_STORE = {}
7
+ class ObjectStore
8
+ def initialize
9
+ @store = {}
10
+ end
11
+
12
+ def store(ptr, obj)
13
+ @store[ptr.address] = obj
14
+ end
15
+
16
+ def fetch(ptr)
17
+ return if ptr.null?
18
+ key = ptr.address
19
+ if @store.has_key? key
20
+ @store[key]
21
+ else
22
+ ptr
23
+ end
24
+ end
25
+ end
26
+
27
+ OBJECT_STORE = ObjectStore.new
7
28
 
8
29
  def self.ptr_to_utf8_length ptr, len
9
30
  ptr.null? ? nil : ptr.read_string(len)
@@ -11,7 +32,7 @@ module GirFFI
11
32
 
12
33
  def self.check_error errpp
13
34
  err = GLib::Error.wrap(errpp.read_pointer)
14
- raise err.message if err
35
+ raise GLibError, err if err
15
36
  end
16
37
 
17
38
  def self.check_fixed_array_size size, arr, name
@@ -63,13 +63,27 @@ module GirFFI
63
63
 
64
64
  def output_value
65
65
  base = "#{callarg}.to_value"
66
- if @type_info.needs_conversion_for_functions?
66
+ if needs_out_conversion?
67
67
  CToRubyConvertor.new(@type_info, base, length_argument_name).conversion
68
+ elsif allocated_by_them?
69
+ "GirFFI::InOutPointer.new(#{type_info.tag_or_class[1].inspect}, #{base}).to_value"
68
70
  else
69
71
  base
70
72
  end
71
73
  end
72
74
 
75
+ def needs_out_conversion?
76
+ @type_info.needs_c_to_ruby_conversion_for_functions?
77
+ end
78
+
79
+ # Check if an out argument needs to be allocated by them, the callee. Since
80
+ # caller_allocates is false by default, we must also check that the type
81
+ # is a pointer. For example, an out parameter of type gint8* will always
82
+ # be allocated by the caller (that's us).
83
+ def allocated_by_them?
84
+ !@arginfo.caller_allocates? && @type_info.pointer?
85
+ end
86
+
73
87
  def length_argument_name
74
88
  length_arg && length_arg.post_converted_name
75
89
  end
@@ -37,6 +37,7 @@ module GirFFI
37
37
  end
38
38
 
39
39
  def specialized_type_tag
40
+ # SMELL: Law of Demeter, due to this being arginfo.argument_type.flattened_tag
40
41
  type_info.flattened_tag
41
42
  end
42
43
 
@@ -21,9 +21,7 @@ module GirFFI
21
21
  end
22
22
 
23
23
  def capture_variable_name
24
- if direction == :out
25
- @capture_variable_name ||= new_variable
26
- end
24
+ result_name if direction == :out
27
25
  end
28
26
 
29
27
  def pre_conversion
@@ -32,12 +30,24 @@ module GirFFI
32
30
  [ "#{pre_converted_name} = #{pre_convertor.conversion}" ]
33
31
  when :out
34
32
  [ "#{pre_converted_name} = #{out_parameter_preparation}" ]
33
+ when :error
34
+ [
35
+ "#{pre_converted_name} = #{out_parameter_preparation}",
36
+ "begin"
37
+ ]
35
38
  end
36
39
  end
37
40
 
38
41
  def post_conversion
39
- if direction == :out
40
- [ "#{pre_converted_name}.set_value #{capture_variable_name}" ]
42
+ case direction
43
+ when :out
44
+ [ outgoing_post_conversion ]
45
+ when :error
46
+ [
47
+ "rescue => #{result_name}",
48
+ outgoing_post_conversion,
49
+ "end"
50
+ ]
41
51
  else
42
52
  []
43
53
  end
@@ -45,10 +55,14 @@ module GirFFI
45
55
 
46
56
  private
47
57
 
58
+ def result_name
59
+ @result_name ||= new_variable
60
+ end
61
+
48
62
  def pre_convertor
49
63
  @pre_convertor ||= if is_closure
50
64
  ClosureConvertor.new(method_argument_name)
51
- elsif type_info.needs_conversion_for_callbacks?
65
+ elsif type_info.needs_c_to_ruby_conversion_for_callbacks?
52
66
  CToRubyConvertor.new(type_info,
53
67
  method_argument_name,
54
68
  length_argument_name)
@@ -57,8 +71,36 @@ module GirFFI
57
71
  end
58
72
  end
59
73
 
74
+ def outgoing_post_conversion
75
+ "#{pre_converted_name}.set_value #{outgoing_convertor.conversion}"
76
+ end
77
+
78
+ def outgoing_convertor
79
+ @outgoing_convertor ||= if type_info.needs_ruby_to_c_conversion_for_callbacks?
80
+ RubyToCConvertor.new(type_info, result_name)
81
+ else
82
+ NullConvertor.new(result_name)
83
+ end
84
+ end
85
+
60
86
  def out_parameter_preparation
61
- "GirFFI::InOutPointer.new(#{type_info.tag_or_class.inspect}, #{method_argument_name})"
87
+ type_spec = type_info.tag_or_class
88
+ if allocated_by_us?
89
+ "GirFFI::InOutPointer.new(#{type_spec[1].inspect})" +
90
+ ".tap { |ptr| #{method_argument_name}.put_pointer 0, ptr }"
91
+ else
92
+ "GirFFI::InOutPointer.new(#{type_spec.inspect}, #{method_argument_name})"
93
+ end
94
+ end
95
+
96
+ # Check if an out argument needs to be allocated by us, the callee. Since
97
+ # caller_allocates is false by default, we must also check that the type
98
+ # is a pointer. For example, an out parameter of type gint8* will always
99
+ # be allocate by the caller.
100
+ def allocated_by_us?
101
+ !@arginfo.caller_allocates? &&
102
+ type_info.pointer? &&
103
+ ![:object, :zero_terminated].include?(specialized_type_tag)
62
104
  end
63
105
 
64
106
  def length_argument_name