module FFI::Module::Library

Constants

DEFAULT_FLAGS

Public Class Methods

extended(target) click to toggle source
# File lib/ffi/module/library.rb, line 28
def self.extended(target)
        raise "Must only be extended by module, got #{target}!" unless target.kind_of?(::Module)
        
        target.instance_variable_set(:@ffi_libraries, Array.new)
        target.instance_variable_set(:@ffi_calling_convention, :default)
        target.instance_variable_set(:@ffi_type_map, Hash.new)
        target.instance_variable_set(:@ffi_enumerations, FFI::Enums.new)
end

Public Instance Methods

ffi_attach_function(name, argument_types, return_type = :void, as: name, **options) click to toggle source
# File lib/ffi/module/library.rb, line 56
def ffi_attach_function(name, argument_types, return_type = :void, as: name, **options)
        argument_types = argument_types.map{|type| self.ffi_find_type(type)}
        return_type = self.ffi_find_type(return_type)
        
        options[:convention] ||= @ffi_calling_convention
        options[:type_map] ||= @ffi_type_map
        options[:enums] ||= @ffi_enumerations
        
        invoker = nil
        
        @ffi_libraries.each do |library|
                function = nil
                
                ffi_function_names(name, argument_types).each do |function_name|
                        break if function = library.find_function(function_name.to_s)
                end
                
                if function
                        if argument_types.length > 0 && argument_types.last == FFI::NativeType::VARARGS
                                invoker = VariadicInvoker.new(function, argument_types, return_type, options)
                        else
                                invoker = Function.new(return_type, argument_types, function, options)
                        end
                        
                        break
                end
        end
        
        if invoker
                invoker.attach(self, as.to_s)
                return true
        else
                raise FFI::NotFoundError.new(name, @ffi_libraries)
        end
end
ffi_attach_variable(name, type, as: name) click to toggle source
# File lib/ffi/module/library.rb, line 92
def ffi_attach_variable(name, type, as: name)
        address = @ffi_libraries.find do |library|
                begin
                        library.find_variable(name)
                rescue LoadError
                end
        end
        
        if address.nil? || address.null?
                raise FFI::NotFoundError.new(name, @ffi_libraries)
        end
        
        if type.is_a?(Class) && type < FFI::Struct
                variable = type.new(address)
                
                self.define_singleton_method(as) do
                        variable
                end
        else
                container_type = Class.new(FFI::Struct)
                container_type.layout :value, self.ffi_find_type(type)
                container = container_type.new(address)
                
                self.define_singleton_method(as) do
                        container[:value]
                end
                
                self.define_singleton_method(:"#{as}=") do |value|
                        container[:value] = value
                end
        end
        
        return true
end
ffi_callback(argument_types, return_type, **options) click to toggle source
# File lib/ffi/module/library.rb, line 127
def ffi_callback(argument_types, return_type, **options)
        argument_types = argument_types.map{|type| self.ffi_find_type(type)}
        return_type = self.ffi_find_type(return_type)
        
        if argument_types.include?(FFI::Type::VARARGS)
                raise ArgumentError, "Callbacks cannot have variadic parameters!"
        end
        
        options[:convention] ||= @ffi_calling_convention
        options[:enums] ||= @ffi_enumerations
        
        if return_type == Type::STRING
                raise TypeError, "String is not allowed as return type of callbacks!"
        end
        
        return FFI::CallbackInfo.new(return_type, argument_types, options)
end
ffi_calling_convention(value = nil) click to toggle source
# File lib/ffi/module/library.rb, line 48
def ffi_calling_convention(value = nil)
        if value
                @ffi_calling_convention = value
        end
        
        return @ffi_calling_convention
end
ffi_define_bitmask(name, *arguments) click to toggle source
# File lib/ffi/module/library.rb, line 170
def ffi_define_bitmask(name, *arguments)
        native_type = arguments.first.kind_of?(FFI::Type) ? arguments.shift : nil
        
        ffi_define_generic_enumeration(name, FFI::Bitmask, native_type, *arguments)
end
ffi_define_callback(name, *arguments, **options) click to toggle source
# File lib/ffi/module/library.rb, line 145
def ffi_define_callback(name, *arguments, **options)
        callback = ffi_callback(*arguments, **options)
        
        ffi_define_type(name, callback)
        
        return callback
end
ffi_define_enumeration(name, *arguments) click to toggle source
# File lib/ffi/module/library.rb, line 164
def ffi_define_enumeration(name, *arguments)
        native_type = arguments.first.kind_of?(FFI::Type) ? arguments.shift : nil
        
        ffi_define_generic_enumeration(name, FFI::Enum, native_type, *arguments)
end
ffi_define_type(name, value) click to toggle source
# File lib/ffi/module/library.rb, line 153
def ffi_define_type(name, value)
        case value
        when FFI::Type
                @ffi_type_map[name] = value
        when FFI::DataConverter
                @ffi_type_map[name] = FFI::Type::Mapped.new(value)
        else
                @ffi_type_map[name] = self.ffi_find_type(value)
        end
end
ffi_find_type(argument) click to toggle source
# File lib/ffi/module/library.rb, line 176
def ffi_find_type(argument)
        if argument.kind_of?(Type)
                return argument
        end
        
        if type = @ffi_type_map[argument]
                return type
        end
        
        if argument.is_a?(Class) && argument < Struct
                return Type::POINTER
        end
        
        if argument.is_a?(DataConverter)
                # Cache the mapped type:
                return ffi_define_type(argument, Type::Mapped.new(argument))
        end
        
        if argument
                return FFI.find_type(argument)
        end
end
ffi_open_library(name = nil, flags: DEFAULT_FLAGS) click to toggle source
# File lib/ffi/module/library.rb, line 39
def ffi_open_library(name = nil, flags: DEFAULT_FLAGS)
        @ffi_libraries << DynamicLibrary.open(name, flags)
        
        return true
rescue LoadError, RuntimeError
        # TruffleRuby raises a RuntimeError if the library can't be found.
        return nil
end

Private Instance Methods

ffi_define_generic_enumeration(name, klass, native_type, values) click to toggle source
# File lib/ffi/module/library.rb, line 201
def ffi_define_generic_enumeration(name, klass, native_type, values)
        enumeration = nil
        
        if native_type
                enumeration = klass.new(native_type, values, name)
        else
                enumeration = klass.new(values, name)
        end
        
        @ffi_enumerations << enumeration
        
        ffi_define_type(name, enumeration)
        
        return enumeration
end
ffi_function_names(name, argument_types) click to toggle source
# File lib/ffi/module/library.rb, line 217
def ffi_function_names(name, argument_types)
        result = [name]
        
        if @ffi_calling_convention == :stdcall
                # Get the size of each parameter:
                size = argument_types.inject(0) do |total, argument|
                        size = argument.size
                        
                        # The size must be a multiple of 4:
                        size += (4 - size) % 4
                        
                        total + size
                end
                
                # win32 naming convention:
                result << "_#{name.to_s}@#{size}"
                
                # win64 naming convention:
                result << "#{name.to_s}@#{size}"
        end
        
        return result
end