summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSylvain Daubert <sylvain.daubert@laposte.net>2011-09-21 21:48:06 +0200
committerSylvain Daubert <sylvain.daubert@laposte.net>2011-09-21 21:48:06 +0200
commit3d7d45fe5482e123fc9b301bd669cce44a214535 (patch)
tree5bbad303eaf15b2d920f70e6b94a03b7f58a38df /lib
parent1888bad66bbda21edf8d94dc3ff35736bda6c66f (diff)
downloadffi-3d7d45fe5482e123fc9b301bd669cce44a214535.tar.gz
Add documentation for DataConverter, LastError, AutoPointer, FFI::IO, Library, Platform and FFI class methods from types.rb.
Diffstat (limited to 'lib')
-rw-r--r--lib/ffi/autopointer.rb89
-rw-r--r--lib/ffi/errno.rb7
-rw-r--r--lib/ffi/io.rb15
-rw-r--r--lib/ffi/library.rb176
-rw-r--r--lib/ffi/platform.rb13
-rw-r--r--lib/ffi/types.rb2
6 files changed, 244 insertions, 58 deletions
diff --git a/lib/ffi/autopointer.rb b/lib/ffi/autopointer.rb
index 222c4e7..7e6eed0 100644
--- a/lib/ffi/autopointer.rb
+++ b/lib/ffi/autopointer.rb
@@ -23,17 +23,31 @@ module FFI
class AutoPointer < Pointer
extend DataConverter
- # call-seq:
- # AutoPointer.new(pointer, method) => the passed Method will be invoked at GC time
- # AutoPointer.new(pointer, proc) => the passed Proc will be invoked at GC time (SEE WARNING BELOW!)
- # AutoPointer.new(pointer) { |p| ... } => the passed block will be invoked at GC time (SEE WARNING BELOW!)
- # AutoPointer.new(pointer) => the pointer's release() class method will be invoked at GC time
+ # @overload initialize(pointer, method)
+ # @param [Pointer] pointer
+ # @param [Method] method
+ # @return [self]
+ # The passed Method will be invoked at GC time.
+ # @overload initialize(pointer, proc)
+ # @param [Pointer] pointer
+ # @return [self]
+ # The passed Proc will be invoked at GC time (SEE WARNING BELOW!)
+ # @note WARNING: passing a proc _may_ cause your pointer to never be GC'd, unless you're
+ # careful to avoid trapping a reference to the pointer in the proc. See the test
+ # specs for examples.
+ # @overload initialize(pointer) { |p| ... }
+ # @param [Pointer] pointer
+ # @yieldparam [Pointer] p +pointer+ passed to the block
+ # @return [self]
+ # The passed block will be invoked at GC time.
+ # @note WARNING: passing a block will cause your pointer to never be GC'd. This is bad.
+ # @overload initialize(pointer)
+ # @param [Pointer] pointer
+ # @return [self]
+ # The pointer's release() class method will be invoked at GC time.
#
- # WARNING: passing a proc _may_ cause your pointer to never be GC'd, unless you're careful to avoid trapping a reference to the pointer in the proc. See the test specs for examples.
- # WARNING: passing a block will cause your pointer to never be GC'd. This is bad.
- #
- # Please note that the safest, and therefore preferred, calling
- # idiom is to pass a Method as the second parameter. Example usage:
+ # @note The safest, and therefore preferred, calling
+ # idiom is to pass a Method as the second parameter. Example usage:
#
# class PointerHelper
# def self.release(pointer)
@@ -43,12 +57,12 @@ module FFI
#
# p = AutoPointer.new(other_pointer, PointerHelper.method(:release))
#
- # The above code will cause PointerHelper#release to be invoked at GC time.
- #
- # The last calling idiom (only one parameter) is generally only
- # going to be useful if you subclass AutoPointer, and override
- # release(), which by default does nothing.
+ # The above code will cause PointerHelper#release to be invoked at GC time.
#
+ # @note
+ # The last calling idiom (only one parameter) is generally only
+ # going to be useful if you subclass {AutoPointer}, and override
+ # #release, which by default does nothing.
def initialize(ptr, proc=nil, &block)
super(ptr)
raise TypeError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
@@ -67,21 +81,36 @@ module FFI
self
end
+ # @return [nil]
+ # Free the pointer.
def free
@releaser.free
end
+ # @param [Boolean] autorelease
+ # @return [Boolean] +autorelease+
+ # Set +autorelease+ property. See {Pointer Autorelease section at Pointer}.
def autorelease=(autorelease)
@releaser.autorelease=(autorelease)
end
+ # @abstract Base class for {AutoPointer}'s releasers.
+ #
+ # All subclasses of Releaser should define a +#release(ptr)+ method.
+ # A releaser is an object in charge of release an {AutoPointer}.
class Releaser
+ # @param [Pointer] ptr
+ # @param [#call] proc
+ # @return [nil]
+ # A new instance of Releaser.
def initialize(ptr, proc)
@ptr = ptr
@proc = proc
@autorelease = true
end
+ # @return [nil]
+ # Free pointer.
def free
if @ptr
release(@ptr)
@@ -91,33 +120,61 @@ module FFI
end
end
+ # @param [Boolean] autorelease
+ # @return [Boolean] autorelease
+ # Set +autorelease+ attribute for pointer managed by Releaser.
def autorelease=(autorelease)
@autorelease = autorelease if @ptr
end
+ # @param args
+ # Release pointer if +autorelease+ is set.
def call(*args)
release(@ptr) if @autorelease && @ptr
end
-
+
end
+ # DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined without Proc
+ # or Method. In this case, the pointer to release must be of a class derived from
+ # AutoPointer with a +#release+ class method.
class DefaultReleaser < Releaser
+ # @param [Pointer] ptr
+ # @return [nil]
+ # Release +ptr+ by using his #release class method.
def release(ptr)
@proc.release(ptr)
end
end
+ # CallableReleaser is a {Releaser} used when an {AutoPointer} is defined with a
+ # Proc or a Method.
class CallableReleaser < Releaser
+ # @param [Pointer] ptr
+ # @return [nil]
+ # Release +ptr+ by using Proc or Method defined at +ptr+ {AutoPointer#initialize initialization}.
def release(ptr)
@proc.call(ptr)
end
end
+ # Return native type of AutoPointer.
+ #
+ # Override {DataConverter#native_type}.
+ # @return [Type::POINTER]
+ # @raise {RuntimeError} if class does not implement a +#release+ method
def self.native_type
raise RuntimeError.new("no release method defined for #{self.inspect}") unless self.respond_to?(:release)
Type::POINTER
end
+ # Create a new AutoPointer.
+ #
+ # Override {DataConverter#from_native}.
+ # @overload self.from_native(ptr, ctx)
+ # @param [Pointer] ptr
+ # @param ctx not used. Please set +nil+.
+ # @return [AutoPointer]
def self.from_native(val, ctx)
self.new(val)
end
diff --git a/lib/ffi/errno.rb b/lib/ffi/errno.rb
index e3a6439..d419062 100644
--- a/lib/ffi/errno.rb
+++ b/lib/ffi/errno.rb
@@ -19,10 +19,15 @@
#
module FFI
+ # @return (see FFI::LastError.error)
+ # @see FFI::LastError.error
def self.errno
FFI::LastError.error
end
+ # @param error (see FFI::LastError.error=)
+ # @return (see FFI::LastError.error=)
+ # @see FFI::LastError.error=
def self.errno=(error)
FFI::LastError.error = error
end
-end \ No newline at end of file
+end
diff --git a/lib/ffi/io.rb b/lib/ffi/io.rb
index b936e25..3a81714 100644
--- a/lib/ffi/io.rb
+++ b/lib/ffi/io.rb
@@ -19,15 +19,26 @@
#
module FFI
+
+ # This module implements a couple of class methods to play with IO.
module IO
+ # @param [Integer] fd file decriptor
+ # @param [String] mode mode string
+ # @return [::IO]
+ # Synonym for IO::for_fd.
def self.for_fd(fd, mode = "r")
::IO.for_fd(fd, mode)
end
+ # @param [#read] io io to read from
+ # @param [AbstractMemory] buf destination for data read from +io+
+ # @param [nil, Numeric] len maximul number of bytes to read from +io+. If +nil+,
+ # read until end of file.
+ # @return [Numeric] length really read, in bytes
#
- # A version of IO#read that reads into a native buffer
+ # A version of IO#read that reads data from an IO and put then into a native buffer.
#
- # This will be optimized at some future time to eliminate the double copy
+ # This will be optimized at some future time to eliminate the double copy.
#
def self.native_read(io, buf, len)
tmp = io.read(len)
diff --git a/lib/ffi/library.rb b/lib/ffi/library.rb
index 8ab4830..5626d9d 100644
--- a/lib/ffi/library.rb
+++ b/lib/ffi/library.rb
@@ -21,6 +21,16 @@
module FFI
CURRENT_PROCESS = USE_THIS_PROCESS_AS_LIBRARY = Object.new
+ # @param [#to_s] lib library name
+ # @return [String] library name formatted for current platform
+ # Transform a generic library name to a platform library name
+ # @example
+ # # Linux
+ # FFI.map_library_name 'c' # -> "libc.so.6"
+ # FFI.map_library_name 'jpeg' # -> "libjpeg.so"
+ # # Windows
+ # FFI.map_library_name 'c' # -> "msvcrt.dll"
+ # FFI.map_library_name 'jpeg' # -> "jpeg.dll"
def self.map_library_name(lib)
# Mangle the library name to reflect the native library naming conventions
lib = lib.to_s unless lib.kind_of?(String)
@@ -35,20 +45,44 @@ module FFI
lib
end
+ # Exception raised when a function is not found in libraries
class NotFoundError < LoadError
def initialize(function, *libraries)
super("Function '#{function}' not found in [#{libraries[0].nil? ? 'current process' : libraries.join(", ")}]")
end
end
+ # This module is the base to use native functions.
+ #
+ # A basic usage may be:
+ # require 'ffi'
+ #
+ # module Hello
+ # extend FFI::Library
+ # ffi_lib FFI::Library::LIBC
+ # attach_function 'puts', [ :string ], :int
+ # end
+ #
+ # Hello.puts("Hello, World")
+ #
+ #
module Library
CURRENT_PROCESS = FFI::CURRENT_PROCESS
LIBC = FFI::Platform::LIBC
+ # @param mod extended object
+ # @return [nil]
+ # @raise {RuntimeError} if +mod+ is not a Module
+ # Test if extended object is a Module. If not, raise RuntimeError.
def self.extended(mod)
raise RuntimeError.new("must only be extended by module") unless mod.kind_of?(Module)
end
+
+ # @param [Array] names names of libraries to load
+ # @return [Array<DynamicLibrary>]
+ # @raise {LoadError} if a library cannot be opened
+ # Load native libraries.
def ffi_lib(*names)
lib_flags = defined?(@ffi_lib_flags) ? @ffi_lib_flags : FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_LOCAL
ffi_libs = names.map do |name|
@@ -109,6 +143,7 @@ module FFI
# @see #ffi_lib
# @return [Array<FFI::DynamicLibrary>] array of currently loaded FFI libraries
# @raise [LoadError] if no libraries have been loaded (using {#ffi_lib})
+ # Get FFI libraries loaded using {#ffi_lib}.
def ffi_libraries
raise LoadError.new("no library specified") if !defined?(@ffi_libs) || @ffi_libs.empty?
@ffi_libs
@@ -125,7 +160,7 @@ module FFI
:now => DynamicLibrary::RTLD_NOW
}
- # Sets library flags for {#ffi_lib}
+ # Sets library flags for {#ffi_lib}.
#
# @example
# ffi_lib_flags(:lazy, :local) # => 5
@@ -139,25 +174,24 @@ module FFI
##
# @overload attach_function(func, args, returns, options = {})
+ # @example attach function without an explicit name
+ # module Foo
+ # extend FFI::Library
+ # ffi_lib FFI::Library::LIBC
+ # attach_function :malloc, [:size_t], :pointer
+ # end
+ # # now callable via Foo.malloc
# @overload attach_function(name, func, args, returns, options = {})
+ # @example attach function with an explicit name
+ # module Bar
+ # extend FFI::Library
+ # ffi_lib FFI::Library::LIBC
+ # attach_function :c_malloc, :malloc, [:size_t], :pointer
+ # end
+ # # now callable via Bar.c_malloc
#
# Attach C function +func+ to this module.
#
- # @example attach function without an explicit name
- # module Foo
- # extend FFI::Library
- # ffi_lib FFI::Library::LIBC
- # attach_function :malloc, [:size_t], :pointer
- # end
- # # now callable via Foo.malloc
- #
- # @example attach function with an explicit name
- # module Bar
- # extend FFI::Library
- # ffi_lib FFI::Library::LIBC
- # attach_function :c_malloc, :malloc, [:size_t], :pointer
- # end
- # # now callable via Bar.c_malloc
#
# @param [#to_s] name name of ruby method to attach as
# @param [#to_s] func name of C function to attach
@@ -165,10 +199,10 @@ module FFI
# @param [Symbol] returns type of return value
# @option options [Boolean] :blocking (@blocking) set to true if the C function is a blocking call
# @option options [Symbol] :convention (:default) calling convention (see {#ffi_convention})
- # @option options :enums
- # @option options :type_map
+ # @option options [FFI::Enums] :enums
+ # @option options [Hash] :type_map
#
- # @return [FFI::VariadicInvoker, FFI::Function]
+ # @return [FFI::VariadicInvoker]
#
# @raise [FFI::NotFoundError] if +func+ cannot be found in the attached libraries (see {#ffi_lib})
def attach_function(name, func, args, returns = nil, options = nil)
@@ -216,18 +250,17 @@ module FFI
invoker
end
+ # @param [#to_s] name function name
+ # @param [Array] arg_types function's argument types
+ # @return [Array<String>]
+ # This function returns a list of possible names to lookup.
+ # @note Function names on windows may be decorated if they are using stdcall. See
+ # * http://en.wikipedia.org/wiki/Name_mangling#C_name_decoration_in_Microsoft_Windows
+ # * http://msdn.microsoft.com/en-us/library/zxk0tw93%28v=VS.100%29.aspx
+ # * http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions#STDCALL
+ # Note that decorated names can be overridden via def files. Also note that the
+ # windows api, although using, doesn't have decorated names.
def function_names(name, arg_types)
- # Function names on windows may be decorated if they are using stdcall. See
- #
- # http://en.wikipedia.org/wiki/Name_mangling#C_name_decoration_in_Microsoft_Windows
- # http://msdn.microsoft.com/en-us/library/zxk0tw93%28v=VS.100%29.aspx
- # http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions#STDCALL
- #
- # Note that decorated names can be overridden via def files. Also note that the
- # windows api, although using, doesn't have decorated names.
- #
- # This function returns a list of possible names to lookup.
-
result = [name.to_s]
if @ffi_convention == :stdcall
# Get the size of each parameter
@@ -244,6 +277,29 @@ module FFI
result
end
+ # @overload attach_variable(mname, cname, type)
+ # @example
+ # module Bar
+ # extend FFI::Library
+ # ffi_lib 'my_lib'
+ # attach_variable :c_myvar, :myvar, :long
+ # end
+ # # now callable via Bar.c_myvar
+ # @overload attach_variable(cname, type)
+ # @example
+ # module Bar
+ # extend FFI::Library
+ # ffi_lib 'my_lib'
+ # attach_variable :myvar, :long
+ # end
+ # # now callable via Bar.myvar
+ # @param [#to_s] mname name of ruby method to attach as
+ # @param [#to_s] cname name of C variable to attach
+ # @param [DataConverter, Struct, Symbol, Type] type C varaible's type
+ # @return [DynamicLibrary::Symbol]
+ # @raise {FFI::NotFoundError} if +cname+ cannot be found in libraries
+ #
+ # Attach C variable +cname+ to this module.
def attach_variable(mname, a1, a2 = nil)
cname, type = a2 ? [ a1, a2 ] : [ mname.to_s, a1 ]
address = nil
@@ -264,7 +320,7 @@ module FFI
def self.#{mname}
@@ffi_gvar_#{mname}
end
- code
+code
else
sc = Class.new(FFI::Struct)
@@ -288,6 +344,13 @@ module FFI
address
end
+
+ # @overload callback(name, params, ret)
+ # @overload callback(params, ret)
+ # @param name callback name to add to type map
+ # @param [Array] params array of parameters' types
+ # @param [DataConverter, Struct, Symbol, Type] ret callback return type
+ # @return [FFI::CallbackInfo]
def callback(*args)
raise ArgumentError, "wrong number of arguments" if args.length < 2 || args.length > 3
name, params, ret = if args.length == 3
@@ -309,6 +372,22 @@ module FFI
cb
end
+ # @param [DataConverter, Symbol, Type] old
+ # @param add
+ # @param [] info
+ # @return [FFI::Enum, FFI::Type]
+ # Register or get an already registered type definition.
+ #
+ # To register a new type definition, +old+ should be a {FFI::Type}. +add+
+ # is in this case the type definition.
+ #
+ # If +old+ is a {DataConverter}, a {Type::Mapped} is returned.
+ #
+ # If +old+ is +:enum+
+ # * and +add+ is an +Array+, a call to {#enum} is made with +add+ as single parameter;
+ # * in others cases, +info+ is used to create a named enum.
+ #
+ # If +old+ is a key for type map, #typedef get +old+ type definition.
def typedef(old, add, info=nil)
@ffi_typedefs = Hash.new unless defined?(@ffi_typedefs)
@@ -333,13 +412,25 @@ module FFI
end
end
+ # @overload enum(name, values)
+ # Create a named enum.
+ # @example
+ # enum :foo, [:zero, :one, :two] # named enum
+ # @param [Symbol] name name for new enum
+ # @param [Array] values values for enum
+ # @overload enum(*args)
+ # Create an unnamed enum.
+ # @example
+ # enum :zero, :one, :two # unnamed enum
+ # @param args values for enum
+ # @overload enum(values)
+ # Create an unnamed enum.
+ # @example
+ # enum [:zero, :one, :two] # unnamed enum, equivalent to above example
+ # @param [Array] values values for enum
+ # @return [FFI::Enum]
+ # Create a new {FFI::Enum}.
def enum(*args)
- #
- # enum can be called as:
- # enum :zero, :one, :two # unnamed enum
- # enum [ :zero, :one, :two ] # equivalent to above
- # enum :foo, [ :zero, :one, :two ] create an enum named :foo
- #
name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array)
[ args[0], args[1] ]
elsif args[0].kind_of?(Array)
@@ -355,14 +446,23 @@ module FFI
e
end
+ # @param name
+ # @return [FFI::Enum]
+ # Find an enum by name.
def enum_type(name)
@ffi_enums.find(name) if defined?(@ffi_enums)
end
+ # @param symbol
+ # @return [FFI::Enum]
+ # Find an enum by a symbol it contains.
def enum_value(symbol)
@ffi_enums.__map_symbol(symbol)
end
+ # @param [DataConverter, Type, Struct, Symbol] t type to find
+ # @return [Type]
+ # Find a type definition.
def find_type(t)
if t.kind_of?(Type)
t
@@ -380,4 +480,4 @@ module FFI
end || FFI.find_type(t)
end
end
-end \ No newline at end of file
+end
diff --git a/lib/ffi/platform.rb b/lib/ffi/platform.rb
index e0ab701..abb1d6b 100644
--- a/lib/ffi/platform.rb
+++ b/lib/ffi/platform.rb
@@ -23,6 +23,8 @@ require 'rbconfig'
module FFI
class PlatformError < LoadError; end
+ # This module defines different constants and class methods to play with
+ # various platforms.
module Platform
OS = case RbConfig::CONFIG['host_os'].downcase
when /linux/
@@ -53,6 +55,9 @@ module FFI
end
private
+ # @param [String) os
+ # @return [Boolean]
+ # Test if current OS is +os+.
def self.is_os(os)
OS == os
end
@@ -91,18 +96,26 @@ module FFI
"#{LIBPREFIX}c.#{LIBSUFFIX}"
end
+ # Test if current OS is a *BSD (include MAC)
+ # @return [Boolean]
def self.bsd?
IS_BSD
end
+ # Test if current OS is Windows
+ # @return [Boolean]
def self.windows?
IS_WINDOWS
end
+ # Test if current OS is Mac OS
+ # @return [Boolean]
def self.mac?
IS_MAC
end
+ # Test if current OS is a unix OS
+ # @return [Boolean]
def self.unix?
!IS_WINDOWS
end
diff --git a/lib/ffi/types.rb b/lib/ffi/types.rb
index e721ba6..42ca6ae 100644
--- a/lib/ffi/types.rb
+++ b/lib/ffi/types.rb
@@ -140,7 +140,7 @@ module FFI
# @param [Pointer] val
# @param [] ctx
- # @return [Array<String, Pointer>]
+ # @return [Array(String, Pointer)]
# Returns a [ String, Pointer ] tuple so the C memory for the string can be freed
def self.from_native(val, ctx)
[ val.null? ? nil : val.get_string(0), val ]