# module Fiddle::Importer

A DSL that provides the means to dynamically load libraries and build modules around them including calling extern functions within the C library that has been loaded.

## Example¶ ↑

    require 'fiddle'
    require 'fiddle/import'

    module LibSum
      extend Fiddle::Importer
      dlload './libsum.so'
      extern 'double sum(double*, int)'
      extern 'double split(double)'
    end

### Attributes

type_alias[R]

### Public Instance Methods

[](name) click to toggle source

Returns the function mapped to `name`, that was created by either `Fiddle::Importer.extern` or `Fiddle::Importer.bind`

    # File ext/fiddle/lib/fiddle/import.rb, line 237
    def [](name)
      @func_map[name]
    end

bind(signature, *opts, &blk) click to toggle source

Creates a global method from the given C `signature` using the given `opts` as bind parameters with the given block.

    # File ext/fiddle/lib/fiddle/import.rb, line 193
        def bind(signature, *opts, &blk)
          name, ctype, argtype = parse_signature(signature, type_alias)
          h = parse_bind_options(opts)
          case h[:callback_type]
          when :bind, nil
            f = bind_function(name, ctype, argtype, h[:call_type], &blk)
          else
            raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
          end
          @func_map[name] = f
          #define_method(name){|*args,&block| f.call(*args,&block)}
          begin
            /^(.+?):(\d+)/ =~ caller.first
            file, line = $1, $2.to_i
          rescue
            file, line = __FILE__, __LINE__+3
          end
          module_eval(<<-EOS, file, line)
            def #{name}(*args,&block)
              @func_map['#{name}'].call(*args,&block)
            end
          EOS
          module_function(name)
          f
        end

bind_function(name, ctype, argtype, call_type = nil, &block) click to toggle source

Returns a new closure wrapper for the `name` function.

- `ctype` is the return type of the function

- `argtype` is an `Array` of arguments, passed to the callback function

- `call_type` is the abi of the closure

- `block` is passed to the callback

See `Fiddle::Closure`

    # File ext/fiddle/lib/fiddle/import.rb, line 313
    def bind_function(name, ctype, argtype, call_type = nil, &block)
      abi = CALL_TYPE_TO_ABI[call_type]
      closure = Class.new(Fiddle::Closure) {
        define_method(:call, block)
      }.new(ctype, argtype, abi)

      Function.new(closure, argtype, ctype, abi, name: name)
    end

create_value(ty, val=nil) click to toggle source

Creates a class to wrap the C struct with the value `ty`

See also `Fiddle::Importer.struct`

    # File ext/fiddle/lib/fiddle/import.rb, line 244
    def create_value(ty, val=nil)
      s = struct([ty + " value"])
      ptr = s.malloc()
      if( val )
        ptr.value = val
      end
      return ptr
    end

Also aliased as: value
dlload(*libs) click to toggle source

Creates an array of handlers for the given `libs`, can be an instance of `Fiddle::Handle`, `Fiddle::Importer`, or will create a new instance of `Fiddle::Handle` using `Fiddle.dlopen`

Raises a `DLError` if the library cannot be loaded.

See `Fiddle.dlopen`

    # File ext/fiddle/lib/fiddle/import.rb, line 76
    def dlload(*libs)
      handles = libs.collect{|lib|
        case lib
        when nil
          nil
        when Handle
          lib
        when Importer
          lib.handlers
        else
          begin
            Fiddle.dlopen(lib)
          rescue DLError
            raise(DLError, "can't load #{lib}")
          end
        end
      }.flatten()
      @handler = CompositeHandler.new(handles)
      @func_map = {}
      @type_alias = {}
    end

extern(signature, *opts) click to toggle source

Creates a global method from the given C `signature`.

    # File ext/fiddle/lib/fiddle/import.rb, line 169
        def extern(signature, *opts)
          symname, ctype, argtype = parse_signature(signature, type_alias)
          opt = parse_bind_options(opts)
          f = import_function(symname, ctype, argtype, opt[:call_type])
          name = symname.gsub(/@.+/,'')
          @func_map[name] = f
          # define_method(name){|*args,&block| f.call(*args,&block)}
          begin
            /^(.+?):(\d+)/ =~ caller.first
            file, line = $1, $2.to_i
          rescue
            file, line = __FILE__, __LINE__+3
          end
          module_eval(<<-EOS, file, line)
            def #{name}(*args, &block)
              @func_map['#{name}'].call(*args,&block)
            end
          EOS
          module_function(name)
          f
        end

handler() click to toggle source

The `Fiddle::CompositeHandler` instance

Will raise an error if no handlers are open.

    # File ext/fiddle/lib/fiddle/import.rb, line 266
    def handler
      (@handler ||= nil) or raise "call dlload before importing symbols and functions"
    end

import_function(name, ctype, argtype, call_type = nil) click to toggle source

Returns a new `Fiddle::Function` instance at the memory address of the given `name` function.

Raises a `DLError` if the `name` doesn't exist.

- `argtype` is an `Array` of arguments, passed to the `name` function.

- `ctype` is the return type of the function

- `call_type` is the ABI of the function

See also Fiddle:Function.new

See `Fiddle::CompositeHandler.sym` and Fiddle::Handler.sym

    # File ext/fiddle/lib/fiddle/import.rb, line 296
    def import_function(name, ctype, argtype, call_type = nil)
      addr = handler.sym(name)
      if( !addr )
        raise(DLError, "cannot find the function: #{name}()")
      end
      Function.new(addr, argtype, ctype, CALL_TYPE_TO_ABI[call_type],
                   name: name)
    end

import_symbol(name) click to toggle source

Returns a new `Fiddle::Pointer` instance at the memory address of the given `name` symbol.

Raises a `DLError` if the `name` doesn't exist.

See `Fiddle::CompositeHandler.sym` and `Fiddle::Handle.sym`

    # File ext/fiddle/lib/fiddle/import.rb, line 276
    def import_symbol(name)
      addr = handler.sym(name)
      if( !addr )
        raise(DLError, "cannot find the symbol: #{name}")
      end
      Pointer.new(addr)
    end

import_value(ty, addr) click to toggle source

Returns a new instance of the C struct with the value `ty` at the `addr` address.

    # File ext/fiddle/lib/fiddle/import.rb, line 256
    def import_value(ty, addr)
      s = struct([ty + " value"])
      ptr = s.new(addr)
      return ptr
    end

sizeof(ty) click to toggle source

Returns the sizeof `ty`, using `Fiddle::Importer.parse_ctype` to determine the C type and the appropriate `Fiddle` constant.

    # File ext/fiddle/lib/fiddle/import.rb, line 105
    def sizeof(ty)
      case ty
      when String
        ty = parse_ctype(ty, type_alias).abs()
        case ty
        when TYPE_CHAR
          return SIZEOF_CHAR
        when TYPE_SHORT
          return SIZEOF_SHORT
        when TYPE_INT
          return SIZEOF_INT
        when TYPE_LONG
          return SIZEOF_LONG
        when TYPE_FLOAT
          return SIZEOF_FLOAT
        when TYPE_DOUBLE
          return SIZEOF_DOUBLE
        when TYPE_VOIDP
          return SIZEOF_VOIDP
        else
          if defined?(TYPE_LONG_LONG) and
            ty == TYPE_LONG_LONG
            return SIZEOF_LONG_LONG
          else
            raise(DLError, "unknown type: #{ty}")
          end
        end
      when Class
        if( ty.instance_methods().include?(:to_ptr) )
          return ty.size()
        end
      end
      return Pointer[ty].size()
    end

struct(signature) click to toggle source

Creates a class to wrap the C struct described by `signature`.

    MyStruct = struct ['int i', 'char c']

    # File ext/fiddle/lib/fiddle/import.rb, line 222
    def struct(signature)
      tys, mems = parse_struct_signature(signature, type_alias)
      Fiddle::CStructBuilder.create(CStruct, tys, mems)
    end

typealias(alias_type, orig_type) click to toggle source

Sets the type alias for `alias_type` as `orig_type`

    # File ext/fiddle/lib/fiddle/import.rb, line 99
    def typealias(alias_type, orig_type)
      @type_alias[alias_type] = orig_type
    end

union(signature) click to toggle source

Creates a class to wrap the C union described by `signature`.

    MyUnion = union ['int i', 'char c']

    # File ext/fiddle/lib/fiddle/import.rb, line 230
    def union(signature)
      tys, mems = parse_struct_signature(signature, type_alias)
      Fiddle::CStructBuilder.create(CUnion, tys, mems)
    end

value(ty, val=nil)
Alias for: create_value

### Private Instance Methods

parse_bind_options(opts) click to toggle source

    # File ext/fiddle/lib/fiddle/import.rb, line 140
    def parse_bind_options(opts)
      h = {}
      while( opt = opts.shift() )
        case opt
        when :stdcall, :cdecl
          h[:call_type] = opt
        when :carried, :temp, :temporal, :bind
          h[:callback_type] = opt
          h[:carrier] = opts.shift()
        else
          h[opt] = true
        end
      end
      h
    end