gir_ffi 0.7.3 → 0.7.4

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