123456789_123456789_123456789_123456789_123456789_

Class: Fiddle::Pointer

Relationships & Source Files
Namespace Children
Modules:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, FFI::DataConverter
Inherits: Object
Defined in: ext/fiddle/pointer.c,
ext/fiddle/pointer.c,
lib/fiddle/ffi_backend.rb

Overview

Pointer is a class to handle C pointers

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(addr, size = nil, free = nil) ⇒ Pointer

[ GitHub ]

  
# File '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

#new(address) ⇒ fiddle_cptr #new(address, size) ⇒ fiddle_cptr #new(address, size, freefunc) ⇒ fiddle_cptr

Create a new pointer to address with an optional #size and freefunc.

freefunc will be called when the instance is garbage collected.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 216

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;
}

Class Method Details

.[](value)

Alias for .to_ptr.

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 274

alias [] to_ptr

.from_native(value, ctx)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 236

def self.from_native(value, ctx)
  self.new(value)
end

.malloc(size, free = nil)

[ GitHub ]

  
# File '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

.read(addr, len)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 269

def self.read(addr, len)
  FFI::Pointer.new(addr).read_bytes(len)
end

.to_native(value, ctx)

[ GitHub ]

  
# File '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

.to_ptr(value) Also known as: .[]

[ GitHub ]

  
# File '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

.write(addr, bytes)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 265

def self.write(addr, bytes)
  FFI::Pointer.new(addr).write_bytes(bytes)
end

Instance Attribute Details

#ffi_ptr (readonly)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 220

attr_reader :ffi_ptr

#free (rw)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 369

def free
  @free
end

#free=(free) (rw)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 373

def free=(free)
  @free = free
end

#freed?Boolean (readonly)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 388

def freed?
  @freed
end

#null?Boolean (readonly)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 357

def null?
  @ffi_ptr.null?
end

#size (rw)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 365

def size
  defined?(@layout) ? @layout.size : @size
end

#size=(size) (rw)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 392

def size=(size)
  @size = size
end

Instance Method Details

#+(delta)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 440

def +(delta)
  self.class.new(to_i + delta, @size - delta)
end

#+@

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 468

def +@
  ptr
end

#-(delta)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 444

def -(delta)
  self.class.new(to_i - delta, @size + delta)
end

#-@

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 472

def -@
  ref
end

#<=>(other)

[ GitHub ]

  
# File '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

#==(other)

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 460

def ==(other)
  eql?(other)
end

#[](index) ⇒ Integer #[](start, length) ⇒ String

Returns integer stored at index.

If start and length are given, a string containing the bytes from start of length will be returned.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 666

static VALUE
rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
{
    VALUE arg0, arg1;
    VALUE retval = Qnil;
    size_t offset, len;
    struct ptr_data *data;

    TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
    if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
    switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
      case 1:
	offset = NUM2ULONG(arg0);
	retval = INT2NUM(*((char *)data->ptr + offset));
	break;
      case 2:
	offset = NUM2ULONG(arg0);
	len    = NUM2ULONG(arg1);
	retval = rb_str_new((char *)data->ptr + offset, len);
	break;
      default:
	rb_bug("rb_fiddle_ptr_aref()");
    }
    return retval;
}

#[]=(*args, value)

[ GitHub ]

  
# File '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

#call_free

[ GitHub ]

  
# File '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

#eql?(other) ⇒ Boolean

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 455

def eql?(other)
  return unless other.is_a?(Pointer)
  self.to_i == other.to_i
end

#inspect

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 436

def inspect
  "#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>"
end

#ptr

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 464

def ptr
  Pointer.new(ffi_ptr.get_pointer(0))
end

#ref

[ GitHub ]

  
# File '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

#to_i Also known as: #to_int

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 406

def to_i
  ffi_ptr.to_i
end

#to_int

Alias for #to_i.

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 409

alias to_int to_i

#to_ptr

[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 361

def to_ptr
  @ffi_ptr
end

#to_s(len = nil)

without 0

[ GitHub ]

  
# File '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

#to_str(len = nil)

[ GitHub ]

  
# File '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

#to_value

Raises:

  • (NotImplementedError)
[ GitHub ]

  
# File 'lib/fiddle/ffi_backend.rb', line 432

def to_value
  raise NotImplementedError, "to_value isn't supported"
end