<commit_before>module GirFFI
  module Overrides
    module GObject

      def self.included base
	base.extend ClassMethods
        extend_classes(base)
        attach_non_introspectable_functions(base)
        build_extra_classes(base)
      end

      def self.extend_classes base
        base::InitiallyUnowned.extend InitiallyUnownedClassMethods
        base::Value.class_eval {
          include ValueInstanceMethods
          extend ValueClassMethods
        }
        base::Closure.class_eval {
          include ClosureInstanceMethods
        }
      end

      def self.attach_non_introspectable_functions base
        base::Lib.attach_function :g_signal_connect_data,
          [:pointer, :string, base::Callback, :pointer, base::ClosureNotify,
            base::ConnectFlags],
            :ulong
        base::Lib.attach_function :g_closure_set_marshal,
          [:pointer, base::ClosureMarshal], :void
      end

      def self.build_extra_classes base
        build_ruby_closure_class base
      end

      # Build the GObject::RubyClosure class. This class encapsulates Ruby
      # blocks as GObject Closures.
      def self.build_ruby_closure_class base
        klass = Class.new(base::Closure) do
          const_set :BLOCK_STORE, {}

          const_set :Struct, Class.new(FFI::Struct) {
            layout :parent, base::Closure::Struct, 0,
            :blockhash, :int64
          }

          def self.new &block
            raise ArgumentError unless block_given?
            wrap(new_simple(self::Struct.size, nil).to_ptr).tap do |it|
              h = block.object_id
              self::BLOCK_STORE[h] = block
              it[:blockhash] = h
              it.set_marshal Proc.new {|*args| marshaller(*args)}
            end
          end

          def self.marshaller(closure, return_value, n_param_values,
                              param_values, invocation_hint, marshal_data)
            rclosure = self.wrap(closure.to_ptr)

            args = []
            n_param_values.times {|i|
              gv = ::GObject::Value.wrap(param_values.to_ptr +
                                         i * ::GObject::Value::Struct.size)
              args << gv.ruby_value
            }

            r = rclosure.invoke_block(*args)
            return_value.set_ruby_value r unless return_value.nil?
          end

          def block
            self.class::BLOCK_STORE[self[:blockhash]]
          end

          def invoke_block *args
            block.call(*args)
          end
        end
        base.const_set :RubyClosure, klass
      end

      module ClassMethods
	# FIXME: These four helper methods belong elsewhere.
	def type_from_instance_pointer inst_ptr
	  base = ::GObject::TypeInstance.wrap inst_ptr
	  kls = ::GObject::TypeClass.wrap(base[:g_class])
	  kls[:g_type]
	end

	def type_from_instance instance
	  type_from_instance_pointer instance.to_ptr
	end

	def signal_emit object, signal, *args
	  type = type_from_instance object
	  id = signal_lookup signal, type

	  arr = Helper.signal_arguments_to_gvalue_array signal, object, *args
	  rval = Helper.gvalue_for_signal_return_value signal, object

	  signal_emitv arr[:values], id, 0, rval

	  rval
	end

	def signal_connect object, signal, data=nil, &block
	  sig = object.class._find_signal signal
	  if sig.nil?
	    raise "Signal #{signal} is invalid for #{object}"
	  end
	  if block.nil?
	    raise ArgumentError, "Block needed"
	  end

	  rettype = GirFFI::Builder.itypeinfo_to_ffitype sig.return_type

	  argtypes = GirFFI::Builder.ffi_argument_types_for_signal sig

	  callback = FFI::Function.new rettype, argtypes,
	    &(Helper.signal_callback_args(sig, object.class, &block))
          ::GObject::Lib::CALLBACKS << callback

          data_ptr = GirFFI::ArgHelper.object_to_inptr data

	  ::GObject::Lib.g_signal_connect_data object, signal, callback, data_ptr, nil, 0
	end
      end

      module Helper
        TAG_TYPE_TO_GTYPE_NAME_MAP = {
          :utf8 => "gchararray"
        }

	def self.signal_callback_args sig, klass, &block
	  return Proc.new do |*args|
	    mapped = cast_back_signal_arguments sig, klass, *args
	    block.call(*mapped)
	  end
	end

	def self.signal_arguments_to_gvalue_array signal, instance, *rest
	  sig = instance.class._find_signal signal

	  arr = ::GObject::ValueArray.new sig.n_args+1

          arr.append signal_reciever_to_gvalue instance

	  sig.args.zip(rest).each do |info, arg|
	    arr.append signal_argument_to_gvalue info, arg
	  end

	  arr
	end

        def self.signal_reciever_to_gvalue instance
          val = ::GObject::Value.new
          val.init ::GObject.type_from_instance instance
          val.set_instance instance
          return val
        end

	def self.signal_argument_to_gvalue info, arg
          arg_type = info.argument_type
          tag = arg_type.tag

	  if tag == :interface
	    interface = info.argument_type.interface

	    val = ::GObject::Value.new
	    val.init info.argument_type.interface.g_type
	    case interface.info_type
	    when :struct
	      val.set_boxed arg
	    when :object
	      val.set_instance arg
            when :enum
              val.set_enum arg
	    else
	      raise NotImplementedError, interface.info_type
	    end

	    return val
	  else
            val = ::GObject::Value.new
            val.init ::GObject.type_from_name(TAG_TYPE_TO_GTYPE_NAME_MAP[tag])
            val.set_ruby_value arg
	  end
	end

	def self.gvalue_for_signal_return_value signal, object
	  type = ::GObject.type_from_instance object

	  # TODO: Use same signal info as signal_arguments_to_gvalue_array
	  id = ::GObject.signal_lookup signal, type

	  query = ::GObject::SignalQuery.new
	  ::GObject.signal_query id, query

	  use_ret = (query[:return_type] != ::GObject.type_from_name("void"))
	  if use_ret
	    rval = ::GObject::Value.new
	    rval.init query[:return_type]
	  end
	  rval
	end

        # TODO: Generate cast back methods using existing Argument builders.
	def self.cast_back_signal_arguments signalinfo, klass, *args
	  result = []

	  # Instance
	  instptr = args.shift
	  instance = klass.wrap instptr
	  result << instance

	  # Extra arguments<commit_msg>Extract method converting ITypeInfo to a GValue.<commit_after>module GirFFI
  module Overrides
    module GObject

      def self.included base
	base.extend ClassMethods
        extend_classes(base)
        attach_non_introspectable_functions(base)
        build_extra_classes(base)
      end

      def self.extend_classes base
        base::InitiallyUnowned.extend InitiallyUnownedClassMethods
        base::Value.class_eval {
          include ValueInstanceMethods
          extend ValueClassMethods
        }
        base::Closure.class_eval {
          include ClosureInstanceMethods
        }
      end

      def self.attach_non_introspectable_functions base
        base::Lib.attach_function :g_signal_connect_data,
          [:pointer, :string, base::Callback, :pointer, base::ClosureNotify,
            base::ConnectFlags],
            :ulong
        base::Lib.attach_function :g_closure_set_marshal,
          [:pointer, base::ClosureMarshal], :void
      end

      def self.build_extra_classes base
        build_ruby_closure_class base
      end

      # Build the GObject::RubyClosure class. This class encapsulates Ruby
      # blocks as GObject Closures.
      def self.build_ruby_closure_class base
        klass = Class.new(base::Closure) do
          const_set :BLOCK_STORE, {}

          const_set :Struct, Class.new(FFI::Struct) {
            layout :parent, base::Closure::Struct, 0,
            :blockhash, :int64
          }

          def self.new &block
            raise ArgumentError unless block_given?
            wrap(new_simple(self::Struct.size, nil).to_ptr).tap do |it|
              h = block.object_id
              self::BLOCK_STORE[h] = block
              it[:blockhash] = h
              it.set_marshal Proc.new {|*args| marshaller(*args)}
            end
          end

          def self.marshaller(closure, return_value, n_param_values,
                              param_values, invocation_hint, marshal_data)
            rclosure = self.wrap(closure.to_ptr)

            args = []
            n_param_values.times {|i|
              gv = ::GObject::Value.wrap(param_values.to_ptr +
                                         i * ::GObject::Value::Struct.size)
              args << gv.ruby_value
            }

            r = rclosure.invoke_block(*args)
            return_value.set_ruby_value r unless return_value.nil?
          end

          def block
            self.class::BLOCK_STORE[self[:blockhash]]
          end

          def invoke_block *args
            block.call(*args)
          end
        end
        base.const_set :RubyClosure, klass
      end

      module ClassMethods
	# FIXME: These four helper methods belong elsewhere.
	def type_from_instance_pointer inst_ptr
	  base = ::GObject::TypeInstance.wrap inst_ptr
	  kls = ::GObject::TypeClass.wrap(base[:g_class])
	  kls[:g_type]
	end

	def type_from_instance instance
	  type_from_instance_pointer instance.to_ptr
	end

	def signal_emit object, signal, *args
	  type = type_from_instance object
	  id = signal_lookup signal, type

	  arr = Helper.signal_arguments_to_gvalue_array signal, object, *args
	  rval = Helper.gvalue_for_signal_return_value signal, object

	  signal_emitv arr[:values], id, 0, rval

	  rval
	end

	def signal_connect object, signal, data=nil, &block
	  sig = object.class._find_signal signal
	  if sig.nil?
	    raise "Signal #{signal} is invalid for #{object}"
	  end
	  if block.nil?
	    raise ArgumentError, "Block needed"
	  end

	  rettype = GirFFI::Builder.itypeinfo_to_ffitype sig.return_type

	  argtypes = GirFFI::Builder.ffi_argument_types_for_signal sig

	  callback = FFI::Function.new rettype, argtypes,
	    &(Helper.signal_callback_args(sig, object.class, &block))
          ::GObject::Lib::CALLBACKS << callback

          data_ptr = GirFFI::ArgHelper.object_to_inptr data

	  ::GObject::Lib.g_signal_connect_data object, signal, callback, data_ptr, nil, 0
	end
      end

      module Helper
        TAG_TYPE_TO_GTYPE_NAME_MAP = {
          :utf8 => "gchararray"
        }

	def self.signal_callback_args sig, klass, &block
	  return Proc.new do |*args|
	    mapped = cast_back_signal_arguments sig, klass, *args
	    block.call(*mapped)
	  end
	end

	def self.signal_arguments_to_gvalue_array signal, instance, *rest
	  sig = instance.class._find_signal signal

	  arr = ::GObject::ValueArray.new sig.n_args+1

          arr.append signal_reciever_to_gvalue instance

	  sig.args.zip(rest).each do |info, arg|
	    arr.append signal_argument_to_gvalue info, arg
	  end

	  arr
	end

        def self.signal_reciever_to_gvalue instance
          val = ::GObject::Value.new
          val.init ::GObject.type_from_instance instance
          val.set_instance instance
          return val
        end

	def self.signal_argument_to_gvalue info, arg
          arg_type = info.argument_type

          val = gvalue_for_type_info arg_type

	  if arg_type.tag == :interface
	    interface = arg_type.interface
	    case interface.info_type
	    when :struct
	      val.set_boxed arg
	    when :object
	      val.set_instance arg
            when :enum
              val.set_enum arg
	    else
	      raise NotImplementedError, interface.info_type
	    end
	  else
            val.set_ruby_value arg
	  end

          return val
	end

        def self.gvalue_for_type_info info
          tag = info.tag
          gtype = if tag == :interface
                    info.interface.g_type
                  else
                    ::GObject.type_from_name(TAG_TYPE_TO_GTYPE_NAME_MAP[tag])
                  end
          ::GObject::Value.new.tap {|val| val.init gtype}
        end

	def self.gvalue_for_signal_return_value signal, object
	  type = ::GObject.type_from_instance object

	  # TODO: Use same signal info as signal_arguments_to_gvalue_array
	  id = ::GObject.signal_lookup signal, type

	  query = ::GObject::SignalQuery.new
	  ::GObject.signal_query id, query

	  use_ret = (query[:return_type] != ::GObject.type_from_name("void"))
	  if use_ret
	    rval = ::GObject::Value.new
	    rval.init query[:return_type]
	  end
	  rval
	end

        # TODO: Generate cast back methods using existing Argument builders.
	def self.cast_back_signal_arguments signalinfo, klass, *args
	  result = []

	  # Instance
	  instptr = args.shift
	  instance = klass.wrap instptr
	  result << instance

	  # Extra arguments
{'fraction_non_alphanumeric': 0.07837040580403412, 'fraction_numerical': 0.0011161604081958065, 'mean_word_length': 2.4003795066413662, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '950093', 'n_tokens_mistral': 3972, 'n_tokens_neox': 3705, 'n_words': 850}