class Fiddle::Pointer
Fiddle::Pointer is a class to handle C pointers
Attributes
Public Class Methods
Get the underlying pointer for ruby object val and return it as a Fiddle::Pointer object.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 236 def self.from_native(value, ctx) self.new(value) end
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 338
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 Examples
# Automatically freeing the pointer when the block is exited - recommended Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer| ... end # Manually freeing but relying on the garbage collector otherwise pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) ... pointer.call_free # Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) ... # Only manually freeing pointer = Fiddle::Pointer.malloc(size) begin ... ensure Fiddle.free pointer end # No free function and no call to free - the native memory will leak if the pointer is garbage collected pointer = Fiddle::Pointer.malloc(size) ...
Allocate size bytes of memory and associate it with an optional freefunc.
If a block is supplied, the pointer will be yielded to the block instead of being returned, and the return value of the block will be returned. A freefunc must be supplied if a block is.
If a freefunc is supplied it will be called once, when the pointer is garbage collected or when the block is left if a block is supplied or when the user calls call_free, whichever happens first. freefunc must be an address pointing to a function or an instance of Fiddle::Function.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 300
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"
else
FFI::Pointer.new(Integer(addr))
end
@size = size ? size : ptr.size
@free = free
@ffi_ptr = ptr
@freed = false
end Source
static VALUE
rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
{
VALUE ptr, sym, size, wrap = 0, funcwrap = 0;
struct ptr_data *data;
void *p = NULL;
freefunc_t f = NULL;
long s = 0;
if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) {
VALUE addrnum = rb_Integer(ptr);
if (addrnum != ptr) wrap = ptr;
p = NUM2PTR(addrnum);
}
if (argc >= 2) {
s = NUM2LONG(size);
}
if (argc >= 3) {
f = get_freefunc(sym, &funcwrap);
}
if (p) {
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
if (data->ptr && data->free) {
/* Free previous memory. Use of inappropriate initialize may cause SEGV. */
(*(data->free))(data->ptr);
}
RB_OBJ_WRITE(self, &data->wrap[0], wrap);
RB_OBJ_WRITE(self, &data->wrap[1], funcwrap);
data->ptr = p;
data->size = s;
data->free = f;
}
return Qnil;
} Create a new pointer to address with an optional size and freefunc.
freefunc will be called when the instance is garbage collected.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 269 def self.read(addr, len) FFI::Pointer.new(addr).read_bytes(len) end
Or read the memory at address address with length len and return a string with that memory
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 224
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 Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 240
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 Get the underlying pointer for ruby object val and return it as a Fiddle::Pointer object.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 265 def self.write(addr, bytes) FFI::Pointer.new(addr).write_bytes(bytes) end
Write bytes in str to the location pointed to by address.
Public Instance Methods
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 440 def +(delta) self.class.new(to_i + delta, @size - delta) end
Returns a new pointer instance that has been advanced n bytes.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 468 def +@ ptr end
Returns a new Fiddle::Pointer instance that is a dereferenced pointer for this pointer.
Analogous to the star operator in C.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 444 def -(delta) self.class.new(to_i - delta, @size + delta) end
Returns a new pointer instance that has been moved back n bytes.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 472 def -@ ref end
Returns a new Fiddle::Pointer instance that is a reference pointer for this pointer.
Analogous to the ampersand operator in C.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 448 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
Returns -1 if less than, 0 if equal to, 1 if greater than other.
Returns nil if ptr cannot be compared to other.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 460 def ==(other) eql?(other) end
Returns true if other wraps the same pointer, otherwise returns false.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 396
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 Returns integer stored at index.
If start and length are given, a string containing the bytes from start of length will be returned.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 277
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 Set the value at index to int.
Or, set the memory at start until length with the contents of string, the memory from dl_cptr, or the memory pointed at by the memory address addr.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 377
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 Call the free function for this pointer. Calling more than once will do nothing. Does nothing if there is no free function attached.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 455 def eql?(other) return unless other.is_a?(Pointer) self.to_i == other.to_i end
Returns true if other wraps the same pointer, otherwise returns false.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 369 def free @free end
Get the free function for this pointer.
Returns a new instance of Fiddle::Function.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 373 def free=(free) @free = free end
Set the free function for this pointer to function in the given Fiddle::Function.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 388 def freed? @freed end
Returns if the free function for this pointer has been called.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 436
def inspect
"#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>"
end Returns a string formatted with an easily readable representation of the internal state of the pointer.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 357 def null? @ffi_ptr.null? end
Returns true if this is a null pointer.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 464 def ptr Pointer.new(ffi_ptr.get_pointer(0)) end
Returns a new Fiddle::Pointer instance that is a dereferenced pointer for this pointer.
Analogous to the star operator in C.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 476 def ref cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE) cptr.ffi_ptr.put_pointer(0, ffi_ptr) cptr end
Returns a new Fiddle::Pointer instance that is a reference pointer for this pointer.
Analogous to the ampersand operator in C.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 365 def size defined?(@layout) ? @layout.size : @size end
Get the size of this pointer.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 392 def size=(size) @size = size end
Set the size of this pointer to size
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 406 def to_i ffi_ptr.to_i end
Returns the integer memory location of this pointer.
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 412
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 without 0
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 422
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 ptr.to_str => string ptr.to_str(len) => string
Returns the pointer contents as a string.
When called with no arguments, this method will return the contents with the length of this pointer’s size.
When called with len, a string of len bytes will be returned.
See to_s
Source
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 432 def to_value raise NotImplementedError, "to_value isn't supported" end
Cast this pointer to a ruby object.
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.