require 'gir_ffi/base_argument_builder' module GirFFI # Implements building pre- and post-processing statements for arguments. class ArgumentBuilder < BaseArgumentBuilder def initialize var_gen, arginfo super var_gen, arginfo.name, arginfo.argument_type, arginfo.direction @arginfo = arginfo end def inarg if has_input_value? @array_arg.nil? ? @name : nil end end def retname if has_output_value? @retname ||= @var_gen.new_var end end def pre pr = [] if has_input_value? pr << fixed_array_size_check if needs_size_check? pr << array_length_assignment if is_array_length_parameter? end pr << set_function_call_argument pr end def post if has_output_value? value = output_value ["#{retname} = #{value}"] else [] end end private def output_value if is_caller_allocated_object? callarg elsif needs_outgoing_parameter_conversion? case specialized_type_tag when :enum, :flags "#{argument_class_name}[#{output_conversion_arguments}]" else "#{argument_class_name}.wrap(#{output_conversion_arguments})" end elsif is_fixed_length_array? "#{callarg}.to_sized_array_value #{array_size}" else "#{callarg}.to_value" end end def is_array_length_parameter? @array_arg end def needs_size_check? specialized_type_tag == :c && type_info.array_fixed_size > -1 end def is_fixed_length_array? specialized_type_tag == :c end def fixed_array_size_check size = type_info.array_fixed_size "GirFFI::ArgHelper.check_fixed_array_size #{size}, #{@name}, \"#{@name}\"" end def has_output_value? @direction == :inout || @direction == :out end def has_input_value? @direction == :inout || @direction == :in end def array_length_assignment arrname = @array_arg.name "#{@name} = #{arrname}.nil? ? 0 : #{arrname}.length" end def set_function_call_argument value = if @direction == :out if is_caller_allocated_object? "#{argument_class_name}.allocate" else "GirFFI::InOutPointer.for #{type_specification}" end else if needs_ingoing_parameter_conversion? ingoing_parameter_conversion else @name end end "#{callarg} = #{value}" end def is_caller_allocated_object? [:object, :struct].include?(specialized_type_tag) && @arginfo.caller_allocates? end def needs_outgoing_parameter_conversion? [ :array, :enum, :flags, :ghash, :glist, :gslist, :object, :struct, :strv ].include?(specialized_type_tag) end def needs_ingoing_parameter_conversion? @direction == :inout || [ :object, :struct, :callback, :utf8, :void, :glist, :gslist, :ghash, :array, :c, :zero_terminated, :strv ].include?(specialized_type_tag) end def ingoing_parameter_conversion case specialized_type_tag when :enum, :flags base = "#{argument_class_name}[#{parameter_conversion_arguments}]" "GirFFI::InOutPointer.from #{specialized_type_tag.inspect}, #{base}" when :object, :struct, :void, :glist, :gslist, :ghash, :array, :zero_terminated, :strv, :callback base = "#{argument_class_name}.from(#{parameter_conversion_arguments})" if has_output_value? if specialized_type_tag == :strv "GirFFI::InOutPointer.from #{type_specification}, #{base}" else "GirFFI::InOutPointer.from :pointer, #{base}" end else base end when :c, :utf8 if has_output_value? "GirFFI::InOutPointer.from #{parameter_conversion_arguments}" else "GirFFI::InPointer.from(#{parameter_conversion_arguments})" end else base = "#{parameter_conversion_arguments}" "GirFFI::InOutPointer.from #{specialized_type_tag.inspect}, #{base}" end end def output_conversion_arguments conversion_arguments "#{callarg}.to_value" end def parameter_conversion_arguments conversion_arguments @name end def self_t type_tag.inspect end end end