Import JRuby implementation (#147)
Fix GH-104 lib/fiddle/jruby.rb is based on https://github.com/jruby/jruby/blob/master/lib/ruby/stdlib/fiddle/jruby.rb . Here are changes for it: * Move `Fiddle::TYPE_*` to `Fiddle::Types::*` * Add `Fiddle::Types::VARIADIC` * Add `Fiddle::Types::CONST_STRING` * Add `Fiddle::Types::BOOL` * Add `Fiddle::Types::INT8_T` * Add `Fiddle::Types::UINT8_T` * Add `Fiddle::Types::INT16_T` * Add `Fiddle::Types::UINT16_T` * Add `Fiddle::Types::INT32_T` * Add `Fiddle::Types::UINT32_T` * Add `Fiddle::Types::INT64_T` * Add `Fiddle::Types::UINT64_T` * Add more `Fiddle::ALIGN_*` for the above new `Fiddle::Types::*` * Add more `Fiddle::SIZEOF_*` for the above new `Fiddle::Types::*` * Add support for specifying type as not only `Fiddle::Types::*` but also `Symbol` like `:int` * Add support for variable size arguments in `Fiddle::Function` * Add `Fiddle::Closure#free` * Add `Fiddle::Closure#freed?` * Add `Fiddle::Error` as base the error class * Add `Fiddle::Pointer#call_free` and stop using `FFI::AutoPointer` in `Fiddle::Pointer` * Add support for `Fiddle::Pointer.malloc {}` `Fiddle::Pointer` * Add support for `Fiddle::Pointer#free=` * Add `Fiddle::Pointer#freed?` * Use binary string not C string for `Fiddle::Pointer#[]` * Add `Fiddle::Handle.sym_defined?` * Add `Fiddle::Handle#sym_defined?` * Add `Fiddle::Handle::DEFAULT` * Add `Fiddle::ClearedReferenceError` * Add no-op `Fiddle::Pinned` Some features are still "not implemented". So there are some "omit"s for JRuby in tests.
This commit is contained in:
parent
a392ee1437
commit
a47f153d9d
Notes:
git
2024-10-10 01:54:48 +00:00
@ -1,6 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
require 'mkmf'
|
||||
|
||||
if RUBY_ENGINE == "jruby"
|
||||
File.write('Makefile', dummy_makefile("").join)
|
||||
return
|
||||
end
|
||||
|
||||
# :stopdoc:
|
||||
|
||||
def gcc?
|
||||
|
@ -40,7 +40,9 @@ Gem::Specification.new do |spec|
|
||||
"lib/fiddle/cparser.rb",
|
||||
"lib/fiddle/function.rb",
|
||||
"lib/fiddle/import.rb",
|
||||
"lib/fiddle/jruby.rb",
|
||||
"lib/fiddle/pack.rb",
|
||||
"lib/fiddle/ruby.rb",
|
||||
"lib/fiddle/struct.rb",
|
||||
"lib/fiddle/types.rb",
|
||||
"lib/fiddle/value.rb",
|
||||
|
@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'fiddle.so'
|
||||
require "fiddle/#{RUBY_ENGINE}"
|
||||
require 'fiddle/closure'
|
||||
require 'fiddle/function'
|
||||
require 'fiddle/version'
|
||||
@ -10,36 +10,63 @@ module Fiddle
|
||||
# Returns the last win32 +Error+ of the current executing +Thread+ or nil
|
||||
# if none
|
||||
def self.win32_last_error
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
|
||||
if RUBY_ENGINE == 'jruby'
|
||||
errno = FFI.errno
|
||||
errno == 0 ? nil : errno
|
||||
else
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the last win32 +Error+ of the current executing +Thread+ to +error+
|
||||
def self.win32_last_error= error
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
|
||||
if RUBY_ENGINE == 'jruby'
|
||||
FFI.errno = error || 0
|
||||
else
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the last win32 socket +Error+ of the current executing
|
||||
# +Thread+ or nil if none
|
||||
def self.win32_last_socket_error
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
|
||||
if RUBY_ENGINE == 'jruby'
|
||||
errno = FFI.errno
|
||||
errno == 0 ? nil : errno
|
||||
else
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the last win32 socket +Error+ of the current executing
|
||||
# +Thread+ to +error+
|
||||
def self.win32_last_socket_error= error
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
|
||||
if RUBY_ENGINE == 'jruby'
|
||||
FFI.errno = error || 0
|
||||
else
|
||||
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the last +Error+ of the current executing +Thread+ or nil if none
|
||||
def self.last_error
|
||||
Thread.current[:__FIDDLE_LAST_ERROR__]
|
||||
if RUBY_ENGINE == 'jruby'
|
||||
errno = FFI.errno
|
||||
errno == 0 ? nil : errno
|
||||
else
|
||||
Thread.current[:__FIDDLE_LAST_ERROR__]
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the last +Error+ of the current executing +Thread+ to +error+
|
||||
def self.last_error= error
|
||||
Thread.current[:__DL2_LAST_ERROR__] = error
|
||||
Thread.current[:__FIDDLE_LAST_ERROR__] = error
|
||||
if RUBY_ENGINE == 'jruby'
|
||||
FFI.errno = error || 0
|
||||
else
|
||||
Thread.current[:__DL2_LAST_ERROR__] = error
|
||||
Thread.current[:__FIDDLE_LAST_ERROR__] = error
|
||||
end
|
||||
end
|
||||
|
||||
# call-seq: dlopen(library) => Fiddle::Handle
|
||||
|
600
ext/fiddle/lib/fiddle/jruby.rb
Normal file
600
ext/fiddle/lib/fiddle/jruby.rb
Normal file
@ -0,0 +1,600 @@
|
||||
# This is part of JRuby's FFI-based fiddle implementation.
|
||||
|
||||
require 'ffi'
|
||||
|
||||
module Fiddle
|
||||
def self.malloc(size)
|
||||
Fiddle::Pointer.malloc(size)
|
||||
end
|
||||
|
||||
def self.free(ptr)
|
||||
Fiddle::Pointer::LibC::FREE.call(ptr)
|
||||
nil
|
||||
end
|
||||
|
||||
def self.dlwrap(val)
|
||||
Pointer.to_ptr(val)
|
||||
end
|
||||
|
||||
module Types
|
||||
VOID = 0
|
||||
VOIDP = 1
|
||||
CHAR = 2
|
||||
UCHAR = -CHAR
|
||||
SHORT = 3
|
||||
USHORT = -SHORT
|
||||
INT = 4
|
||||
UINT = -INT
|
||||
LONG = 5
|
||||
ULONG = -LONG
|
||||
LONG_LONG = 6
|
||||
ULONG_LONG = -LONG_LONG
|
||||
FLOAT = 7
|
||||
DOUBLE = 8
|
||||
VARIADIC = 9
|
||||
CONST_STRING = 10
|
||||
BOOL = 11
|
||||
INT8_T = CHAR
|
||||
UINT8_T = UCHAR
|
||||
if FFI::Type::Builtin::SHORT.size == 2
|
||||
INT16_T = SHORT
|
||||
UINT16_T = USHORT
|
||||
elsif FFI::Type::Builtin::INT.size == 2
|
||||
INT16_T = INT
|
||||
UINT16_T = UINT
|
||||
end
|
||||
if FFI::Type::Builtin::SHORT.size == 4
|
||||
INT32_T = SHORT
|
||||
UINT32_T = USHORT
|
||||
elsif FFI::Type::Builtin::INT.size == 4
|
||||
INT32_T = INT
|
||||
UINT32_T = UINT
|
||||
elsif FFI::Type::Builtin::LONG.size == 4
|
||||
INT32_T = LONG
|
||||
UINT32_T = ULONG
|
||||
end
|
||||
if FFI::Type::Builtin::INT.size == 8
|
||||
INT64_T = INT
|
||||
UINT64_T = UINT
|
||||
elsif FFI::Type::Builtin::LONG.size == 8
|
||||
INT64_T = LONG
|
||||
UINT64_T = ULONG
|
||||
else
|
||||
INT64_T = LONG_LONG
|
||||
UINT64_T = ULONG_LONG
|
||||
end
|
||||
|
||||
# FIXME: platform specific values
|
||||
SSIZE_T = INT64_T
|
||||
SIZE_T = -SSIZE_T
|
||||
PTRDIFF_T = SSIZE_T
|
||||
INTPTR_T = INT64_T
|
||||
UINTPTR_T = -INTPTR_T
|
||||
end
|
||||
|
||||
WINDOWS = FFI::Platform.windows?
|
||||
|
||||
module JRuby
|
||||
FFITypes = {
|
||||
'c' => FFI::Type::INT8,
|
||||
'h' => FFI::Type::INT16,
|
||||
'i' => FFI::Type::INT32,
|
||||
'l' => FFI::Type::LONG,
|
||||
'f' => FFI::Type::FLOAT32,
|
||||
'd' => FFI::Type::FLOAT64,
|
||||
'p' => FFI::Type::POINTER,
|
||||
's' => FFI::Type::STRING,
|
||||
|
||||
Types::VOID => FFI::Type::Builtin::VOID,
|
||||
Types::VOIDP => FFI::Type::Builtin::POINTER,
|
||||
Types::CHAR => FFI::Type::Builtin::CHAR,
|
||||
Types::UCHAR => FFI::Type::Builtin::UCHAR,
|
||||
Types::SHORT => FFI::Type::Builtin::SHORT,
|
||||
Types::USHORT => FFI::Type::Builtin::USHORT,
|
||||
Types::INT => FFI::Type::Builtin::INT,
|
||||
Types::UINT => FFI::Type::Builtin::UINT,
|
||||
Types::LONG => FFI::Type::Builtin::LONG,
|
||||
Types::ULONG => FFI::Type::Builtin::ULONG,
|
||||
Types::LONG_LONG => FFI::Type::Builtin::LONG_LONG,
|
||||
Types::ULONG_LONG => FFI::Type::Builtin::ULONG_LONG,
|
||||
Types::FLOAT => FFI::Type::Builtin::FLOAT,
|
||||
Types::DOUBLE => FFI::Type::Builtin::DOUBLE,
|
||||
Types::BOOL => FFI::Type::Builtin::BOOL,
|
||||
Types::CONST_STRING => FFI::Type::Builtin::POINTER,
|
||||
Types::VARIADIC => FFI::Type::Builtin::VARARGS,
|
||||
}
|
||||
|
||||
def self.__ffi_type__(dl_type)
|
||||
if dl_type.is_a?(Symbol)
|
||||
dl_type = Types.const_get(dl_type.to_s.upcase)
|
||||
end
|
||||
if !dl_type.is_a?(Integer) && dl_type.respond_to?(:to_int)
|
||||
dl_type = dl_type.to_int
|
||||
end
|
||||
ffi_type = FFITypes[dl_type]
|
||||
ffi_type = FFITypes[-dl_type] if ffi_type.nil? && dl_type.is_a?(Integer) && dl_type < 0
|
||||
raise TypeError.new("cannot convert #{dl_type} to ffi") unless ffi_type
|
||||
ffi_type
|
||||
end
|
||||
end
|
||||
|
||||
class Function
|
||||
DEFAULT = "default"
|
||||
STDCALL = "stdcall"
|
||||
|
||||
def initialize(ptr, args, return_type, abi = DEFAULT, kwargs = nil)
|
||||
if kwargs.nil?
|
||||
if abi.kind_of? Hash
|
||||
kwargs = abi
|
||||
abi = DEFAULT
|
||||
end
|
||||
end
|
||||
@name = kwargs[:name] if kwargs.kind_of? Hash
|
||||
@ptr, @args, @return_type, @abi = ptr, args, return_type, abi
|
||||
raise TypeError.new "invalid argument types" unless args.is_a?(Array)
|
||||
|
||||
ffi_return_type = Fiddle::JRuby::__ffi_type__(@return_type)
|
||||
ffi_args = @args.map { |t| Fiddle::JRuby.__ffi_type__(t) }
|
||||
pointer = FFI::Pointer.new(ptr.to_i)
|
||||
options = {convention: @abi}
|
||||
if ffi_args.last == FFI::Type::Builtin::VARARGS
|
||||
@function = FFI::VariadicInvoker.new(
|
||||
pointer,
|
||||
ffi_args,
|
||||
ffi_return_type,
|
||||
options
|
||||
)
|
||||
else
|
||||
@function = FFI::Function.new(ffi_return_type, ffi_args, pointer, options)
|
||||
end
|
||||
end
|
||||
|
||||
def call(*args, &block);
|
||||
if @function.is_a?(FFI::VariadicInvoker)
|
||||
n_fixed_args = @args.size - 1
|
||||
n_fixed_args.step(args.size - 1, 2) do |i|
|
||||
if args[i] == :const_string || args[i] == Types::CONST_STRING
|
||||
args[i + 1] = String.try_convert(args[i + 1]) || args[i + 1]
|
||||
end
|
||||
args[i] = Fiddle::JRuby.__ffi_type__(args[i])
|
||||
end
|
||||
end
|
||||
result = @function.call(*args, &block)
|
||||
result = Pointer.new(result) if result.is_a?(FFI::Pointer)
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
class Closure
|
||||
def initialize(ret, args, abi = Function::DEFAULT)
|
||||
raise TypeError.new "invalid argument types" unless args.is_a?(Array)
|
||||
|
||||
@ctype, @args = ret, args
|
||||
ffi_args = @args.map { |t| Fiddle::JRuby.__ffi_type__(t) }
|
||||
if ffi_args.size == 1 && ffi_args[0] == FFI::Type::Builtin::VOID
|
||||
ffi_args = []
|
||||
end
|
||||
@function = FFI::Function.new(
|
||||
Fiddle::JRuby.__ffi_type__(@ctype),
|
||||
ffi_args,
|
||||
self,
|
||||
:convention => abi
|
||||
)
|
||||
@freed = false
|
||||
end
|
||||
|
||||
def to_i
|
||||
@function.to_i
|
||||
end
|
||||
|
||||
def free
|
||||
return if @freed
|
||||
@function.free
|
||||
@freed = true
|
||||
end
|
||||
|
||||
def freed?
|
||||
@freed
|
||||
end
|
||||
end
|
||||
|
||||
class Error < StandardError; end
|
||||
class DLError < Error; end
|
||||
class ClearedReferenceError < Error; end
|
||||
|
||||
class Pointer
|
||||
attr_reader :ffi_ptr
|
||||
extend FFI::DataConverter
|
||||
native_type FFI::Type::Builtin::POINTER
|
||||
|
||||
def self.to_native(value, ctx)
|
||||
if value.is_a?(Pointer)
|
||||
value.ffi_ptr
|
||||
|
||||
elsif value.is_a?(Integer)
|
||||
FFI::Pointer.new(value)
|
||||
|
||||
elsif value.is_a?(String)
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_native(value, ctx)
|
||||
self.new(value)
|
||||
end
|
||||
|
||||
def self.to_ptr(value)
|
||||
if value.is_a?(String)
|
||||
cptr = Pointer.malloc(value.bytesize)
|
||||
cptr.ffi_ptr.put_string(0, value)
|
||||
cptr
|
||||
|
||||
elsif value.is_a?(Array)
|
||||
raise NotImplementedError, "array ptr"
|
||||
|
||||
elsif value.respond_to?(:to_ptr)
|
||||
ptr = value.to_ptr
|
||||
case ptr
|
||||
when Pointer
|
||||
ptr
|
||||
when FFI::Pointer
|
||||
Pointer.new(ptr)
|
||||
else
|
||||
raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{ptr.class}")
|
||||
end
|
||||
|
||||
else
|
||||
Pointer.new(value)
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
alias [] to_ptr
|
||||
end
|
||||
|
||||
def []=(*args, value)
|
||||
if args.size == 2
|
||||
if value.is_a?(Integer)
|
||||
value = self.class.new(value)
|
||||
end
|
||||
if value.is_a?(Fiddle::Pointer)
|
||||
value = value.to_str(args[1])
|
||||
end
|
||||
|
||||
@ffi_ptr.put_bytes(args[0], value, 0, args[1])
|
||||
elsif args.size == 1
|
||||
if value.is_a?(Fiddle::Pointer)
|
||||
value = value.to_str(args[0] + 1)
|
||||
else
|
||||
value = value.chr
|
||||
end
|
||||
|
||||
@ffi_ptr.put_bytes(args[0], value, 0, 1)
|
||||
end
|
||||
rescue FFI::NullPointerError
|
||||
raise DLError.new("NULL pointer access")
|
||||
end
|
||||
|
||||
def initialize(addr, size = nil, free = nil)
|
||||
ptr = if addr.is_a?(FFI::Pointer)
|
||||
addr
|
||||
|
||||
elsif addr.is_a?(Integer)
|
||||
FFI::Pointer.new(addr)
|
||||
|
||||
elsif addr.respond_to?(:to_ptr)
|
||||
fiddle_ptr = addr.to_ptr
|
||||
if fiddle_ptr.is_a?(Pointer)
|
||||
fiddle_ptr.ffi_ptr
|
||||
elsif fiddle_ptr.is_a?(FFI::AutoPointer)
|
||||
addr.ffi_ptr
|
||||
elsif fiddle_ptr.is_a?(FFI::Pointer)
|
||||
fiddle_ptr
|
||||
else
|
||||
raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{fiddle_ptr.class}")
|
||||
end
|
||||
elsif addr.is_a?(IO)
|
||||
raise NotImplementedError, "IO ptr isn't supported"
|
||||
end
|
||||
|
||||
@size = size ? size : ptr.size
|
||||
@free = free
|
||||
@ffi_ptr = ptr
|
||||
@freed = false
|
||||
end
|
||||
|
||||
module LibC
|
||||
extend FFI::Library
|
||||
ffi_lib FFI::Library::LIBC
|
||||
MALLOC = attach_function :malloc, [ :size_t ], :pointer
|
||||
REALLOC = attach_function :realloc, [ :pointer, :size_t ], :pointer
|
||||
FREE = attach_function :free, [ :pointer ], :void
|
||||
end
|
||||
|
||||
def self.malloc(size, free = nil)
|
||||
if block_given? and free.nil?
|
||||
message = "a free function must be supplied to #{self}.malloc " +
|
||||
"when it is called with a block"
|
||||
raise ArgumentError, message
|
||||
end
|
||||
|
||||
pointer = new(LibC.malloc(size), size, free)
|
||||
if block_given?
|
||||
begin
|
||||
yield(pointer)
|
||||
ensure
|
||||
pointer.call_free
|
||||
end
|
||||
else
|
||||
pointer
|
||||
end
|
||||
end
|
||||
|
||||
def null?
|
||||
@ffi_ptr.null?
|
||||
end
|
||||
|
||||
def to_ptr
|
||||
@ffi_ptr
|
||||
end
|
||||
|
||||
def size
|
||||
defined?(@layout) ? @layout.size : @size
|
||||
end
|
||||
|
||||
def free
|
||||
@free
|
||||
end
|
||||
|
||||
def free=(free)
|
||||
@free = free
|
||||
end
|
||||
|
||||
def call_free
|
||||
return if @free.nil?
|
||||
return if @freed
|
||||
if @free == RUBY_FREE
|
||||
LibC::FREE.call(@ffi_ptr)
|
||||
else
|
||||
@free.call(@ffi_ptr)
|
||||
end
|
||||
@freed = true
|
||||
end
|
||||
|
||||
def freed?
|
||||
@freed
|
||||
end
|
||||
|
||||
def size=(size)
|
||||
@size = size
|
||||
end
|
||||
|
||||
def [](index, length = nil)
|
||||
if length
|
||||
ffi_ptr.get_bytes(index, length)
|
||||
else
|
||||
ffi_ptr.get_char(index)
|
||||
end
|
||||
rescue FFI::NullPointerError
|
||||
raise DLError.new("NULL pointer dereference")
|
||||
end
|
||||
|
||||
def to_i
|
||||
ffi_ptr.to_i
|
||||
end
|
||||
alias to_int to_i
|
||||
|
||||
# without \0
|
||||
def to_s(len = nil)
|
||||
if len
|
||||
ffi_ptr.get_string(0, len)
|
||||
else
|
||||
ffi_ptr.get_string(0)
|
||||
end
|
||||
rescue FFI::NullPointerError
|
||||
raise DLError.new("NULL pointer access")
|
||||
end
|
||||
|
||||
def to_str(len = nil)
|
||||
if len
|
||||
ffi_ptr.read_string(len)
|
||||
else
|
||||
ffi_ptr.read_string(@size)
|
||||
end
|
||||
rescue FFI::NullPointerError
|
||||
raise DLError.new("NULL pointer access")
|
||||
end
|
||||
|
||||
def to_value
|
||||
raise NotImplementedError, "to_value isn't supported"
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>"
|
||||
end
|
||||
|
||||
def +(delta)
|
||||
self.class.new(to_i + delta, @size - delta)
|
||||
end
|
||||
|
||||
def -(delta)
|
||||
self.class.new(to_i - delta, @size + delta)
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
return unless other.is_a?(Pointer)
|
||||
diff = self.to_i - other.to_i
|
||||
return 0 if diff == 0
|
||||
diff > 0 ? 1 : -1
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
return unless other.is_a?(Pointer)
|
||||
self.to_i == other.to_i
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
eql?(other)
|
||||
end
|
||||
|
||||
def ptr
|
||||
Pointer.new(ffi_ptr.get_pointer(0))
|
||||
end
|
||||
|
||||
def +@
|
||||
ptr
|
||||
end
|
||||
|
||||
def -@
|
||||
ref
|
||||
end
|
||||
|
||||
def ref
|
||||
cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE)
|
||||
cptr.ffi_ptr.put_pointer(0, ffi_ptr)
|
||||
cptr
|
||||
end
|
||||
end
|
||||
|
||||
class Handle
|
||||
RTLD_GLOBAL = FFI::DynamicLibrary::RTLD_GLOBAL
|
||||
RTLD_LAZY = FFI::DynamicLibrary::RTLD_LAZY
|
||||
RTLD_NOW = FFI::DynamicLibrary::RTLD_NOW
|
||||
|
||||
def initialize(libname = nil, flags = RTLD_LAZY | RTLD_GLOBAL)
|
||||
@lib = FFI::DynamicLibrary.open(libname, flags) rescue LoadError
|
||||
raise DLError.new("Could not open #{libname}") unless @lib
|
||||
|
||||
@open = true
|
||||
|
||||
begin
|
||||
yield(self)
|
||||
ensure
|
||||
self.close
|
||||
end if block_given?
|
||||
end
|
||||
|
||||
def close
|
||||
raise DLError.new("closed handle") unless @open
|
||||
@open = false
|
||||
0
|
||||
end
|
||||
|
||||
def self.sym(func)
|
||||
DEFAULT.sym(func)
|
||||
end
|
||||
|
||||
def sym(func)
|
||||
raise TypeError.new("invalid function name") unless func.is_a?(String)
|
||||
raise DLError.new("closed handle") unless @open
|
||||
address = @lib.find_function(func)
|
||||
raise DLError.new("unknown symbol #{func}") if address.nil? || address.null?
|
||||
address.to_i
|
||||
end
|
||||
|
||||
def self.sym_defined?(func)
|
||||
DEFAULT.sym_defined?(func)
|
||||
end
|
||||
|
||||
def sym_defined?(func)
|
||||
raise TypeError.new("invalid function name") unless func.is_a?(String)
|
||||
raise DLError.new("closed handle") unless @open
|
||||
address = @lib.find_function(func)
|
||||
!address.nil? && !address.null?
|
||||
end
|
||||
|
||||
def self.[](func)
|
||||
self.sym(func)
|
||||
end
|
||||
|
||||
def [](func)
|
||||
sym(func)
|
||||
end
|
||||
|
||||
def enable_close
|
||||
@enable_close = true
|
||||
end
|
||||
|
||||
def close_enabled?
|
||||
@enable_close
|
||||
end
|
||||
|
||||
def disable_close
|
||||
@enable_close = false
|
||||
end
|
||||
|
||||
DEFAULT = new
|
||||
end
|
||||
|
||||
class Pinned
|
||||
def initialize(object)
|
||||
@object = object
|
||||
end
|
||||
|
||||
def ref
|
||||
if @object.nil?
|
||||
raise ClearedReferenceError, "`ref` called on a cleared object"
|
||||
end
|
||||
@object
|
||||
end
|
||||
|
||||
def clear
|
||||
@object = nil
|
||||
end
|
||||
|
||||
def cleared?
|
||||
@object.nil?
|
||||
end
|
||||
end
|
||||
|
||||
RUBY_FREE = Fiddle::Pointer::LibC::FREE.address
|
||||
NULL = Fiddle::Pointer.new(0)
|
||||
|
||||
ALIGN_VOIDP = Fiddle::JRuby::FFITypes[Types::VOIDP].alignment
|
||||
ALIGN_CHAR = Fiddle::JRuby::FFITypes[Types::CHAR].alignment
|
||||
ALIGN_SHORT = Fiddle::JRuby::FFITypes[Types::SHORT].alignment
|
||||
ALIGN_INT = Fiddle::JRuby::FFITypes[Types::INT].alignment
|
||||
ALIGN_LONG = Fiddle::JRuby::FFITypes[Types::LONG].alignment
|
||||
ALIGN_LONG_LONG = Fiddle::JRuby::FFITypes[Types::LONG_LONG].alignment
|
||||
ALIGN_INT8_T = Fiddle::JRuby::FFITypes[Types::INT8_T].alignment
|
||||
ALIGN_INT16_T = Fiddle::JRuby::FFITypes[Types::INT16_T].alignment
|
||||
ALIGN_INT32_T = Fiddle::JRuby::FFITypes[Types::INT32_T].alignment
|
||||
ALIGN_INT64_T = Fiddle::JRuby::FFITypes[Types::INT64_T].alignment
|
||||
ALIGN_FLOAT = Fiddle::JRuby::FFITypes[Types::FLOAT].alignment
|
||||
ALIGN_DOUBLE = Fiddle::JRuby::FFITypes[Types::DOUBLE].alignment
|
||||
ALIGN_BOOL = Fiddle::JRuby::FFITypes[Types::BOOL].alignment
|
||||
ALIGN_SIZE_T = Fiddle::JRuby::FFITypes[Types::SIZE_T].alignment
|
||||
ALIGN_SSIZE_T = ALIGN_SIZE_T
|
||||
ALIGN_PTRDIFF_T = Fiddle::JRuby::FFITypes[Types::PTRDIFF_T].alignment
|
||||
ALIGN_INTPTR_T = Fiddle::JRuby::FFITypes[Types::INTPTR_T].alignment
|
||||
ALIGN_UINTPTR_T = Fiddle::JRuby::FFITypes[Types::UINTPTR_T].alignment
|
||||
|
||||
SIZEOF_VOIDP = Fiddle::JRuby::FFITypes[Types::VOIDP].size
|
||||
SIZEOF_CHAR = Fiddle::JRuby::FFITypes[Types::CHAR].size
|
||||
SIZEOF_UCHAR = Fiddle::JRuby::FFITypes[Types::UCHAR].size
|
||||
SIZEOF_SHORT = Fiddle::JRuby::FFITypes[Types::SHORT].size
|
||||
SIZEOF_USHORT = Fiddle::JRuby::FFITypes[Types::USHORT].size
|
||||
SIZEOF_INT = Fiddle::JRuby::FFITypes[Types::INT].size
|
||||
SIZEOF_UINT = Fiddle::JRuby::FFITypes[Types::UINT].size
|
||||
SIZEOF_LONG = Fiddle::JRuby::FFITypes[Types::LONG].size
|
||||
SIZEOF_ULONG = Fiddle::JRuby::FFITypes[Types::ULONG].size
|
||||
SIZEOF_LONG_LONG = Fiddle::JRuby::FFITypes[Types::LONG_LONG].size
|
||||
SIZEOF_ULONG_LONG = Fiddle::JRuby::FFITypes[Types::ULONG_LONG].size
|
||||
SIZEOF_INT8_T = Fiddle::JRuby::FFITypes[Types::INT8_T].size
|
||||
SIZEOF_UINT8_T = Fiddle::JRuby::FFITypes[Types::UINT8_T].size
|
||||
SIZEOF_INT16_T = Fiddle::JRuby::FFITypes[Types::INT16_T].size
|
||||
SIZEOF_UINT16_T = Fiddle::JRuby::FFITypes[Types::UINT16_T].size
|
||||
SIZEOF_INT32_T = Fiddle::JRuby::FFITypes[Types::INT32_T].size
|
||||
SIZEOF_UINT32_T = Fiddle::JRuby::FFITypes[Types::UINT32_T].size
|
||||
SIZEOF_INT64_T = Fiddle::JRuby::FFITypes[Types::INT64_T].size
|
||||
SIZEOF_UINT64_T = Fiddle::JRuby::FFITypes[Types::UINT64_T].size
|
||||
SIZEOF_FLOAT = Fiddle::JRuby::FFITypes[Types::FLOAT].size
|
||||
SIZEOF_DOUBLE = Fiddle::JRuby::FFITypes[Types::DOUBLE].size
|
||||
SIZEOF_BOOL = Fiddle::JRuby::FFITypes[Types::BOOL].size
|
||||
SIZEOF_SIZE_T = Fiddle::JRuby::FFITypes[Types::SIZE_T].size
|
||||
SIZEOF_SSIZE_T = SIZEOF_SIZE_T
|
||||
SIZEOF_PTRDIFF_T = Fiddle::JRuby::FFITypes[Types::PTRDIFF_T].size
|
||||
SIZEOF_INTPTR_T = Fiddle::JRuby::FFITypes[Types::INTPTR_T].size
|
||||
SIZEOF_UINTPTR_T = Fiddle::JRuby::FFITypes[Types::UINTPTR_T].size
|
||||
SIZEOF_CONST_STRING = Fiddle::JRuby::FFITypes[Types::VOIDP].size
|
||||
end
|
@ -41,6 +41,12 @@ module Fiddle
|
||||
when SIZEOF_LONG
|
||||
PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_ULONG]
|
||||
end
|
||||
if RUBY_ENGINE == "jruby" and WINDOWS and [0].pack("l!").size == 8
|
||||
# JRuby's 'l!' pack string doesn't use 32-bit on Windows.
|
||||
# See https://github.com/jruby/jruby/issues/8357 for details
|
||||
PACK_MAP[TYPE_LONG] = PACK_MAP[TYPE_INT]
|
||||
PACK_MAP[TYPE_ULONG] = PACK_MAP[TYPE_UINT]
|
||||
end
|
||||
|
||||
SIZE_MAP = {
|
||||
TYPE_VOIDP => SIZEOF_VOIDP,
|
||||
|
1
ext/fiddle/lib/fiddle/ruby.rb
Normal file
1
ext/fiddle/lib/fiddle/ruby.rb
Normal file
@ -0,0 +1 @@
|
||||
require "fiddle.so"
|
@ -290,15 +290,28 @@ module Fiddle
|
||||
# Allocates a C struct with the +types+ provided.
|
||||
#
|
||||
# See Fiddle::Pointer.malloc for memory management issues.
|
||||
def CStructEntity.malloc(types, func = nil, size = size(types), &block)
|
||||
def CStructEntity.malloc(types, func = nil, size = size(types))
|
||||
if block_given? and func.nil?
|
||||
message = "a free function must be supplied to #{self}.malloc " +
|
||||
"when it is called with a block"
|
||||
raise ArgumentError, message
|
||||
end
|
||||
|
||||
pointer = Pointer.malloc(size)
|
||||
begin
|
||||
struct = new(pointer, types, func)
|
||||
rescue
|
||||
pointer.free = func
|
||||
pointer.call_free
|
||||
raise
|
||||
end
|
||||
if block_given?
|
||||
super(size, func) do |struct|
|
||||
struct.set_ctypes types
|
||||
yield struct
|
||||
begin
|
||||
yield(struct)
|
||||
ensure
|
||||
struct.call_free
|
||||
end
|
||||
else
|
||||
struct = super(size, func)
|
||||
struct.set_ctypes types
|
||||
struct
|
||||
end
|
||||
end
|
||||
@ -505,6 +518,14 @@ module Fiddle
|
||||
def to_s() # :nodoc:
|
||||
super(@size)
|
||||
end
|
||||
|
||||
def +(delta)
|
||||
Pointer.new(to_i + delta, @size - delta)
|
||||
end
|
||||
|
||||
def -(delta)
|
||||
Pointer.new(to_i - delta, @size + delta)
|
||||
end
|
||||
end
|
||||
|
||||
# A pointer to a C union
|
||||
|
@ -4,11 +4,19 @@ require 'rbconfig/sizeof'
|
||||
require 'test/unit'
|
||||
require 'fiddle'
|
||||
|
||||
puts("Fiddle::VERSION: #{Fiddle::VERSION}")
|
||||
|
||||
# FIXME: this is stolen from DL and needs to be refactored.
|
||||
|
||||
libc_so = libm_so = nil
|
||||
|
||||
case RUBY_PLATFORM
|
||||
if RUBY_ENGINE == "jruby"
|
||||
# "jruby ... [x86_64-linux]" -> "x86_64-linux"
|
||||
ruby_platform = RUBY_DESCRIPTION.split(" ").last[1..-2]
|
||||
else
|
||||
ruby_platform = RUBY_PLATFORM
|
||||
end
|
||||
case ruby_platform
|
||||
when /cygwin/
|
||||
libc_so = "cygwin1.dll"
|
||||
libm_so = "cygwin1.dll"
|
||||
@ -147,6 +155,7 @@ unless rigid_path
|
||||
end
|
||||
|
||||
if !libc_so || !libm_so
|
||||
require "envutil"
|
||||
ruby = EnvUtil.rubybin
|
||||
# When the ruby binary is 32-bit and the host is 64-bit,
|
||||
# `ldd ruby` outputs "not a dynamic executable" message.
|
||||
|
@ -8,6 +8,8 @@ module Fiddle
|
||||
class TestClosure < Fiddle::TestCase
|
||||
def teardown
|
||||
super
|
||||
# We can't use ObjectSpace with JRuby.
|
||||
return if RUBY_ENGINE == "jruby"
|
||||
# Ensure freeing all closures.
|
||||
# See https://github.com/ruby/fiddle/issues/102#issuecomment-1241763091 .
|
||||
not_freed_closures = []
|
||||
@ -31,19 +33,6 @@ module Fiddle
|
||||
end
|
||||
end
|
||||
|
||||
def test_type_symbol
|
||||
Closure.create(:int, [:void]) do |closure|
|
||||
assert_equal([
|
||||
TYPE_INT,
|
||||
[TYPE_VOID],
|
||||
],
|
||||
[
|
||||
closure.instance_variable_get(:@ctype),
|
||||
closure.instance_variable_get(:@args),
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
def test_call
|
||||
closure_class = Class.new(Closure) do
|
||||
def call
|
||||
@ -69,6 +58,11 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_const_string
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Closure with :const_string works but " +
|
||||
"Function with :const_string doesn't work with JRuby")
|
||||
end
|
||||
|
||||
closure_class = Class.new(Closure) do
|
||||
def call(string)
|
||||
@return_string = "Hello! #{string}"
|
||||
@ -94,7 +88,12 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_free
|
||||
Closure.create(:int, [:void]) do |closure|
|
||||
closure_class = Class.new(Closure) do
|
||||
def call
|
||||
10
|
||||
end
|
||||
end
|
||||
closure_class.create(:int, [:void]) do |closure|
|
||||
assert(!closure.freed?)
|
||||
closure.free
|
||||
assert(closure.freed?)
|
||||
@ -115,6 +114,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_memsize_ruby_dev_42480
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("We can't use ObjectSpace with JRuby")
|
||||
end
|
||||
|
||||
require 'objspace'
|
||||
n = 10000
|
||||
n.times do
|
||||
|
@ -6,6 +6,10 @@ end
|
||||
|
||||
class TestFiddle < Fiddle::TestCase
|
||||
def test_nil_true_etc
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Q* aren't supported with JRuby")
|
||||
end
|
||||
|
||||
assert_equal Fiddle::Qtrue, Fiddle.dlwrap(true)
|
||||
assert_equal Fiddle::Qfalse, Fiddle.dlwrap(false)
|
||||
assert_equal Fiddle::Qnil, Fiddle.dlwrap(nil)
|
||||
|
@ -26,6 +26,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_string
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Function that returns string doesn't work with JRuby")
|
||||
end
|
||||
|
||||
under_gc_stress do
|
||||
f = Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
|
||||
buff = +"000"
|
||||
@ -82,6 +86,8 @@ module Fiddle
|
||||
assert_equal("1349", buff, bug4929)
|
||||
end
|
||||
ensure
|
||||
# We can't use ObjectSpace with JRuby.
|
||||
return if RUBY_ENGINE == "jruby"
|
||||
# Ensure freeing all closures.
|
||||
# See https://github.com/ruby/fiddle/issues/102#issuecomment-1241763091 .
|
||||
not_freed_closures = []
|
||||
@ -113,37 +119,36 @@ module Fiddle
|
||||
:variadic,
|
||||
],
|
||||
:int)
|
||||
output_buffer = " " * 1024
|
||||
output = Pointer[output_buffer]
|
||||
Pointer.malloc(1024, Fiddle::RUBY_FREE) do |output|
|
||||
written = snprintf.call(output,
|
||||
output.size,
|
||||
"int: %d, string: %.*s, const string: %s\n",
|
||||
:int, -29,
|
||||
:int, 4,
|
||||
:voidp, "Hello",
|
||||
:const_string, "World")
|
||||
assert_equal("int: -29, string: Hell, const string: World\n",
|
||||
output[0, written])
|
||||
|
||||
written = snprintf.call(output,
|
||||
output.size,
|
||||
"int: %d, string: %.*s, const string: %s\n",
|
||||
:int, -29,
|
||||
:int, 4,
|
||||
:voidp, "Hello",
|
||||
:const_string, "World")
|
||||
assert_equal("int: -29, string: Hell, const string: World\n",
|
||||
output_buffer[0, written])
|
||||
string_like_class = Class.new do
|
||||
def initialize(string)
|
||||
@string = string
|
||||
end
|
||||
|
||||
string_like_class = Class.new do
|
||||
def initialize(string)
|
||||
@string = string
|
||||
end
|
||||
|
||||
def to_str
|
||||
@string
|
||||
def to_str
|
||||
@string
|
||||
end
|
||||
end
|
||||
written = snprintf.call(output,
|
||||
output.size,
|
||||
"string: %.*s, const string: %s, uint: %u\n",
|
||||
:int, 2,
|
||||
:voidp, "Hello",
|
||||
:const_string, string_like_class.new("World"),
|
||||
:int, 29)
|
||||
assert_equal("string: He, const string: World, uint: 29\n",
|
||||
output[0, written])
|
||||
end
|
||||
written = snprintf.call(output,
|
||||
output.size,
|
||||
"string: %.*s, const string: %s, uint: %u\n",
|
||||
:int, 2,
|
||||
:voidp, "Hello",
|
||||
:const_string, string_like_class.new("World"),
|
||||
:int, 29)
|
||||
assert_equal("string: He, const string: World, uint: 29\n",
|
||||
output_buffer[0, written])
|
||||
end
|
||||
|
||||
def test_rb_memory_view_available_p
|
||||
|
@ -16,6 +16,8 @@ module Fiddle
|
||||
end
|
||||
|
||||
def teardown
|
||||
# We can't use ObjectSpace with JRuby.
|
||||
return if RUBY_ENGINE == "jruby"
|
||||
# Ensure freeing all closures.
|
||||
# See https://github.com/ruby/fiddle/issues/102#issuecomment-1241763091 .
|
||||
not_freed_closures = []
|
||||
@ -36,6 +38,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_need_gvl?
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("rb_str_dup() doesn't exit in JRuby")
|
||||
end
|
||||
|
||||
libruby = Fiddle.dlopen(nil)
|
||||
rb_str_dup = Function.new(libruby['rb_str_dup'],
|
||||
[:voidp],
|
||||
@ -103,6 +109,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_last_error
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle.last_error doesn't work with JRuby")
|
||||
end
|
||||
|
||||
func = Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
|
||||
|
||||
assert_nil Fiddle.last_error
|
||||
@ -135,6 +145,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_strcpy
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Function that returns string doesn't work with JRuby")
|
||||
end
|
||||
|
||||
f = Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
|
||||
buff = +"000"
|
||||
str = f.call(buff, "123")
|
||||
@ -149,6 +163,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_function_as_proc
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Function that returns string doesn't work with JRuby")
|
||||
end
|
||||
|
||||
f = Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
|
||||
buff, str = call_proc("123", &f)
|
||||
assert_equal("123", buff)
|
||||
@ -156,6 +174,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_function_as_method
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Function that returns string doesn't work with JRuby")
|
||||
end
|
||||
|
||||
f = Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
|
||||
klass = Class.new do
|
||||
define_singleton_method(:strcpy, &f)
|
||||
@ -194,6 +216,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_no_memory_leak
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("rb_obj_frozen_p() doesn't exist in JRuby")
|
||||
end
|
||||
|
||||
if respond_to?(:assert_nothing_leaked_memory)
|
||||
rb_obj_frozen_p_symbol = Fiddle.dlopen(nil)["rb_obj_frozen_p"]
|
||||
rb_obj_frozen_p = Fiddle::Function.new(rb_obj_frozen_p_symbol,
|
||||
|
@ -9,11 +9,19 @@ module Fiddle
|
||||
include Fiddle
|
||||
|
||||
def test_to_i
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Handle#to_i is unavailable with JRuby")
|
||||
end
|
||||
|
||||
handle = Fiddle::Handle.new(LIBC_SO)
|
||||
assert_kind_of Integer, handle.to_i
|
||||
end
|
||||
|
||||
def test_to_ptr
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Handle#to_i is unavailable with JRuby")
|
||||
end
|
||||
|
||||
handle = Fiddle::Handle.new(LIBC_SO)
|
||||
ptr = handle.to_ptr
|
||||
assert_equal ptr.to_i, handle.to_i
|
||||
@ -26,6 +34,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_static_sym
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("We can't assume static symbols with JRuby")
|
||||
end
|
||||
|
||||
begin
|
||||
# Linux / Darwin / FreeBSD
|
||||
refute_nil Fiddle::Handle.sym('dlopen')
|
||||
@ -90,6 +102,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_initialize_noargs
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("rb_str_new() doesn't exist in JRuby")
|
||||
end
|
||||
|
||||
handle = Handle.new
|
||||
refute_nil handle['rb_str_new']
|
||||
end
|
||||
@ -117,6 +133,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_file_name
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Handle::NEXT doesn't exist with JRuby")
|
||||
end
|
||||
|
||||
file_name = Handle.new(LIBC_SO).file_name
|
||||
if file_name
|
||||
assert_kind_of String, file_name
|
||||
@ -135,6 +155,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_NEXT
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Handle::NEXT doesn't exist with JRuby")
|
||||
end
|
||||
|
||||
begin
|
||||
# Linux / Darwin
|
||||
#
|
||||
@ -173,9 +197,13 @@ module Fiddle
|
||||
end unless /mswin|mingw/ =~ RUBY_PLATFORM
|
||||
|
||||
def test_DEFAULT
|
||||
if Fiddle::WINDOWS
|
||||
omit("Fiddle::Handle::DEFAULT doesn't have malloc() on Windows")
|
||||
end
|
||||
|
||||
handle = Handle::DEFAULT
|
||||
refute_nil handle['malloc']
|
||||
end unless /mswin|mingw/ =~ RUBY_PLATFORM
|
||||
end
|
||||
|
||||
def test_dlerror
|
||||
# FreeBSD (at least 7.2 to 7.2) calls nsdispatch(3) when it calls
|
||||
|
@ -149,11 +149,15 @@ module Fiddle
|
||||
def test_unsigned_result()
|
||||
d = (2 ** 31) + 1
|
||||
|
||||
r = LIBC.strtoul(d.to_s, 0, 0)
|
||||
r = LIBC.strtoul(d.to_s, nil, 0)
|
||||
assert_equal(d, r)
|
||||
end
|
||||
|
||||
def test_io()
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("BUILD_RUBY_PLATFORM doesn't exist in JRuby")
|
||||
end
|
||||
|
||||
if( RUBY_PLATFORM != BUILD_RUBY_PLATFORM ) || !defined?(LIBC.fprintf)
|
||||
return
|
||||
end
|
||||
@ -329,11 +333,12 @@ module Fiddle
|
||||
|
||||
def test_struct_nested_struct_replace_array_element_hash()
|
||||
LIBC::StructNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
|
||||
s.vertices[0] = nil
|
||||
s.vertices[0] = {
|
||||
position: {
|
||||
x: 10,
|
||||
y: 100,
|
||||
}
|
||||
},
|
||||
}
|
||||
assert_equal({
|
||||
"position" => {
|
||||
@ -450,7 +455,7 @@ module Fiddle
|
||||
s.buff = "012345\377"
|
||||
assert_equal([0,1,2,3,4], s.num)
|
||||
assert_equal(?a.ord, s.c)
|
||||
assert_equal([?0.ord,?1.ord,?2.ord,?3.ord,?4.ord,?5.ord,?\377.ord], s.buff)
|
||||
assert_equal([?0.ord,?1.ord,?2.ord,?3.ord,?4.ord,?5.ord,"\xFF".ord], s.buff)
|
||||
end
|
||||
end
|
||||
|
||||
@ -467,6 +472,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_strcpy()
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Function that returns string doesn't work with JRuby")
|
||||
end
|
||||
|
||||
buff = +"000"
|
||||
str = LIBC.strcpy(buff, "123")
|
||||
assert_equal("123", buff)
|
||||
|
@ -11,19 +11,22 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_can_read_write_memory
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Pointer.{read,write} don't exist in JRuby")
|
||||
end
|
||||
|
||||
# Allocate some memory
|
||||
address = Fiddle.malloc(Fiddle::SIZEOF_VOIDP)
|
||||
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |pointer|
|
||||
address = pointer.to_i
|
||||
bytes_to_write = Fiddle::SIZEOF_VOIDP.times.to_a.pack("C*")
|
||||
|
||||
bytes_to_write = Fiddle::SIZEOF_VOIDP.times.to_a.pack("C*")
|
||||
# Write to the memory
|
||||
Fiddle::Pointer.write(address, bytes_to_write)
|
||||
|
||||
# Write to the memory
|
||||
Fiddle::Pointer.write(address, bytes_to_write)
|
||||
|
||||
# Read the bytes out again
|
||||
bytes = Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP)
|
||||
assert_equal bytes_to_write, bytes
|
||||
ensure
|
||||
Fiddle.free address
|
||||
# Read the bytes out again
|
||||
bytes = Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP)
|
||||
assert_equal bytes_to_write, bytes
|
||||
end
|
||||
end
|
||||
|
||||
def test_cptr_to_int
|
||||
@ -110,6 +113,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_inspect
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Pointer#inspect is incompatible on JRuby")
|
||||
end
|
||||
|
||||
ptr = Pointer.new(0)
|
||||
inspect = ptr.inspect
|
||||
assert_match(/size=#{ptr.size}/, inspect)
|
||||
@ -125,6 +132,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_to_ptr_io
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle::Pointer.to_ptr(IO) isn't supported with JRuby")
|
||||
end
|
||||
|
||||
Pointer.malloc(10, Fiddle::RUBY_FREE) do |buf|
|
||||
File.open(__FILE__, 'r') do |f|
|
||||
ptr = Pointer.to_ptr f
|
||||
@ -172,6 +183,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_ref_ptr
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle.dlwrap([]) isn't supported with JRuby")
|
||||
end
|
||||
|
||||
ary = [0,1,2,4,5]
|
||||
addr = Pointer.new(dlwrap(ary))
|
||||
assert_equal addr.to_i, addr.ref.ptr.to_i
|
||||
@ -180,6 +195,10 @@ module Fiddle
|
||||
end
|
||||
|
||||
def test_to_value
|
||||
if RUBY_ENGINE == "jruby"
|
||||
omit("Fiddle.dlwrap([]) isn't supported with JRuby")
|
||||
end
|
||||
|
||||
ary = [0,1,2,4,5]
|
||||
addr = Pointer.new(dlwrap(ary))
|
||||
assert_equal ary, addr.to_value
|
||||
|
Loading…
x
Reference in New Issue
Block a user