Parent

Included Modules

NiceFFI::Struct

A class to be used as a baseclass where you would use FFI::Struct. It acts mostly like FFI::Struct, but with nice extra features and conveniences to make life easier:

Public Class Methods

hidden( *members ) click to toggle source

Mark the given members as hidden, i.e. do not create accessors for them in layout, and do not print them out in to_s, etc. You can call this before or after calling layout, and can call it more than once if you like.

Note: They can still be read and written via #[] and #[]=, but will not have convenience accessors.

Note: This will remove the accessor methods (if they exist) for the members! So if you're defining your own custom accessors, do that after you have called this method.

Example:

class SecretStruct < NiceStruct

  # You can use it before the layout...
  hidden( :hidden1 )

  layout( :visible1, :uint16,
          :visible2, :int,
          :hidden1,  :uint,
          :hidden2,  :pointer )

  # ... and/or after it.
  hidden( :hidden2 )

  # :hidden1 and :hidden2 are now both hidden.
end
# File lib/nice-ffi/struct.rb, line 138
def hidden( *members )
  if defined?(@hidden_members)
    @hidden_members += members
  else
    @hidden_members = members 
  end

  members.each do |member|
    # Remove the accessors if they exist.
    [member, "#{member}=".to_sym].each { |m|
      begin
        remove_method( m )
      rescue NameError
      end
    }
  end
end
hidden?( member ) click to toggle source

True if the member has been marked hidden, false otherwise.

# File lib/nice-ffi/struct.rb, line 158
def hidden?( member )
  return false unless defined?(@hidden_members)
  @hidden_members.include?( member )
end
layout( *spec ) click to toggle source

Same syntax as FFI::Struct#layout, but also defines nice accessors for the attributes.

Example:

class Rect < NiceStruct
  layout( :x, :int16,
          :y, :int16,
          :w, :uint16,
          :h, :uint16 )
end
# File lib/nice-ffi/struct.rb, line 85
def layout( *spec )
  @nice_spec = spec

  # Wrap the members.
  0.step(spec.size - 1, 2) { |index|
    member, type = spec[index, 2]
    wrap_member( member, type)
  }

  simple_spec = spec.collect { |a|
    case a
    when NiceFFI::TypedPointer
      :pointer
    else
      a
    end
  }

  # Normal FFI::Struct behavior
  super( *simple_spec )
end
new( val, options={} ) click to toggle source

Create a new instance of the class, reading data from a Hash or Array of attributes, a bytestring of raw data, copying from another instance of the class, or wrapping (not copying!) a FFI::Pointer.

If val is an instance of FFI::Pointer and you have defined MyClass.release, the pointer will be passed to MyClass.release when the memory is no longer being used. Use MyClass.release to free the memory for the struct, as appropriate for your class. To disable autorelease for this instance, set {:autorelease => false} in options.

(Note: FFI::MemoryPointer and FFI::Buffer have built-in memory management, so MyClass.release is never called for them.)

# File lib/nice-ffi/struct.rb, line 331
def initialize( val, options={} )
  # Stores certain kinds of member values so that we don't need
  # to create a new object every time they are read.
  @member_cache = {}

  options = {:autorelease => true}.merge!( options )

  case val

  when Hash
    super(FFI::Buffer.new(size))
    init_from_hash( val )         # Read the values from a Hash.

  # Note: plain "Array" would mean FFI::Struct::Array in this scope.
  when ::Array
    super(FFI::Buffer.new(size))
    init_from_array( val )        # Read the values from an Array.

  when String
    super(FFI::Buffer.new(size))
    init_from_bytes( val )        # Read the values from a bytestring.

  when self.class
    super(FFI::Buffer.new(size))
    init_from_bytes( val.to_bytes ) # Read the values from another instance.

  when FFI::Pointer, FFI::Buffer
    val = _make_autopointer( val, options[:autorelease] )

    # Normal FFI::Struct behavior to wrap the pointer.
    super( val )

  else
    raise TypeError, "cannot create new #{self.class} from #{val.inspect}"

  end
end
read_only( *members ) click to toggle source

Mark the given members as read-only, so they won't have write accessors.

Note: They can still be written via #[]=, but will not have convenience accessors.

Note: This will remove the writer method (if it exists) for the members! So if you're defining your own custom writer, do that after you have called this method.

Example:

class SecretStruct < NiceStruct

  # You can use it before the layout...
  read_only( :readonly1 )

  layout( :visible1,  :uint16,
          :visible2,  :int,
          :readonly1, :uint,
          :readonly2, :pointer )

  # ... and/or after it.
  read_only( :readonly2 )

  # :readonly1 and :readonly2 are now both read-only.
end
# File lib/nice-ffi/struct.rb, line 192
def read_only( *members )
  if defined?(@readonly_members)
    @readonly_members += members
  else
    @readonly_members = members 
  end

  members.each do |member|
    # Remove the write accessor if it exists.
    begin
      remove_method( "#{member}=".to_sym )
    rescue NameError
    end
  end
end
read_only?( member ) click to toggle source

True if the member has been marked read_only, false otherwise.

# File lib/nice-ffi/struct.rb, line 209
def read_only?( member )
  return false unless defined?(@readonly_members)
  @readonly_members.include?( member )
end
typed_pointer( options={} ) click to toggle source

Returns a NiceFFI::TypedPointer instance for this class. Equivalent to NiceFFI::TypedPointer.new( this_class, options )

# File lib/nice-ffi/struct.rb, line 68
def typed_pointer( options={} )
  NiceFFI::TypedPointer.new(self, options)
end

Public Instance Methods

inspect() click to toggle source
Alias for: to_s
to_ary() click to toggle source

Dump this instance as an Array of its struct data. The array contains only the data, not the member names.

Note: the order of data in the array always matches the order of members given in layout.

Example:

Rect.new( :x=>1, :y=>2, :w=>3, :h=>4 ).to_ary
# => [1,2,3,4]
# File lib/nice-ffi/struct.rb, line 404
def to_ary
  members.collect{ |m| self[m] }
end
to_bytes() click to toggle source

Dump this instance as a string of raw bytes of its struct data.

# File lib/nice-ffi/struct.rb, line 411
def to_bytes
  return self.pointer.get_bytes(0, self.size)
end
to_hash() click to toggle source

Dump this instance as a Hash containing {member => data} pairs for every member in the struct.

Example:

Rect.new( :x=>1, :y=>2, :w=>3, :h=>4 ).to_hash
# => {:h=>4, :w=>3, :x=>1, :y=>2}
# File lib/nice-ffi/struct.rb, line 424
def to_hash
  return {} if members.empty?
  Hash[ *(members.collect{ |m| [m, self[m]] }.flatten!) ]
end
to_s() click to toggle source
# File lib/nice-ffi/struct.rb, line 430
def to_s
  begin
    if self.pointer.null?
      return "#<NULL %s:%#.x>"%[self.class.name, self.object_id]
    end
  rescue NoMethodError
  end

  mems = members.collect{ |m|
    unless self.class.hidden?( m )
      val = self.send(m)

      # Cleanup/simplify for display
      if val.nil? or (val.is_a? FFI::Pointer and val.null?)
        val = "NULL" 
      elsif val.kind_of? FFI::Struct
        val = "#<#{val.class}:%#.x>"%val.object_id
      end
      
      "@#{m}=#{val}"
    end
  }.compact.join(", ")

  if( mems == "" )
    return "#<%s:%#.x>"%[self.class.name, self.object_id]
  else
    return "#<%s:%#.x %s>"%[self.class.name, self.object_id, mems]
  end
end
Also aliased as: inspect

[Validate]

Generated with the Darkfish Rdoc Generator 2.