diff --git a/ext/fiddle/lib/fiddle/struct.rb b/ext/fiddle/lib/fiddle/struct.rb index f5385e548c..8a48a1cb8b 100644 --- a/ext/fiddle/lib/fiddle/struct.rb +++ b/ext/fiddle/lib/fiddle/struct.rb @@ -20,6 +20,33 @@ module Fiddle 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 @@ -191,7 +218,7 @@ module Fiddle 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 diff --git a/test/fiddle/test_import.rb b/test/fiddle/test_import.rb index 778327b4b2..867f6960ee 100644 --- a/test/fiddle/test_import.rb +++ b/test/fiddle/test_import.rb @@ -129,6 +129,20 @@ module Fiddle 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]