* ext/fiddle/closure.c: Documentation for Fiddle

* ext/fiddle/lib/fiddle/import.rb: ditto
* ext/fiddle/lib/fiddle/value.rb: ditto
* ext/fiddle/lib/fiddle/pack.rb: ditto
* ext/fiddle/lib/fiddle/cparser.rb: ditto
* ext/fiddle/lib/fiddle/struct.rb: ditto
* ext/fiddle/lib/fiddle/function.rb: ditto



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37917 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
zzak 2012-11-28 02:08:39 +00:00
parent 0700a9113f
commit 4ed6a88b74
8 changed files with 139 additions and 40 deletions

View File

@ -1,3 +1,13 @@
Wed Nov 28 11:07:00 2012 Zachary Scott <zachary@zacharyscott.net>
* ext/fiddle/closure.c: Documentation for Fiddle
* ext/fiddle/lib/fiddle/import.rb: ditto
* ext/fiddle/lib/fiddle/value.rb: ditto
* ext/fiddle/lib/fiddle/pack.rb: ditto
* ext/fiddle/lib/fiddle/cparser.rb: ditto
* ext/fiddle/lib/fiddle/struct.rb: ditto
* ext/fiddle/lib/fiddle/function.rb: ditto
Wed Nov 28 09:15:51 2012 Ryan Davis <ryand-ruby@zenspider.com> Wed Nov 28 09:15:51 2012 Ryan Davis <ryand-ruby@zenspider.com>
* ext/strscan/strscan.c: Added #charpos for multibyte string position. * ext/strscan/strscan.c: Added #charpos for multibyte string position.

View File

@ -289,7 +289,7 @@ Init_fiddle_closure()
* Construct a new Closure object. * Construct a new Closure object.
* *
* * +ret+ is the C type to be returned * * +ret+ is the C type to be returned
* * +args+ are passed the callback * * +args+is an Array of arguments, passed to the callback function
* * +abi+ is the abi of the closure * * +abi+ is the abi of the closure
* *
* If there is an error in preparing the ffi_cif or ffi_prep_closure, * If there is an error in preparing the ffi_cif or ffi_prep_closure,

View File

@ -1,12 +1,25 @@
module Fiddle module Fiddle
# Methods for parsing C struct and C prototype signatures. # A mixin that provides methods for parsing C struct and prototype signatures.
#
# == Example
# require 'fiddle/import'
#
# include Fiddle::CParser
# #=> Object
#
# parse_ctype('int increment(int)')
# #=> ["increment", Fiddle::TYPE_INT, [Fiddle::TYPE_INT]]
#
module CParser module CParser
# Parses a C struct's members # Parses a C struct's members
# #
# Example: # Example:
# #
# include Fiddle::CParser
# #=> Object
#
# parse_struct_signature(['int i', 'char c']) # parse_struct_signature(['int i', 'char c'])
# => [[Fiddle::TYPE_INT, Fiddle::TYPE_CHAR], ["i", "c"]] # #=> [[Fiddle::TYPE_INT, Fiddle::TYPE_CHAR], ["i", "c"]]
# #
def parse_struct_signature(signature, tymap=nil) def parse_struct_signature(signature, tymap=nil)
if( signature.is_a?(String) ) if( signature.is_a?(String) )
@ -45,13 +58,17 @@ module Fiddle
# Parses a C prototype signature # Parses a C prototype signature
# #
# If Hash +tymap+ is provided, the return value and the arguments from the
# +signature+ are expected to be keys, and the value will be the C type to
# be looked up.
#
# Example: # Example:
# #
# include Fiddle::CParser # include Fiddle::CParser
# => Object # #=> Object
# #
# parse_signature('double sum(double, double)') # parse_signature('double sum(double, double)')
# => ["sum", Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE, Fiddle::TYPE_DOUBLE]] # #=> ["sum", Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE, Fiddle::TYPE_DOUBLE]]
# #
def parse_signature(signature, tymap=nil) def parse_signature(signature, tymap=nil)
tymap ||= {} tymap ||= {}
@ -74,24 +91,27 @@ module Fiddle
end end
end end
# Given a String of C type +ty+, return the corresponding DL constant. # Given a String of C type +ty+, returns the corresponding Fiddle constant.
# #
# +ty+ can also accept an Array of C type Strings, and will returned in a # +ty+ can also accept an Array of C type Strings, and will be returned in
# corresponding Array. # a corresponding Array.
# #
# If Hash +tymap+ is provided, +ty+ is expected to be the key, and the # If Hash +tymap+ is provided, +ty+ is expected to be the key, and the
# value will be the C type to be looked up. # value will be the C type to be looked up.
# #
# Example: # Example:
# #
# include Fiddle::CParser
# #=> Object
#
# parse_ctype('int') # parse_ctype('int')
# => Fiddle::TYPE_INT # #=> Fiddle::TYPE_INT
# #
# parse_ctype('double') # parse_ctype('double')
# => Fiddle::TYPE_DOUBLE # #=> Fiddle::TYPE_DOUBLE
# #
# parse_ctype('unsigned char') # parse_ctype('unsigned char')
# => -Fiddle::TYPE_CHAR # #=> -Fiddle::TYPE_CHAR
# #
def parse_ctype(ty, tymap=nil) def parse_ctype(ty, tymap=nil)
tymap ||= {} tymap ||= {}

View File

@ -6,6 +6,7 @@ module Fiddle
# The address of this function # The address of this function
attr_reader :ptr attr_reader :ptr
# The integer memory location of this function
def to_i def to_i
ptr.to_i ptr.to_i
end end

View File

@ -3,15 +3,25 @@ require 'fiddle/struct'
require 'fiddle/cparser' require 'fiddle/cparser'
module Fiddle module Fiddle
# Used internally by Fiddle::Importer
class CompositeHandler class CompositeHandler
# Create a new handler with the open +handlers+
#
# Used internally by Fiddle::Importer.dlload
def initialize(handlers) def initialize(handlers)
@handlers = handlers @handlers = handlers
end end
# Array of the currently loaded libraries.
def handlers() def handlers()
@handlers @handlers
end end
# Returns the address as an Integer from any handlers with the function
# named +symbol+.
#
# Raises a DLError if the handle is closed.
def sym(symbol) def sym(symbol)
@handlers.each{|handle| @handlers.each{|handle|
if( handle ) if( handle )
@ -25,22 +35,23 @@ module Fiddle
return nil return nil
end end
# See Fiddle::CompositeHandler.sym
def [](symbol) def [](symbol)
sym(symbol) sym(symbol)
end end
end end
# DL::Importer includes the means to dynamically load libraries and build # A DSL that provides the means to dynamically load libraries and build
# modules around them including calling extern functions within the C # modules around them including calling extern functions within the C
# library that has been loaded. # library that has been loaded.
# #
# == Example # == Example
# #
# require 'dl' # require 'fiddle'
# require 'dl/import' # require 'fiddle/import'
# #
# module LibSum # module LibSum
# extend DL::Importer # extend Fiddle::Importer
# dlload './libsum.so' # dlload './libsum.so'
# extern 'double sum(double*, int)' # extern 'double sum(double*, int)'
# extern 'double split(double)' # extern 'double split(double)'
@ -51,6 +62,13 @@ module Fiddle
include CParser include CParser
extend Importer extend Importer
# Creates an array of handlers for the given +libs+, can be an instance of
# Fiddle::Handle, Fiddle::Importer, or will create a new istance of
# Fiddle::Handle using Fiddle.dlopen
#
# Raises a DLError if the library cannot be loaded.
#
# See Fiddle.dlopen
def dlload(*libs) def dlload(*libs)
handles = libs.collect{|lib| handles = libs.collect{|lib|
case lib case lib
@ -73,10 +91,13 @@ module Fiddle
@type_alias = {} @type_alias = {}
end end
# Sets the type alias for +alias_type+ as +orig_type+
def typealias(alias_type, orig_type) def typealias(alias_type, orig_type)
@type_alias[alias_type] = orig_type @type_alias[alias_type] = orig_type
end end
# Returns the sizeof +ty+, using Fiddle::Importer.parse_ctype to determine
# the C type and the appropriate Fiddle constant.
def sizeof(ty) def sizeof(ty)
case ty case ty
when String when String
@ -126,6 +147,7 @@ module Fiddle
end end
private :parse_bind_options private :parse_bind_options
# Creates a global method from the given C +signature+.
def extern(signature, *opts) def extern(signature, *opts)
symname, ctype, argtype = parse_signature(signature, @type_alias) symname, ctype, argtype = parse_signature(signature, @type_alias)
opt = parse_bind_options(opts) opt = parse_bind_options(opts)
@ -148,6 +170,8 @@ module Fiddle
f f
end end
# Creates a global method from the given C +signature+ using the given
# +opts+ as bind parameters with the given block.
def bind(signature, *opts, &blk) def bind(signature, *opts, &blk)
name, ctype, argtype = parse_signature(signature, @type_alias) name, ctype, argtype = parse_signature(signature, @type_alias)
h = parse_bind_options(opts) h = parse_bind_options(opts)
@ -190,10 +214,15 @@ module Fiddle
Fiddle::CStructBuilder.create(CUnion, tys, mems) Fiddle::CStructBuilder.create(CUnion, tys, mems)
end end
# Returns the function mapped to +name+, that was created by either
# Fiddle::Importer.extern or Fiddle::Importer.bind
def [](name) def [](name)
@func_map[name] @func_map[name]
end end
# Creates a class to wrap the C struct with the value +ty+
#
# See also Fiddle::Importer.struct
def create_value(ty, val=nil) def create_value(ty, val=nil)
s = struct([ty + " value"]) s = struct([ty + " value"])
ptr = s.malloc() ptr = s.malloc()
@ -204,16 +233,28 @@ module Fiddle
end end
alias value create_value alias value create_value
# Returns a new instance of the C struct with the value +ty+ at the +addr+
# address.
def import_value(ty, addr) def import_value(ty, addr)
s = struct([ty + " value"]) s = struct([ty + " value"])
ptr = s.new(addr) ptr = s.new(addr)
return ptr return ptr
end end
# The Fiddle::CompositeHandler instance
#
# Will raise an error if no handlers are open.
def handler def handler
@handler or raise "call dlload before importing symbols and functions" @handler or raise "call dlload before importing symbols and functions"
end end
# 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
def import_symbol(name) def import_symbol(name)
addr = handler.sym(name) addr = handler.sym(name)
if( !addr ) if( !addr )
@ -222,6 +263,18 @@ module Fiddle
Pointer.new(addr) Pointer.new(addr)
end end
# 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
def import_function(name, ctype, argtype, call_type = nil) def import_function(name, ctype, argtype, call_type = nil)
addr = handler.sym(name) addr = handler.sym(name)
if( !addr ) if( !addr )
@ -230,6 +283,14 @@ module Fiddle
Function.new(addr, argtype, ctype, call_type) Function.new(addr, argtype, ctype, call_type)
end end
# 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
def bind_function(name, ctype, argtype, call_type = nil, &block) def bind_function(name, ctype, argtype, call_type = nil, &block)
closure = Class.new(Fiddle::Closure) { closure = Class.new(Fiddle::Closure) {
define_method(:call, block) define_method(:call, block)

View File

@ -1,7 +1,7 @@
require 'fiddle' require 'fiddle'
module Fiddle module Fiddle
module PackInfo module PackInfo # :nodoc: all
ALIGN_MAP = { ALIGN_MAP = {
TYPE_VOIDP => ALIGN_VOIDP, TYPE_VOIDP => ALIGN_VOIDP,
TYPE_CHAR => ALIGN_CHAR, TYPE_CHAR => ALIGN_CHAR,
@ -60,7 +60,7 @@ module Fiddle
module_function :align module_function :align
end end
class Packer class Packer # :nodoc: all
include PackInfo include PackInfo
def self.[](*types) def self.[](*types)

View File

@ -36,14 +36,14 @@ module Fiddle
# #
# Example: # Example:
# #
# require 'dl/struct' # require 'fiddle/struct'
# require 'dl/cparser' # require 'fiddle/cparser'
# #
# include Fiddle::CParser # include Fiddle::CParser
# #
# types, members = parse_struct_signature(['int i','char c']) # types, members = parse_struct_signature(['int i','char c'])
# #
# MyStruct = Fiddle::CStructBuilder.create(CUnion, types, members) # MyStruct = Fiddle::CStructBuilder.create(Fiddle::CUnion, types, members)
# #
# obj = MyStruct.allocate # obj = MyStruct.allocate
# #
@ -80,18 +80,21 @@ module Fiddle
include PackInfo include PackInfo
include ValueUtil include ValueUtil
# Allocates a C struct the +types+ provided. The C function +func+ is # Allocates a C struct with the +types+ provided.
# called when the instance is garbage collected. #
# When the instance is garbage collected, the C function +func+ is called.
def CStructEntity.malloc(types, func = nil) def CStructEntity.malloc(types, func = nil)
addr = Fiddle.malloc(CStructEntity.size(types)) addr = Fiddle.malloc(CStructEntity.size(types))
CStructEntity.new(addr, types, func) CStructEntity.new(addr, types, func)
end end
# Given +types+, returns the offset for the packed sizes of those types # Returns the offset for the packed sizes for the given +types+.
# #
# Fiddle::CStructEntity.size([Fiddle::TYPE_DOUBLE, Fiddle::TYPE_INT, Fiddle::TYPE_CHAR, # Fiddle::CStructEntity.size(
# Fiddle::TYPE_VOIDP]) # [ Fiddle::TYPE_DOUBLE,
# => 24 # Fiddle::TYPE_INT,
# Fiddle::TYPE_CHAR,
# Fiddle::TYPE_VOIDP ]) #=> 24
def CStructEntity.size(types) def CStructEntity.size(types)
offset = 0 offset = 0
@ -108,10 +111,11 @@ module Fiddle
PackInfo.align(offset, max_align) PackInfo.align(offset, max_align)
end end
# Wraps the C pointer +addr+ as a C struct with the given +types+. The C # Wraps the C pointer +addr+ as a C struct with the given +types+.
# function +func+ is called when the instance is garbage collected.
# #
# See also Fiddle::CPtr.new # When the instance is garbage collected, the C function +func+ is called.
#
# See also Fiddle::Pointer.new
def initialize(addr, types, func = nil) def initialize(addr, types, func = nil)
set_ctypes(types) set_ctypes(types)
super(addr, @size, func) super(addr, @size, func)
@ -122,8 +126,7 @@ module Fiddle
@members = members @members = members
end end
# Given +types+, calculate the offsets and sizes for the types in the # Calculates the offsets and sizes for the given +types+ in the struct.
# struct.
def set_ctypes(types) def set_ctypes(types)
@ctypes = types @ctypes = types
@offset = [] @offset = []
@ -207,25 +210,29 @@ module Fiddle
class CUnionEntity < CStructEntity class CUnionEntity < CStructEntity
include PackInfo include PackInfo
# Allocates a C union the +types+ provided. The C function +func+ is # Allocates a C union the +types+ provided.
# called when the instance is garbage collected. #
# When the instance is garbage collected, the C function +func+ is called.
def CUnionEntity.malloc(types, func=nil) def CUnionEntity.malloc(types, func=nil)
addr = Fiddle.malloc(CUnionEntity.size(types)) addr = Fiddle.malloc(CUnionEntity.size(types))
CUnionEntity.new(addr, types, func) CUnionEntity.new(addr, types, func)
end end
# Given +types+, returns the size needed for the union. # Returns the size needed for the union with the given +types+.
# #
# Fiddle::CUnionEntity.size([Fiddle::TYPE_DOUBLE, Fiddle::TYPE_INT, Fiddle::TYPE_CHAR, # Fiddle::CUnionEntity.size(
# Fiddle::TYPE_VOIDP]) # [ Fiddle::TYPE_DOUBLE,
# => 8 # Fiddle::TYPE_INT,
# Fiddle::TYPE_CHAR,
# Fiddle::TYPE_VOIDP ]) #=> 8
def CUnionEntity.size(types) def CUnionEntity.size(types)
types.map { |type, count = 1| types.map { |type, count = 1|
PackInfo::SIZE_MAP[type] * count PackInfo::SIZE_MAP[type] * count
}.max }.max
end end
# Given +types+, calculate the necessary offset and for each union member # Calculate the necessary offset and for each union member with the given
# +types+
def set_ctypes(types) def set_ctypes(types)
@ctypes = types @ctypes = types
@offset = Array.new(types.length, 0) @offset = Array.new(types.length, 0)

View File

@ -1,7 +1,7 @@
require 'fiddle' require 'fiddle'
module Fiddle module Fiddle
module ValueUtil module ValueUtil #:nodoc: all
def unsigned_value(val, ty) def unsigned_value(val, ty)
case ty.abs case ty.abs
when TYPE_CHAR when TYPE_CHAR