A pointer to a C structure
# File fiddle/lib/fiddle/struct.rb, line 206
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
Allocates a C struct with the types provided.
See Fiddle::Pointer.malloc for memory management issues.
# File fiddle/lib/fiddle/struct.rb, line 222
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
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
# File fiddle/lib/fiddle/struct.rb, line 269
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
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 fiddle/lib/fiddle/struct.rb, line 242
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
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
# File fiddle/lib/fiddle/struct.rb, line 342
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
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
# File fiddle/lib/fiddle/struct.rb, line 394
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
Set the names of the members in this C struct
# File fiddle/lib/fiddle/struct.rb, line 278
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
Calculates the offsets and sizes for the given types in the
struct.
# File fiddle/lib/fiddle/struct.rb, line 304
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