Skip to content
29 changes: 28 additions & 1 deletion lib/fiddle/struct.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,33 @@ def CUnion.entity_class
end
end

# Wrapper for arrays within a struct
class StructArray < Array
include ValueUtil

def initialize(ptr, type, initial_values)
@ptr = ptr
@type = type
@align = PackInfo::ALIGN_MAP[type]
@size = Fiddle::PackInfo::SIZE_MAP[type]
@pack_format = Fiddle::PackInfo::PACK_MAP[type]
super(initial_values.collect { |v| unsigned_value(v, type) })
end

def to_ptr
@ptr
end

def []=(index, value)
if index < 0 || index >= size
raise IndexError, 'index %d outside of array bounds 0...%d' % [index, size]
end

to_ptr[index * @size, @size] = [value].pack(@pack_format)
super(index, value)
end
end

# Used to construct C classes (CUnion, CStruct, etc)
#
# Fiddle::Importer#struct and Fiddle::Importer#union wrap this functionality in an
Expand Down Expand Up @@ -191,7 +218,7 @@ def [](*args)
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])}
return StructArray.new(self + @offset[idx], ty[0], val)
else
return val
end
Expand Down
14 changes: 14 additions & 0 deletions test/fiddle/test_import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,20 @@ def test_value()
assert_equal([0,1,2], ary.value)
end

def test_struct_array_assignment()
instance = Fiddle::Importer.struct(["unsigned int stages[3]"]).malloc
instance.stages[0] = 1024
instance.stages[1] = 10
instance.stages[2] = 100
assert_equal 1024, instance.stages[0]
assert_equal 10, instance.stages[1]
assert_equal 100, instance.stages[2]
assert_equal [1024, 10, 100].pack(Fiddle::PackInfo::PACK_MAP[-Fiddle::TYPE_INT] * 3),
instance.to_ptr[0, 3 * Fiddle::SIZEOF_INT]
assert_raise(IndexError) { instance.stages[-1] = 5 }
assert_raise(IndexError) { instance.stages[3] = 5 }
end

def test_struct()
s = LIBC::MyStruct.malloc()
s.num = [0,1,2,3,4]
Expand Down