Fiddle::Pointer
is a class to handle C pointers
# File tmp/rubies/ruby-3.4.1/ext/fiddle/lib/fiddle/ffi_backend.rb, line 236
def self.from_native(value, ctx)
self.new(value)
end
# File tmp/rubies/ruby-3.4.1/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
.
# File tmp/rubies/ruby-3.4.1/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
# File tmp/rubies/ruby-3.4.1/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
# File tmp/rubies/ruby-3.4.1/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
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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
.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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
.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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
.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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
.
# File tmp/rubies/ruby-3.4.1/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
.
# File tmp/rubies/ruby-3.4.1/ext/fiddle/lib/fiddle/ffi_backend.rb, line 388
def freed?
@freed
end
Returns if the free function for this pointer has been called.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/ext/fiddle/lib/fiddle/ffi_backend.rb, line 357
def null?
@ffi_ptr.null?
end
Returns true
if this is a null pointer.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/ext/fiddle/lib/fiddle/ffi_backend.rb, line 365
def size
defined?(@layout) ? @layout.size : @size
end
Get the size of this pointer.
# File tmp/rubies/ruby-3.4.1/ext/fiddle/lib/fiddle/ffi_backend.rb, line 392
def size=(size)
@size = size
end
Set
the size of this pointer to size
# File tmp/rubies/ruby-3.4.1/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.
# File tmp/rubies/ruby-3.4.1/ext/fiddle/lib/fiddle/ffi_backend.rb, line 361
def to_ptr
@ffi_ptr
end
# File tmp/rubies/ruby-3.4.1/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
# File tmp/rubies/ruby-3.4.1/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
# File tmp/rubies/ruby-3.4.1/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.