class Fiddle::CStructEntity

A pointer to a C structure

Public Class Methods

alignment (types)
# File ext/fiddle/lib/fiddle/struct.rb, line 277
def CStructEntity.alignment(types)
  max = 1
  types.each do |type, count = 1|
    if type.respond_to?(:entity_class)
      n = type.alignment
    else
      n = ALIGN_MAP[type]
    end
    max = n if n > max
  end
  max
end
malloc (types, func = nil, size = size(types)) { |struct| ... }

Allocates a C struct with the types provided.

See Fiddle::Pointer.malloc for memory management issues.

Calls superclass method Fiddle::Pointer::malloc
# File ext/fiddle/lib/fiddle/struct.rb, line 293
def CStructEntity.malloc(types, func = nil, size = size(types), &block)
  if block_given?
    super(size, func) do |struct|
      struct.set_ctypes types
      yield struct
    end
  else
    struct = super(size, func)
    struct.set_ctypes types
    struct
  end
end
new (addr, types, func = nil)

Wraps the C pointer addr as a C struct with the given types.

When the instance is garbage collected, the C function func is called.

See also Fiddle::Pointer.new

Calls superclass method Fiddle::Pointer::new
# File ext/fiddle/lib/fiddle/struct.rb, line 340
def initialize(addr, types, func = nil)
  if func && addr.is_a?(Pointer) && addr.free
    raise ArgumentError, 'free function specified on both underlying struct Pointer and when creating a CStructEntity - who do you want to free this?'
  end
  set_ctypes(types)
  super(addr, @size, func)
end
size (types)

Returns the offset for the packed sizes for the given types.

Fiddle::CStructEntity.size(
  [ Fiddle::TYPE_DOUBLE,
    Fiddle::TYPE_INT,
    Fiddle::TYPE_CHAR,
    Fiddle::TYPE_VOIDP ]) #=> 24
# File ext/fiddle/lib/fiddle/struct.rb, line 313
def CStructEntity.size(types)
  offset = 0

  max_align = types.map { |type, count = 1|
    last_offset = offset

    if type.respond_to?(:entity_class)
      align = type.alignment
      type_size = type.size
    else
      align = PackInfo::ALIGN_MAP[type]
      type_size = PackInfo::SIZE_MAP[type]
    end
    offset = PackInfo.align(last_offset, align) +
             (type_size * count)

    align
  }.max

  PackInfo.align(offset, max_align)
end

Public Instance Methods

[] (*args)

Fetch struct member name if only one argument is specified. If two arguments are specified, the first is an offset and the second is a length and this method returns the string of length bytes beginning at offset.

Examples:

my_struct = struct(['int id']).malloc
my_struct.id = 1
my_struct['id'] # => 1
my_struct[0, 4] # => "\x01\x00\x00\x00".b
Calls superclass method Fiddle::Pointer::[]
# File ext/fiddle/lib/fiddle/struct.rb, line 413
def [](*args)
  return super(*args) if args.size > 1
  name = args[0]
  idx = @members.index(name)
  if( idx.nil? )
    raise(ArgumentError, "no such member: #{name}")
  end
  ty = @ctypes[idx]
  if( ty.is_a?(Array) )
    if ty.first.respond_to?(:entity_class)
      return @nested_structs[name]
    else
      r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
    end
  elsif ty.respond_to?(:entity_class)
    return @nested_structs[name]
  else
    r = super(@offset[idx], SIZE_MAP[ty.abs])
  end
  packer = Packer.new([ty])
  val = packer.unpack([r])
  case ty
  when Array
    case ty[0]
    when TYPE_VOIDP
      val = val.collect{|v| Pointer.new(v)}
    end
  when TYPE_VOIDP
    val = Pointer.new(val[0])
  else
    val = val[0]
  end
  if( ty.is_a?(Integer) && (ty < 0) )
    return unsigned_value(val, ty)
  elsif( ty.is_a?(Array) && (ty[0] < 0) )
    return StructArray.new(self + @offset[idx], ty[0], val)
  else
    return val
  end
end
[]= (*args)

Set struct member name, to value val. If more arguments are specified, writes the string of bytes to the memory at the given offset and length.

Examples:

my_struct = struct(['int id']).malloc
my_struct['id'] = 1
my_struct[0, 4] = "\x01\x00\x00\x00".b
my_struct.id # => 1
Calls superclass method Fiddle::Pointer#[]=
# File ext/fiddle/lib/fiddle/struct.rb, line 465
def []=(*args)
  return super(*args) if args.size > 2
  name, val = *args
  name = name.to_s if name.is_a?(Symbol)
  nested_struct = @nested_structs[name]
  if nested_struct
    if nested_struct.is_a?(StructArray)
      if val.nil?
        nested_struct.each do |s|
          s.replace(nil)
        end
      else
        val.each_with_index do |v, i|
          nested_struct[i] = v
        end
      end
    else
      nested_struct.replace(val)
    end
    return val
  end
  idx = @members.index(name)
  if( idx.nil? )
    raise(ArgumentError, "no such member: #{name}")
  end
  ty  = @ctypes[idx]
  packer = Packer.new([ty])
  val = wrap_arg(val, ty, [])
  buff = packer.pack([val].flatten())
  super(@offset[idx], buff.size, buff)
  if( ty.is_a?(Integer) && (ty < 0) )
    return unsigned_value(val, ty)
  elsif( ty.is_a?(Array) && (ty[0] < 0) )
    return val.collect{|v| unsigned_value(v,ty[0])}
  else
    return val
  end
end
assign_names (members)

Set the names of the members in this C struct

# File ext/fiddle/lib/fiddle/struct.rb, line 349
def assign_names(members)
  @members = []
  @nested_structs = {}
  members.each_with_index do |member, index|
    if member.is_a?(Array) # nested struct
      member_name = member[0]
      struct_type, struct_count = @ctypes[index]
      if struct_count.nil?
        struct = struct_type.new(to_i + @offset[index])
      else
        structs = struct_count.times.map do |i|
          struct_type.new(to_i + @offset[index] + i * struct_type.size)
        end
        struct = StructArray.new(to_i + @offset[index],
                                 struct_type,
                                 structs)
      end
      @nested_structs[member_name] = struct
    else
      member_name = member
    end
    @members << member_name
  end
end
set_ctypes (types)

Calculates the offsets and sizes for the given types in the struct.

# File ext/fiddle/lib/fiddle/struct.rb, line 375
def set_ctypes(types)
  @ctypes = types
  @offset = []
  offset = 0

  max_align = types.map { |type, count = 1|
    orig_offset = offset
    if type.respond_to?(:entity_class)
      align = type.alignment
      type_size = type.size
    else
      align = ALIGN_MAP[type]
      type_size = SIZE_MAP[type]
    end
    offset = PackInfo.align(orig_offset, align)

    @offset << offset

    offset += (type_size * count)

    align
  }.max

  @size = PackInfo.align(offset, max_align)
end