PageRenderTime 2ms CodeModel.GetById 98ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/cache/ruby/2.7.0/gems/ruby-vips-2.0.17/lib/vips/gvalue.rb

https://gitlab.com/gitnyasha/zimcreative
Ruby | 287 lines | 168 code | 58 blank | 61 comment | 9 complexity | bfb9764cd8053268342794bebd14f9fb MD5 | raw file
  1# This module provides an interface GValue via ruby-ffi.
  2#
  3# Author::    John Cupitt  (mailto:jcupitt@gmail.com)
  4# License::   MIT
  5
  6require 'ffi'
  7
  8module GObject
  9  # Represent a GValue. Example use:
 10  #
 11  # ```ruby
 12  # gvalue = GValue::alloc
 13  # gvalue.init GObject::GDOUBLE_TYPE
 14  # gvalue.set 3.1415
 15  # value = gvalue.get
 16  # # optional -- drop any ref the gvalue had
 17  # gvalue.unset
 18  # ```
 19  #
 20  # Lifetime is managed automatically. It doesn't know about all GType values,
 21  # but it does know the ones that libvips uses.
 22
 23  class GValue < FFI::ManagedStruct
 24    layout :gtype, :GType,
 25           :data, [:ulong_long, 2]
 26
 27    # convert an enum value (str/symb/int) into an int ready for libvips
 28    def self.from_nick(gtype, value)
 29      value = value.to_s if value.is_a? Symbol
 30
 31      if value.is_a? String
 32        # libvips expects "-" as a separator in enum names, but "_" is more
 33        # convenient for ruby, eg. :b_w
 34        value = Vips::vips_enum_from_nick "ruby-vips", gtype, value.tr("_", "-")
 35        if value == -1
 36          raise Vips::Error
 37        end
 38      end
 39
 40      value
 41    end
 42
 43    # convert an int enum back into a symbol
 44    def self.to_nick(gtype, enum_value)
 45      enum_name = Vips::vips_enum_nick gtype, enum_value
 46      if enum_name == nil
 47        raise Vips::Error
 48      end
 49
 50      enum_name.to_sym
 51    end
 52
 53    def self.release ptr
 54      # GLib::logger.debug("GObject::GValue::release") {"ptr = #{ptr}"}
 55      ::GObject::g_value_unset ptr
 56    end
 57
 58    # Allocate memory for a GValue and return a class wrapper. Memory will
 59    # be freed automatically when it goes out of scope. The GValue is inited
 60    # to 0, use {GValue.init} to set a type.
 61    #
 62    # @return [GValue] a new gvalue set to 0
 63    def self.alloc
 64      # allocate memory
 65      memory = FFI::MemoryPointer.new GValue
 66
 67      # make this alloc autorelease ... we mustn't release in
 68      # GValue::release, since we are used to wrap GValue pointers
 69      # made by other people
 70      pointer = FFI::Pointer.new GValue, memory
 71
 72      # ... and wrap in a GValue
 73      return GValue.new pointer
 74    end
 75
 76    # Set the type of thing a gvalue can hold.
 77    #
 78    # @param gtype [GType] the type of thing this GValue can hold.
 79    def init gtype
 80      ::GObject::g_value_init self, gtype
 81    end
 82
 83    # Set the value of a GValue. The value is converted to the type of the
 84    # GValue, if possible.
 85    #
 86    # @param value [Any] The value to set
 87    def set value
 88      # GLib::logger.debug("GObject::GValue.set") {
 89      #     "value = #{value.inspect[0..50]}"
 90      # }
 91
 92      gtype = self[:gtype]
 93      fundamental = ::GObject::g_type_fundamental gtype
 94
 95      case gtype
 96      when GBOOL_TYPE
 97        ::GObject::g_value_set_boolean self, (value ? 1 : 0)
 98
 99      when GINT_TYPE
100        ::GObject::g_value_set_int self, value
101
102      when GUINT64_TYPE
103        ::GObject::g_value_set_uint64 self, value
104
105      when GDOUBLE_TYPE
106        ::GObject::g_value_set_double self, value
107
108      when GSTR_TYPE
109        ::GObject::g_value_set_string self, value
110
111      when Vips::REFSTR_TYPE
112        ::Vips::vips_value_set_ref_string self, value
113
114      when Vips::ARRAY_INT_TYPE
115        value = [value] unless value.is_a? Array
116
117        Vips::vips_value_set_array_int self, nil, value.length
118        ptr = Vips::vips_value_get_array_int self, nil
119        ptr.write_array_of_int32 value
120
121      when Vips::ARRAY_DOUBLE_TYPE
122        value = [value] unless value.is_a? Array
123
124        # this will allocate an array in the gvalue
125        Vips::vips_value_set_array_double self, nil, value.length
126
127        # pull the array out and fill it
128        ptr = Vips::vips_value_get_array_double self, nil
129
130        ptr.write_array_of_double value
131
132      when Vips::ARRAY_IMAGE_TYPE
133        value = [value] unless value.is_a? Array
134
135        Vips::vips_value_set_array_image self, value.length
136        ptr = Vips::vips_value_get_array_image self, nil
137        ptr.write_array_of_pointer value
138
139        # the gvalue needs a ref on each of the images
140        value.each { |image| ::GObject::g_object_ref image }
141
142      when Vips::BLOB_TYPE
143        len = value.bytesize
144        ptr = GLib::g_malloc len
145        Vips::vips_value_set_blob self, GLib::G_FREE, ptr, len
146        ptr.write_bytes value
147
148      else
149        case fundamental
150        when GFLAGS_TYPE
151          ::GObject::g_value_set_flags self, value
152
153        when GENUM_TYPE
154          enum_value = GValue.from_nick(self[:gtype], value)
155          ::GObject::g_value_set_enum self, enum_value
156
157        when GOBJECT_TYPE
158          ::GObject::g_value_set_object self, value
159
160        else
161          raise Vips::Error, "unimplemented gtype for set: " +
162                             "#{::GObject::g_type_name gtype} (#{gtype})"
163        end
164      end
165    end
166
167    # Get the value of a GValue. The value is converted to a Ruby type in
168    # the obvious way.
169    #
170    # @return [Any] the value held by the GValue
171    def get
172      gtype = self[:gtype]
173      fundamental = ::GObject::g_type_fundamental gtype
174      result = nil
175
176      case gtype
177      when GBOOL_TYPE
178        result = ::GObject::g_value_get_boolean(self) != 0 ? true : false
179
180      when GINT_TYPE
181        result = ::GObject::g_value_get_int self
182
183      when GUINT64_TYPE
184        result = ::GObject::g_value_get_uint64 self
185
186      when GDOUBLE_TYPE
187        result = ::GObject::g_value_get_double self
188
189      when GSTR_TYPE
190        result = ::GObject::g_value_get_string self
191
192      when Vips::REFSTR_TYPE
193        len = Vips::SizeStruct.new
194        result = ::Vips::vips_value_get_ref_string self, len
195
196      when Vips::ARRAY_INT_TYPE
197        len = Vips::IntStruct.new
198        array = Vips::vips_value_get_array_int self, len
199        result = array.get_array_of_int32 0, len[:value]
200
201      when Vips::ARRAY_DOUBLE_TYPE
202        len = Vips::IntStruct.new
203        array = Vips::vips_value_get_array_double self, len
204        result = array.get_array_of_double 0, len[:value]
205
206      when Vips::ARRAY_IMAGE_TYPE
207        len = Vips::IntStruct.new
208        array = Vips::vips_value_get_array_image self, len
209        result = array.get_array_of_pointer 0, len[:value]
210        result.map! do |pointer|
211          ::GObject::g_object_ref pointer
212          Vips::Image.new pointer
213        end
214
215      when Vips::BLOB_TYPE
216        len = Vips::SizeStruct.new
217        array = Vips::vips_value_get_blob self, len
218        result = array.get_bytes 0, len[:value]
219
220      else
221        case fundamental
222        when GFLAGS_TYPE
223          result = ::GObject::g_value_get_flags self
224
225        when GENUM_TYPE
226          enum_value = ::GObject::g_value_get_enum(self)
227          result = GValue.to_nick self[:gtype], enum_value
228
229        when GOBJECT_TYPE
230          obj = ::GObject::g_value_get_object self
231          # g_value_get_object() does not add a ref ... we need to add
232          # one to match the unref in gobject release
233          ::GObject::g_object_ref obj
234          result = Vips::Image.new obj
235
236        else
237          raise Vips::Error, "unimplemented gtype for get: " +
238                             "#{::GObject::g_type_name gtype} (#{gtype})"
239        end
240      end
241
242      # GLib::logger.debug("GObject::GValue.get") {
243      #     "result = #{result.inspect[0..50]}"
244      # }
245
246      return result
247    end
248
249    # Clear the thing held by a GValue. 
250    #
251    # This happens automatically when a GValue is GCed, but this method can be 
252    # handy if you need to drop a reference explicitly for some reason.
253    def unset 
254      ::GObject::g_value_unset self
255    end
256  end
257
258  attach_function :g_value_init, [GValue.ptr, :GType], :void
259
260  # we must use a plain :pointer here, since we call this from #release, which
261  # just gives us the unwrapped pointer, not the ruby class
262  attach_function :g_value_unset, [:pointer], :void
263
264  attach_function :g_value_set_boolean, [GValue.ptr, :int], :void
265  attach_function :g_value_set_int, [GValue.ptr, :int], :void
266  attach_function :g_value_set_uint64, [GValue.ptr, :uint64], :void
267  attach_function :g_value_set_double, [GValue.ptr, :double], :void
268  attach_function :g_value_set_enum, [GValue.ptr, :int], :void
269  attach_function :g_value_set_flags, [GValue.ptr, :uint], :void
270  attach_function :g_value_set_string, [GValue.ptr, :string], :void
271  attach_function :g_value_set_object, [GValue.ptr, :pointer], :void
272
273  attach_function :g_value_get_boolean, [GValue.ptr], :int
274  attach_function :g_value_get_int, [GValue.ptr], :int
275  attach_function :g_value_get_uint64, [GValue.ptr], :uint64
276  attach_function :g_value_get_double, [GValue.ptr], :double
277  attach_function :g_value_get_enum, [GValue.ptr], :int
278  attach_function :g_value_get_flags, [GValue.ptr], :int
279  attach_function :g_value_get_string, [GValue.ptr], :string
280  attach_function :g_value_get_object, [GValue.ptr], :pointer
281
282  # use :pointer rather than GObject.ptr to avoid casting later
283  attach_function :g_object_set_property,
284      [:pointer, :string, GValue.ptr], :void
285  attach_function :g_object_get_property,
286      [:pointer, :string, GValue.ptr], :void
287end