ffi 1.9.21 → 1.9.22

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (151) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +22 -0
  5. data/.gitmodules +3 -0
  6. data/.travis.yml +52 -0
  7. data/.yardopts +5 -0
  8. data/Gemfile +15 -0
  9. data/{spec/ffi/LICENSE.SPECS → LICENSE.SPECS} +1 -1
  10. data/README.md +1 -1
  11. data/Rakefile +28 -3
  12. data/appveyor.yml +22 -0
  13. data/ext/ffi_c/Call.c +1 -22
  14. data/ext/ffi_c/Call.h +0 -9
  15. data/ext/ffi_c/Closure.c +54 -0
  16. data/ext/ffi_c/{ClosurePool.h → Closure.h} +13 -23
  17. data/ext/ffi_c/Function.c +16 -25
  18. data/ext/ffi_c/Function.h +1 -2
  19. data/ext/ffi_c/FunctionInfo.c +0 -4
  20. data/ext/ffi_c/MethodHandle.c +33 -268
  21. data/ext/ffi_c/extconf.rb +3 -3
  22. data/ext/ffi_c/ffi.c +2 -2
  23. data/ext/ffi_c/libffi.bsd.mk +3 -3
  24. data/ext/ffi_c/libffi.darwin.mk +1 -1
  25. data/ext/ffi_c/libffi.gnu.mk +1 -1
  26. data/ext/ffi_c/libffi.mk +2 -2
  27. data/ext/ffi_c/libffi.vc.mk +1 -1
  28. data/ext/ffi_c/libffi.vc64.mk +1 -1
  29. data/ext/ffi_c/libffi/.appveyor.yml +48 -0
  30. data/ext/ffi_c/libffi/.gitignore +36 -0
  31. data/ext/ffi_c/libffi/.travis.yml +30 -0
  32. data/ext/ffi_c/libffi/.travis/install.sh +14 -0
  33. data/ext/ffi_c/libffi/Makefile.am +5 -3
  34. data/ext/ffi_c/libffi/acinclude.m4 +6 -0
  35. data/ext/ffi_c/libffi/autogen.sh +1 -1
  36. data/ext/ffi_c/libffi/config.guess +1466 -0
  37. data/ext/ffi_c/libffi/config.sub +1836 -0
  38. data/ext/ffi_c/libffi/configure.ac +2 -2
  39. data/ext/ffi_c/libffi/configure.host +15 -3
  40. data/ext/ffi_c/libffi/generate-darwin-source-and-headers.py +11 -15
  41. data/ext/ffi_c/libffi/include/ffi.h.in +6 -1
  42. data/ext/ffi_c/libffi/libffi.xcodeproj/project.pbxproj +465 -59
  43. data/ext/ffi_c/libffi/src/aarch64/ffi.c +33 -10
  44. data/ext/ffi_c/libffi/src/aarch64/sysv.S +2 -2
  45. data/ext/ffi_c/libffi/src/arm/ffi.c +12 -1
  46. data/ext/ffi_c/libffi/src/arm/sysv.S +1 -1
  47. data/ext/ffi_c/libffi/src/closures.c +143 -97
  48. data/ext/ffi_c/libffi/src/ia64/unix.S +2 -0
  49. data/ext/ffi_c/libffi/src/mips/ffi.c +8 -0
  50. data/ext/ffi_c/libffi/src/mips/ffitarget.h +1 -1
  51. data/ext/ffi_c/libffi/src/mips/n32.S +2 -0
  52. data/ext/ffi_c/libffi/src/powerpc/aix.S +239 -1
  53. data/ext/ffi_c/libffi/src/powerpc/aix_closure.S +250 -3
  54. data/ext/ffi_c/libffi/src/powerpc/ffi_darwin.c +86 -5
  55. data/ext/ffi_c/libffi/src/powerpc/ffitarget.h +3 -0
  56. data/ext/ffi_c/libffi/src/x86/ffi.c +3 -1
  57. data/ext/ffi_c/libffi/src/x86/ffi64.c +26 -5
  58. data/ext/ffi_c/libffi/src/x86/sysv.S +2 -2
  59. data/ext/ffi_c/libffi/src/x86/unix64.S +1 -1
  60. data/ext/ffi_c/libffi/src/x86/win64.S +1 -1
  61. data/ext/ffi_c/libffi/testsuite/Makefile.am +2 -1
  62. data/ext/ffi_c/libffi/testsuite/lib/libffi.exp +2 -1
  63. data/ext/ffi_c/libffi/testsuite/libffi.call/cls_3float.c +95 -0
  64. data/ffi.gemspec +14 -1
  65. data/lib/ffi/library.rb +1 -1
  66. data/lib/ffi/version.rb +1 -1
  67. data/samples/getlogin.rb +8 -0
  68. data/samples/getpid.rb +8 -0
  69. data/samples/gettimeofday.rb +18 -0
  70. data/samples/hello.rb +7 -0
  71. data/samples/inotify.rb +60 -0
  72. data/samples/pty.rb +76 -0
  73. data/samples/qsort.rb +21 -0
  74. data/samples/sample_helper.rb +6 -0
  75. metadata +59 -81
  76. metadata.gz.sig +0 -0
  77. data/ext/ffi_c/ClosurePool.c +0 -283
  78. data/gen/Rakefile +0 -30
  79. data/libtest/Benchmark.c +0 -52
  80. data/libtest/BoolTest.c +0 -34
  81. data/libtest/BufferTest.c +0 -31
  82. data/libtest/ClosureTest.c +0 -205
  83. data/libtest/EnumTest.c +0 -51
  84. data/libtest/FunctionTest.c +0 -70
  85. data/libtest/GNUmakefile +0 -149
  86. data/libtest/GlobalVariable.c +0 -62
  87. data/libtest/LastErrorTest.c +0 -21
  88. data/libtest/NumberTest.c +0 -132
  89. data/libtest/PointerTest.c +0 -63
  90. data/libtest/ReferenceTest.c +0 -23
  91. data/libtest/StringTest.c +0 -34
  92. data/libtest/StructTest.c +0 -243
  93. data/libtest/UnionTest.c +0 -43
  94. data/libtest/VariadicTest.c +0 -99
  95. data/spec/ffi/async_callback_spec.rb +0 -35
  96. data/spec/ffi/bitmask_spec.rb +0 -575
  97. data/spec/ffi/bool_spec.rb +0 -32
  98. data/spec/ffi/buffer_spec.rb +0 -279
  99. data/spec/ffi/callback_spec.rb +0 -773
  100. data/spec/ffi/custom_param_type.rb +0 -37
  101. data/spec/ffi/custom_type_spec.rb +0 -74
  102. data/spec/ffi/dup_spec.rb +0 -52
  103. data/spec/ffi/enum_spec.rb +0 -423
  104. data/spec/ffi/errno_spec.rb +0 -20
  105. data/spec/ffi/ffi_spec.rb +0 -28
  106. data/spec/ffi/fixtures/Benchmark.c +0 -52
  107. data/spec/ffi/fixtures/BitmaskTest.c +0 -51
  108. data/spec/ffi/fixtures/BoolTest.c +0 -34
  109. data/spec/ffi/fixtures/BufferTest.c +0 -31
  110. data/spec/ffi/fixtures/ClosureTest.c +0 -205
  111. data/spec/ffi/fixtures/EnumTest.c +0 -51
  112. data/spec/ffi/fixtures/FunctionTest.c +0 -142
  113. data/spec/ffi/fixtures/GNUmakefile +0 -149
  114. data/spec/ffi/fixtures/GlobalVariable.c +0 -62
  115. data/spec/ffi/fixtures/LastErrorTest.c +0 -21
  116. data/spec/ffi/fixtures/NumberTest.c +0 -132
  117. data/spec/ffi/fixtures/PipeHelper.h +0 -21
  118. data/spec/ffi/fixtures/PipeHelperPosix.c +0 -41
  119. data/spec/ffi/fixtures/PipeHelperWindows.c +0 -72
  120. data/spec/ffi/fixtures/PointerTest.c +0 -63
  121. data/spec/ffi/fixtures/ReferenceTest.c +0 -23
  122. data/spec/ffi/fixtures/StringTest.c +0 -34
  123. data/spec/ffi/fixtures/StructTest.c +0 -243
  124. data/spec/ffi/fixtures/UnionTest.c +0 -43
  125. data/spec/ffi/fixtures/VariadicTest.c +0 -99
  126. data/spec/ffi/fixtures/classes.rb +0 -438
  127. data/spec/ffi/function_spec.rb +0 -97
  128. data/spec/ffi/io_spec.rb +0 -16
  129. data/spec/ffi/library_spec.rb +0 -286
  130. data/spec/ffi/long_double.rb +0 -30
  131. data/spec/ffi/managed_struct_spec.rb +0 -68
  132. data/spec/ffi/memorypointer_spec.rb +0 -78
  133. data/spec/ffi/number_spec.rb +0 -247
  134. data/spec/ffi/platform_spec.rb +0 -114
  135. data/spec/ffi/pointer_spec.rb +0 -285
  136. data/spec/ffi/rbx/attach_function_spec.rb +0 -34
  137. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -198
  138. data/spec/ffi/rbx/spec_helper.rb +0 -6
  139. data/spec/ffi/rbx/struct_spec.rb +0 -18
  140. data/spec/ffi/spec_helper.rb +0 -93
  141. data/spec/ffi/string_spec.rb +0 -118
  142. data/spec/ffi/strptr_spec.rb +0 -50
  143. data/spec/ffi/struct_by_ref_spec.rb +0 -43
  144. data/spec/ffi/struct_callback_spec.rb +0 -69
  145. data/spec/ffi/struct_initialize_spec.rb +0 -35
  146. data/spec/ffi/struct_packed_spec.rb +0 -50
  147. data/spec/ffi/struct_spec.rb +0 -882
  148. data/spec/ffi/typedef_spec.rb +0 -91
  149. data/spec/ffi/union_spec.rb +0 -67
  150. data/spec/ffi/variadic_spec.rb +0 -132
  151. data/spec/spec.opts +0 -4
@@ -1,50 +0,0 @@
1
- #
2
- # This file is part of ruby-ffi.
3
- # For licensing, see LICENSE.SPECS
4
- #
5
-
6
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
-
8
- describe "functions returning :strptr" do
9
-
10
- it "can attach function with :strptr return type" do
11
- expect do
12
- Module.new do
13
- extend FFI::Library
14
- ffi_lib FFI::Library::LIBC
15
- if !FFI::Platform.windows?
16
- attach_function :strdup, [ :string ], :strptr
17
- else
18
- attach_function :_strdup, [ :string ], :strptr
19
- end
20
- end
21
- end.not_to raise_error
22
- end
23
-
24
- module StrPtr
25
- extend FFI::Library
26
- ffi_lib FFI::Library::LIBC
27
- attach_function :free, [ :pointer ], :void
28
- if !FFI::Platform.windows?
29
- attach_function :strdup, [ :string ], :strptr
30
- else
31
- attach_function :strdup, :_strdup, [ :string ], :strptr
32
- end
33
- end
34
-
35
- it "should return [ String, Pointer ]" do
36
- result = StrPtr.strdup("test")
37
- expect(result[0].is_a?(String)).to be true
38
- expect(result[1].is_a?(FFI::Pointer)).to be true
39
- end
40
-
41
- it "should return the correct value" do
42
- result = StrPtr.strdup("test")
43
- expect(result[0]).to eq("test")
44
- end
45
-
46
- it "should return non-NULL pointer" do
47
- result = StrPtr.strdup("test")
48
- expect(result[1]).not_to be_null
49
- end
50
- end
@@ -1,43 +0,0 @@
1
- #
2
- # This file is part of ruby-ffi.
3
- # For licensing, see LICENSE.SPECS
4
- #
5
-
6
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
-
8
- describe FFI::Struct, ' by_ref' do
9
- before :all do
10
- @struct_class = struct_class = Class.new(FFI::Struct) do
11
- layout :a, :pointer
12
- end
13
-
14
- @api = Module.new do
15
- extend FFI::Library
16
- ffi_lib TestLibrary::PATH
17
- fn = FFI::Type::POINTER.size == FFI::Type::LONG.size ? :ret_ulong : :ret_u64
18
- attach_function :struct_test, fn, [ struct_class.by_ref ], :pointer
19
- end
20
- end
21
-
22
- it "should accept instances of exact struct class" do
23
- s = @struct_class.new
24
- expect(@api.struct_test(s)).to eq(s.pointer)
25
- end
26
-
27
- it "should accept nil" do
28
- expect(@api.struct_test(nil)).to be_null
29
- end
30
-
31
- it "should reject other types" do
32
- expect { expect(@api.struct_test('test')).to be_nil }.to raise_error(TypeError)
33
- end
34
-
35
- it "should reject instances of other struct classes" do
36
- other_class = Class.new(FFI::Struct) do
37
- layout :a, :pointer
38
- end
39
-
40
- expect { @api.struct_test(other_class.new) }.to raise_error(TypeError)
41
- end
42
- end
43
-
@@ -1,69 +0,0 @@
1
- #
2
- # This file is part of ruby-ffi.
3
- # For licensing, see LICENSE.SPECS
4
- #
5
-
6
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
-
8
- describe FFI::Struct, ' with inline callback functions' do
9
- it 'should be able to define inline callback field' do
10
- expect(module CallbackMember1
11
- extend FFI::Library
12
- ffi_lib TestLibrary::PATH
13
- DUMMY_CB = callback :dummy_cb, [ :int ], :int
14
- class TestStruct < FFI::Struct
15
- layout \
16
- :add, callback([ :int, :int ], :int),
17
- :sub, callback([ :int, :int ], :int),
18
- :cb_with_cb_parameter, callback([ DUMMY_CB, :int ], :int)
19
- end
20
- attach_function :struct_call_add_cb, [TestStruct, :int, :int], :int
21
- attach_function :struct_call_sub_cb, [TestStruct, :int, :int], :int
22
- end).to be_an_instance_of FFI::Function
23
- end
24
-
25
- it 'should take methods as callbacks' do
26
- module CallbackMember2
27
- extend FFI::Library
28
- ffi_lib TestLibrary::PATH
29
- class TestStruct < FFI::Struct
30
- layout \
31
- :add, callback([ :int, :int ], :int),
32
- :sub, callback([ :int, :int ], :int)
33
- end
34
- attach_function :struct_call_add_cb, [TestStruct, :int, :int], :int
35
- attach_function :struct_call_sub_cb, [TestStruct, :int, :int], :int
36
- end
37
- module StructCallbacks
38
- def self.add a, b
39
- a+b
40
- end
41
- end
42
-
43
- ts = CallbackMember2::TestStruct.new
44
- ts[:add] = StructCallbacks.method(:add)
45
-
46
- expect(CallbackMember2.struct_call_add_cb(ts, 1, 2)).to eq(3)
47
- end
48
-
49
- it 'should return callable object from []' do
50
- module CallbackMember3
51
- extend FFI::Library
52
- ffi_lib TestLibrary::PATH
53
- class TestStruct < FFI::Struct
54
- layout \
55
- :add, callback([ :int, :int ], :int),
56
- :sub, callback([ :int, :int ], :int)
57
- end
58
- attach_function :struct_call_add_cb, [TestStruct, :int, :int], :int
59
- attach_function :struct_call_sub_cb, [TestStruct, :int, :int], :int
60
- end
61
-
62
- s = CallbackMember3::TestStruct.new
63
- add = Proc.new { |a,b| a+b}
64
- s[:add] = add
65
- fn = s[:add]
66
- expect(fn.respond_to?(:call)).to be true
67
- expect(fn.call(1, 2)).to eq(3)
68
- end
69
- end
@@ -1,35 +0,0 @@
1
- #
2
- # This file is part of ruby-ffi.
3
- # For licensing, see LICENSE.SPECS
4
- #
5
-
6
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
-
8
- describe FFI::Struct, ' with an initialize function' do
9
- it "should call the initialize function" do
10
- class StructWithInitialize < FFI::Struct
11
- layout :string, :string
12
- attr_accessor :magic
13
- def initialize
14
- super
15
- self.magic = 42
16
- end
17
- end
18
- expect(StructWithInitialize.new.magic).to eq(42)
19
- end
20
- end
21
-
22
- describe FFI::ManagedStruct, ' with an initialize function' do
23
- it "should call the initialize function" do
24
- class ManagedStructWithInitialize < FFI::ManagedStruct
25
- layout :string, :string
26
- attr_accessor :magic
27
- def initialize
28
- super FFI::MemoryPointer.new(:pointer).put_int(0, 0x1234).get_pointer(0)
29
- self.magic = 42
30
- end
31
- def self.release;end
32
- end
33
- expect(ManagedStructWithInitialize.new.magic).to eq(42)
34
- end
35
- end
@@ -1,50 +0,0 @@
1
- #
2
- # This file is part of ruby-ffi.
3
- # For licensing, see LICENSE.SPECS
4
- #
5
-
6
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
-
8
- describe FFI::Struct do
9
- it "packed :char followed by :int should have size of 5" do
10
- expect(Class.new(FFI::Struct) do
11
- packed
12
- layout :c, :char, :i, :int
13
- end.size).to eq(5)
14
- end
15
-
16
- it "packed :char followed by :int should have alignment of 1" do
17
- expect(Class.new(FFI::Struct) do
18
- packed
19
- layout :c, :char, :i, :int
20
- end.alignment).to eq(1)
21
- end
22
-
23
- it "packed(2) :char followed by :int should have size of 6" do
24
- expect(Class.new(FFI::Struct) do
25
- packed 2
26
- layout :c, :char, :i, :int
27
- end.size).to eq(6)
28
- end
29
-
30
- it "packed(2) :char followed by :int should have alignment of 2" do
31
- expect(Class.new(FFI::Struct) do
32
- packed 2
33
- layout :c, :char, :i, :int
34
- end.alignment).to eq(2)
35
- end
36
-
37
- it "packed :short followed by int should have size of 6" do
38
- expect(Class.new(FFI::Struct) do
39
- packed
40
- layout :s, :short, :i, :int
41
- end.size).to eq(6)
42
- end
43
-
44
- it "packed :short followed by int should have alignment of 1" do
45
- expect(Class.new(FFI::Struct) do
46
- packed
47
- layout :s, :short, :i, :int
48
- end.alignment).to eq(1)
49
- end
50
- end
@@ -1,882 +0,0 @@
1
- #
2
- # This file is part of ruby-ffi.
3
- # For licensing, see LICENSE.SPECS
4
- #
5
-
6
- require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
7
-
8
- describe "Struct aligns fields correctly" do
9
- it "char, followed by an int" do
10
- class CIStruct < FFI::Struct
11
- layout :c => :char, :i => :int
12
- end
13
- expect(CIStruct.size).to eq(8)
14
- end
15
-
16
- it "short, followed by an int" do
17
- class SIStruct < FFI::Struct
18
- layout :s => :short, :i => :int
19
- end
20
- expect(SIStruct.size).to eq(8)
21
- end
22
-
23
- it "int, followed by an int" do
24
- class IIStruct < FFI::Struct
25
- layout :i1 => :int, :i => :int
26
- end
27
- expect(IIStruct.size).to eq(8)
28
- end
29
-
30
- it "long long, followed by an int" do
31
- class LLIStruct < FFI::Struct
32
- layout :l => :long_long, :i => :int
33
- end
34
- expect(LLIStruct.size).to eq(FFI::TYPE_UINT64.alignment == 4 ? 12 : 16)
35
- end
36
- end
37
-
38
- describe "Struct tests" do
39
- StructTypes = {
40
- 's8' => :char,
41
- 's16' => :short,
42
- 's32' => :int,
43
- 's64' => :long_long,
44
- 'long' => :long,
45
- 'f32' => :float,
46
- 'f64' => :double
47
- }
48
- module LibTest
49
- extend FFI::Library
50
- ffi_lib TestLibrary::PATH
51
- attach_function :ptr_ret_pointer, [ :pointer, :int], :string
52
- begin
53
- attach_function :ptr_ret_int32_t, [ :pointer, :int ], :int
54
- rescue FFI::NotFoundError
55
- # NetBSD uses #define instead of typedef for these
56
- attach_function :ptr_ret_int32_t, :ptr_ret___int32_t, [ :pointer, :int ], :int
57
- end
58
- attach_function :ptr_from_address, [ :ulong ], :pointer
59
- attach_function :string_equals, [ :string, :string ], :int
60
- [ 's8', 's16', 's32', 's64', 'f32', 'f64', 'long' ].each do |t|
61
- attach_function "struct_align_#{t}", [ :pointer ], StructTypes[t]
62
- end
63
- end
64
- class PointerMember < FFI::Struct
65
- layout :pointer, :pointer
66
- end
67
- class StringMember < FFI::Struct
68
- layout :string, :string
69
- end
70
-
71
- it "Struct#[:pointer]" do
72
- magic = 0x12345678
73
- mp = FFI::MemoryPointer.new :long
74
- mp.put_long(0, magic)
75
- smp = FFI::MemoryPointer.new :pointer
76
- smp.put_pointer(0, mp)
77
- s = PointerMember.new smp
78
- expect(s[:pointer]).to eq(mp)
79
- end
80
-
81
- it "Struct#[:pointer].nil? for NULL value" do
82
- magic = 0x12345678
83
- mp = FFI::MemoryPointer.new :long
84
- mp.put_long(0, magic)
85
- smp = FFI::MemoryPointer.new :pointer
86
- smp.put_pointer(0, nil)
87
- s = PointerMember.new smp
88
- expect(s[:pointer].null?).to be true
89
- end
90
-
91
- it "Struct#[:pointer]=" do
92
- magic = 0x12345678
93
- mp = FFI::MemoryPointer.new :long
94
- mp.put_long(0, magic)
95
- smp = FFI::MemoryPointer.new :pointer
96
- s = PointerMember.new smp
97
- s[:pointer] = mp
98
- expect(smp.get_pointer(0)).to eq(mp)
99
- end
100
-
101
- it "Struct#[:pointer]=struct" do
102
- smp = FFI::MemoryPointer.new :pointer
103
- s = PointerMember.new smp
104
- expect { s[:pointer] = s }.not_to raise_error Exception
105
- expect { s[:pointer].nil? }.not_to raise_error Exception
106
- end
107
-
108
- it "Struct#[:pointer]=nil" do
109
- smp = FFI::MemoryPointer.new :pointer
110
- s = PointerMember.new smp
111
- s[:pointer] = nil
112
- expect(smp.get_pointer(0)).to be_null
113
- end
114
-
115
- it "Struct#[:string]" do
116
- magic = "test"
117
- mp = FFI::MemoryPointer.new 1024
118
- mp.put_string(0, magic)
119
- smp = FFI::MemoryPointer.new :pointer
120
- smp.put_pointer(0, mp)
121
- s = StringMember.new smp
122
- expect(s[:string]).to eq(magic)
123
- end
124
-
125
- it "Struct#[:string].nil? for NULL value" do
126
- smp = FFI::MemoryPointer.new :pointer
127
- smp.put_pointer(0, nil)
128
- s = StringMember.new smp
129
- expect(s[:string]).to be_nil
130
- end
131
-
132
- it "Struct#layout works with :name, :type pairs" do
133
- class PairLayout < FFI::Struct
134
- layout :a, :int, :b, :long_long
135
- end
136
- ll_off = (FFI::TYPE_UINT64.alignment == 4 ? 4 : 8)
137
- expect(PairLayout.size).to eq((ll_off + 8))
138
- mp = FFI::MemoryPointer.new(PairLayout.size)
139
- s = PairLayout.new mp
140
- s[:a] = 0x12345678
141
- expect(mp.get_int(0)).to eq(0x12345678)
142
- s[:b] = 0xfee1deadbeef
143
- expect(mp.get_int64(ll_off)).to eq(0xfee1deadbeef)
144
- end
145
-
146
- it "Struct#layout works with :name, :type, offset tuples" do
147
- class PairLayout < FFI::Struct
148
- layout :a, :int, 0, :b, :long_long, 4
149
- end
150
- expect(PairLayout.size).to eq((FFI::TYPE_UINT64.alignment == 4 ? 12 : 16))
151
- mp = FFI::MemoryPointer.new(PairLayout.size)
152
- s = PairLayout.new mp
153
- s[:a] = 0x12345678
154
- expect(mp.get_int(0)).to eq(0x12345678)
155
- s[:b] = 0xfee1deadbeef
156
- expect(mp.get_int64(4)).to eq(0xfee1deadbeef)
157
- end
158
-
159
- it "Struct#layout works with mixed :name,:type and :name,:type,offset" do
160
- class MixedLayout < FFI::Struct
161
- layout :a, :int, :b, :long_long, 4
162
- end
163
- expect(MixedLayout.size).to eq((FFI::TYPE_UINT64.alignment == 4 ? 12 : 16))
164
- mp = FFI::MemoryPointer.new(MixedLayout.size)
165
- s = MixedLayout.new mp
166
- s[:a] = 0x12345678
167
- expect(mp.get_int(0)).to eq(0x12345678)
168
- s[:b] = 0xfee1deadbeef
169
- expect(mp.get_int64(4)).to eq(0xfee1deadbeef)
170
- end
171
-
172
- rb_maj, rb_min = RUBY_VERSION.split('.')
173
- if rb_maj.to_i >= 1 && rb_min.to_i >= 9 || RUBY_PLATFORM =~ /java/
174
- it "Struct#layout withs with a hash of :name => type" do
175
- class HashLayout < FFI::Struct
176
- layout :a => :int, :b => :long_long
177
- end
178
- ll_off = (FFI::TYPE_UINT64.alignment == 4 ? 4 : 8)
179
- expect(HashLayout.size).to eq(ll_off + 8)
180
- mp = FFI::MemoryPointer.new(HashLayout.size)
181
- s = HashLayout.new mp
182
- s[:a] = 0x12345678
183
- expect(mp.get_int(0)).to eq(0x12345678)
184
- s[:b] = 0xfee1deadbeef
185
- expect(mp.get_int64(ll_off)).to eq(0xfee1deadbeef)
186
- end
187
- end
188
-
189
- it "subclass overrides initialize without calling super" do
190
- class InitializeWithoutSuper < FFI::Struct
191
- layout :a, :int, :b, :long_long, :d, [:double, 2]
192
-
193
- def initialize(a, b)
194
- self[:a] = a
195
- self[:b] = b
196
- self[:d][0] = 1.2
197
- self[:d][1] = 3.4
198
- end
199
-
200
- end
201
- s = InitializeWithoutSuper.new(0x1eefbeef, 0xdeadcafebabe)
202
- expect(s[:a]).to eq(0x1eefbeef)
203
- expect(s[:b]).to eq(0xdeadcafebabe)
204
- end
205
-
206
- it "Can use Struct subclass as parameter type" do
207
- expect(module StructParam
208
- extend FFI::Library
209
- ffi_lib TestLibrary::PATH
210
- class TestStruct < FFI::Struct
211
- layout :c, :char
212
- end
213
- attach_function :struct_field_s8, [ TestStruct.in ], :char
214
- end).to be_an_instance_of FFI::Function
215
- end
216
-
217
- it "Can use Struct subclass as IN parameter type" do
218
- expect(module StructParam2
219
- extend FFI::Library
220
- ffi_lib TestLibrary::PATH
221
- class TestStruct < FFI::Struct
222
- layout :c, :char
223
- end
224
- attach_function :struct_field_s8, [ TestStruct.in ], :char
225
- end).to be_an_instance_of FFI::Function
226
- end
227
-
228
- it "Can use Struct subclass as OUT parameter type" do
229
- expect(module StructParam3
230
- extend FFI::Library
231
- ffi_lib TestLibrary::PATH
232
- class TestStruct < FFI::Struct
233
- layout :c, :char
234
- end
235
- attach_function :struct_field_s8, [ TestStruct.out ], :char
236
- end).to be_an_instance_of FFI::Function
237
- end
238
-
239
- it "can be passed directly as a :pointer parameter" do
240
- class TestStruct < FFI::Struct
241
- layout :i, :int
242
- end
243
- s = TestStruct.new
244
- s[:i] = 0x12
245
- expect(LibTest.ptr_ret_int32_t(s, 0)).to eq(0x12)
246
- end
247
-
248
- it ":char member aligned correctly" do
249
- class AlignChar < FFI::Struct
250
- layout :c, :char, :v, :char
251
- end
252
- s = AlignChar.new
253
- s[:v] = 0x12
254
- expect(LibTest.struct_align_s8(s.pointer)).to eq(0x12)
255
- end
256
-
257
- it ":short member aligned correctly" do
258
- class AlignShort < FFI::Struct
259
- layout :c, :char, :v, :short
260
- end
261
- s = AlignShort.alloc_in
262
- s[:v] = 0x1234
263
- expect(LibTest.struct_align_s16(s.pointer)).to eq(0x1234)
264
- end
265
-
266
- it ":int member aligned correctly" do
267
- class AlignInt < FFI::Struct
268
- layout :c, :char, :v, :int
269
- end
270
- s = AlignInt.alloc_in
271
- s[:v] = 0x12345678
272
- expect(LibTest.struct_align_s32(s.pointer)).to eq(0x12345678)
273
- end
274
-
275
- it ":long_long member aligned correctly" do
276
- class AlignLongLong < FFI::Struct
277
- layout :c, :char, :v, :long_long
278
- end
279
- s = AlignLongLong.alloc_in
280
- s[:v] = 0x123456789abcdef0
281
- expect(LibTest.struct_align_s64(s.pointer)).to eq(0x123456789abcdef0)
282
- end
283
-
284
- it ":long member aligned correctly" do
285
- class AlignLong < FFI::Struct
286
- layout :c, :char, :v, :long
287
- end
288
- s = AlignLong.alloc_in
289
- s[:v] = 0x12345678
290
- expect(LibTest.struct_align_long(s.pointer)).to eq(0x12345678)
291
- end
292
-
293
- it ":float member aligned correctly" do
294
- class AlignFloat < FFI::Struct
295
- layout :c, :char, :v, :float
296
- end
297
- s = AlignFloat.alloc_in
298
- s[:v] = 1.23456
299
- expect((LibTest.struct_align_f32(s.pointer) - 1.23456).abs).to be < 0.00001
300
- end
301
-
302
- it ":double member aligned correctly" do
303
- class AlignDouble < FFI::Struct
304
- layout :c, :char, :v, :double
305
- end
306
- s = AlignDouble.alloc_in
307
- s[:v] = 1.23456789
308
- expect((LibTest.struct_align_f64(s.pointer) - 1.23456789).abs).to be < 0.00000001
309
- end
310
-
311
- it ":ulong, :pointer struct" do
312
- class ULPStruct < FFI::Struct
313
- layout :ul, :ulong, :p, :pointer
314
- end
315
- s = ULPStruct.alloc_in
316
- s[:ul] = 0xdeadbeef
317
- s[:p] = LibTest.ptr_from_address(0x12345678)
318
- expect(s.pointer.get_ulong(0)).to eq(0xdeadbeef)
319
- end
320
- def test_num_field(type, v)
321
- klass = Class.new(FFI::Struct)
322
- klass.layout :v, type, :dummy, :long
323
-
324
- s = klass.new
325
- s[:v] = v
326
- expect(s.pointer.send("get_#{type.to_s}", 0)).to eq(v)
327
- s.pointer.send("put_#{type.to_s}", 0, 0)
328
- expect(s[:v]).to eq(0)
329
- end
330
- def self.int_field_test(type, values)
331
- values.each do |v|
332
- it "#{type} field r/w (#{v.to_s(16)})" do
333
- test_num_field(type, v)
334
- end
335
- end
336
- end
337
- int_field_test(:char, [ 0, 127, -128, -1 ])
338
- int_field_test(:uchar, [ 0, 0x7f, 0x80, 0xff ])
339
- int_field_test(:short, [ 0, 0x7fff, -0x8000, -1 ])
340
- int_field_test(:ushort, [ 0, 0x7fff, 0x8000, 0xffff ])
341
- int_field_test(:int, [ 0, 0x7fffffff, -0x80000000, -1 ])
342
- int_field_test(:uint, [ 0, 0x7fffffff, 0x80000000, 0xffffffff ])
343
- int_field_test(:long_long, [ 0, 0x7fffffffffffffff, -0x8000000000000000, -1 ])
344
- int_field_test(:ulong_long, [ 0, 0x7fffffffffffffff, 0x8000000000000000, 0xffffffffffffffff ])
345
- if FFI::Platform::LONG_SIZE == 32
346
- int_field_test(:long, [ 0, 0x7fffffff, -0x80000000, -1 ])
347
- int_field_test(:ulong, [ 0, 0x7fffffff, 0x80000000, 0xffffffff ])
348
- else
349
- int_field_test(:long, [ 0, 0x7fffffffffffffff, -0x8000000000000000, -1 ])
350
- int_field_test(:ulong, [ 0, 0x7fffffffffffffff, 0x8000000000000000, 0xffffffffffffffff ])
351
- end
352
-
353
- it ":float field r/w" do
354
- klass = Class.new(FFI::Struct)
355
- klass.layout :v, :float, :dummy, :long
356
-
357
- s = klass.new
358
- value = 1.23456
359
- s[:v] = value
360
- expect((s.pointer.get_float(0) - value).abs).to be < 0.0001
361
- end
362
-
363
- it ":double field r/w" do
364
- klass = Class.new(FFI::Struct)
365
- klass.layout :v, :double, :dummy, :long
366
-
367
- s = klass.new
368
- value = 1.23456
369
- s[:v] = value
370
- expect((s.pointer.get_double(0) - value).abs).to be < 0.0001
371
- end
372
- module EnumFields
373
- extend FFI::Library
374
- TestEnum = enum :test_enum, [:c1, 10, :c2, 20, :c3, 30, :c4, 40]
375
- class TestStruct < FFI::Struct
376
- layout :a, :int, :c, :test_enum,
377
- :d, [ TestEnum, TestEnum.symbols.length ]
378
- end
379
- end
380
-
381
- it ":enum field r/w" do
382
- s = EnumFields::TestStruct.new
383
- s[:c] = :c3
384
-
385
- expect(s.pointer.get_uint(FFI::Type::INT32.size)).to eq(30)
386
- expect(s[:c]).to eq(:c3)
387
- end
388
-
389
- it "array of :enum field" do
390
- s = EnumFields::TestStruct.new
391
- EnumFields::TestEnum.symbols.each_with_index do |val, i|
392
- s[:d][i] = val
393
- end
394
-
395
- EnumFields::TestEnum.symbols.each_with_index do |val, i|
396
- expect(s.pointer.get_uint(FFI::Type::INT32.size * (2 + i))).to eq(EnumFields::TestEnum[val])
397
- end
398
-
399
- s[:d].each_with_index do |val, i|
400
- expect(val).to eq(EnumFields::TestEnum.symbols[i])
401
- end
402
- end
403
-
404
- module CallbackMember
405
- extend FFI::Library
406
- ffi_lib TestLibrary::PATH
407
- callback :add, [ :int, :int ], :int
408
- callback :sub, [ :int, :int ], :int
409
- class TestStruct < FFI::Struct
410
- layout :add, :add,
411
- :sub, :sub
412
- end
413
- attach_function :struct_call_add_cb, [TestStruct.in, :int, :int], :int
414
- attach_function :struct_call_sub_cb, [TestStruct.in, :int, :int], :int
415
- end
416
-
417
- it "Can have CallbackInfo struct field" do
418
- s = CallbackMember::TestStruct.new
419
- add_proc = lambda { |a, b| a+b }
420
- sub_proc = lambda { |a, b| a-b }
421
- s[:add] = add_proc
422
- s[:sub] = sub_proc
423
- expect(CallbackMember.struct_call_add_cb(s, 40, 2)).to eq(42)
424
- expect(CallbackMember.struct_call_sub_cb(s, 44, 2)).to eq(42)
425
- end
426
-
427
- it "Can return its members as a list" do
428
- class TestStruct < FFI::Struct
429
- layout :a, :int, :b, :int, :c, :int
430
- end
431
- expect(TestStruct.members).to include(:a, :b, :c)
432
- end
433
-
434
- it "Can return its instance members and values as lists" do
435
- class TestStruct < FFI::Struct
436
- layout :a, :int, :b, :int, :c, :int
437
- end
438
- s = TestStruct.new
439
- expect(s.members).to include(:a, :b, :c)
440
- s[:a] = 1
441
- s[:b] = 2
442
- s[:c] = 3
443
- expect(s.values).to include(1, 2, 3)
444
- end
445
-
446
- it 'should return an ordered field/offset pairs array' do
447
- class TestStruct < FFI::Struct
448
- layout :a, :int, :b, :int, :c, :int
449
- end
450
- s = TestStruct.new
451
- expect(s.offsets).to eq([[:a, 0], [:b, 4], [:c, 8]])
452
- expect(TestStruct.offsets).to eq([[:a, 0], [:b, 4], [:c, 8]])
453
- end
454
-
455
- it "Struct#offset_of returns offset of field within struct" do
456
- class TestStruct < FFI::Struct
457
- layout :a, :int, :b, :int, :c, :int
458
- end
459
- expect(TestStruct.offset_of(:a)).to eq(0)
460
- expect(TestStruct.offset_of(:b)).to eq(4)
461
- expect(TestStruct.offset_of(:c)).to eq(8)
462
- end
463
- end
464
-
465
- describe FFI::Struct, ".layout" do
466
- module FFISpecs
467
- module LibTest
468
- extend FFI::Library
469
- ffi_lib TestLibrary::PATH
470
- begin
471
- attach_function :ptr_ret_int32_t, [ :pointer, :int ], :int
472
- rescue FFI::NotFoundError
473
- # NetBSD uses #define instead of typedef for these
474
- attach_function :ptr_ret_int32_t, :ptr_ret___int32_t, [ :pointer, :int ], :int
475
- end
476
- end
477
- end
478
-
479
- describe "when derived class is not assigned to any constant" do
480
- it "resolves a built-in type" do
481
- klass = Class.new FFI::Struct
482
- klass.layout :number, :int
483
-
484
- instance = klass.new
485
- instance[:number] = 0xA1
486
- expect(FFISpecs::LibTest.ptr_ret_int32_t(instance, 0)).to eq(0xA1)
487
- end
488
- end
489
-
490
- describe "when derived class is assigned to a constant" do
491
- it "resolves a built-in type" do
492
- class FFISpecs::TestStruct < FFI::Struct
493
- layout :number, :int
494
- end
495
-
496
- instance = FFISpecs::TestStruct.new
497
- instance[:number] = 0xA1
498
- expect(FFISpecs::LibTest.ptr_ret_int32_t(instance, 0)).to eq(0xA1)
499
- end
500
-
501
- it "resolves a type from the enclosing module" do
502
- module FFISpecs::LibTest
503
- typedef :uint, :custom_int
504
-
505
- class TestStruct < FFI::Struct
506
- layout :number, :custom_int
507
- end
508
- end
509
-
510
- instance = FFISpecs::LibTest::TestStruct.new
511
- instance[:number] = 0xA1
512
- expect(FFISpecs::LibTest.ptr_ret_int32_t(instance, 0)).to eq(0xA1)
513
- end
514
- end
515
- end
516
-
517
- describe FFI::Struct, ' with a nested struct field' do
518
- module LibTest
519
- extend FFI::Library
520
- ffi_lib TestLibrary::PATH
521
- class NestedStruct < FFI::Struct
522
- layout :i, :int
523
- end
524
- class ContainerStruct < FFI::Struct
525
- layout :first, :char, :ns, NestedStruct
526
- end
527
- attach_function :struct_align_nested_struct, [ :pointer ], :int
528
- attach_function :struct_make_container_struct, [ :int ], :pointer
529
- end
530
- before do
531
- @cs = LibTest::ContainerStruct.new
532
- end
533
-
534
- it 'should align correctly nested struct field' do
535
- @cs[:ns][:i] = 123
536
- expect(LibTest.struct_align_nested_struct(@cs.to_ptr)).to eq(123)
537
- end
538
-
539
- it 'should correctly calculate Container size (in bytes)' do
540
- expect(LibTest::ContainerStruct.size).to eq(8)
541
- end
542
-
543
- it 'should return a Struct object when the field is accessed' do
544
- expect(@cs[:ns].is_a?(FFI::Struct)).to be true
545
- end
546
-
547
- it 'should read a value from memory' do
548
- @cs = LibTest::ContainerStruct.new(LibTest.struct_make_container_struct(123))
549
- expect(@cs[:ns][:i]).to eq(123)
550
- end
551
-
552
- it 'should write a value to memory' do
553
- @cs = LibTest::ContainerStruct.new(LibTest.struct_make_container_struct(123))
554
- @cs[:ns][:i] = 456
555
- expect(LibTest.struct_align_nested_struct(@cs.to_ptr)).to eq(456)
556
- end
557
-
558
- it 'should be able to assign struct instance to nested field' do
559
- cs = LibTest::ContainerStruct.new(LibTest.struct_make_container_struct(123))
560
- ns = LibTest::NestedStruct.new
561
- ns[:i] = 567
562
- cs[:ns] = ns
563
- expect(cs[:ns][:i]).to eq(567)
564
- expect(LibTest.struct_align_nested_struct(cs.to_ptr)).to eq(567)
565
- end
566
- end
567
-
568
- describe FFI::Struct, ' with a nested array of structs' do
569
- module InlineArrayOfStructs
570
- extend FFI::Library
571
- ffi_lib TestLibrary::PATH
572
- class NestedStruct < FFI::Struct
573
- layout :i, :int
574
- end
575
- class ContainerStruct < FFI::Struct
576
- layout :first, :char, :ns, [ NestedStruct, 1 ]
577
- end
578
- attach_function :struct_align_nested_struct, [ :pointer ], :int
579
- attach_function :struct_make_container_struct, [ :int ], :pointer
580
- end
581
-
582
- before do
583
- @cs = InlineArrayOfStructs::ContainerStruct.new
584
- end
585
-
586
- it 'should align correctly nested struct field' do
587
- @cs[:ns][0][:i] = 123
588
- expect(InlineArrayOfStructs.struct_align_nested_struct(@cs.to_ptr)).to eq(123)
589
- end
590
-
591
- it 'should correctly calculate Container size (in bytes)' do
592
- expect(InlineArrayOfStructs::ContainerStruct.size).to eq(8)
593
- end
594
-
595
- it 'should return a Struct object when the field is accessed' do
596
- expect(@cs[:ns][0].is_a?(FFI::Struct)).to be true
597
- end
598
-
599
- it 'should read a value from memory' do
600
- @cs = InlineArrayOfStructs::ContainerStruct.new(InlineArrayOfStructs.struct_make_container_struct(123))
601
- expect(@cs[:ns][0][:i]).to eq(123)
602
- end
603
-
604
- it 'should write a value to memory' do
605
- @cs = InlineArrayOfStructs::ContainerStruct.new(InlineArrayOfStructs.struct_make_container_struct(123))
606
- @cs[:ns][0][:i] = 456
607
- expect(InlineArrayOfStructs.struct_align_nested_struct(@cs.to_ptr)).to eq(456)
608
- end
609
-
610
- it 'should support Enumerable#each' do
611
- @cs = InlineArrayOfStructs::ContainerStruct.new(InlineArrayOfStructs.struct_make_container_struct(123))
612
- ints = []
613
- @cs[:ns].each { |s| ints << s[:i] }
614
- expect(ints[0]).to eq(123)
615
- end
616
- end
617
-
618
- describe FFI::Struct, ' by value' do
619
- module LibTest
620
- extend FFI::Library
621
- ffi_lib TestLibrary::PATH
622
-
623
- class S8S32 < FFI::Struct
624
- layout :s8, :char, :s32, :int
625
- end
626
-
627
- class StructString < FFI::Struct
628
- layout :bytes, :string, :len, :int
629
- end
630
-
631
- attach_function :struct_return_s8s32, [ ], S8S32.by_value
632
- attach_function :struct_s8s32_set, [ :char, :int ], S8S32.by_value
633
- attach_function :struct_s8s32_get_s8, [ S8S32.by_value ], :char
634
- attach_function :struct_s8s32_get_s32, [ S8S32.by_value ], :int
635
- attach_function :struct_s8s32_s32_ret_s32, [ S8S32.by_value, :int ], :int
636
- attach_function :struct_s8s32_s64_ret_s64, [ S8S32.by_value, :long_long ], :long_long
637
- attach_function :struct_s8s32_ret_s8s32, [ S8S32.by_value ], S8S32.by_value
638
- attach_function :struct_s32_ptr_s32_s8s32_ret_s32, [ :int, :pointer, :int, S8S32.by_value ], :int
639
- attach_function :struct_varargs_ret_struct_string, [ :int, :varargs ], StructString.by_value
640
- end
641
-
642
- it 'return using pre-set values' do
643
- s = LibTest.struct_return_s8s32
644
- expect(s[:s8]).to eq(0x7f)
645
- expect(s[:s32]).to eq(0x12345678)
646
- end
647
-
648
- it 'return using passed in values' do
649
- s = LibTest.struct_s8s32_set(123, 456789)
650
- expect(s[:s8]).to eq(123)
651
- expect(s[:s32]).to eq(456789)
652
- end
653
-
654
- it 'parameter' do
655
- s = LibTest::S8S32.new
656
- s[:s8] = 0x12
657
- s[:s32] = 0x34567890
658
- expect(LibTest.struct_s8s32_get_s8(s)).to eq(0x12)
659
- expect(LibTest.struct_s8s32_get_s32(s)).to eq(0x34567890)
660
- end
661
-
662
- it 'parameter with following s32' do
663
- s = LibTest::S8S32.new
664
- s[:s8] = 0x12
665
- s[:s32] = 0x34567890
666
-
667
- expect(LibTest.struct_s8s32_s32_ret_s32(s, 0x1eefdead)).to eq(0x1eefdead)
668
- end
669
-
670
- # it 'parameter with following s64' do
671
- # s = LibTest::S8S64.new
672
- # s[:s8] = 0x12
673
- # s[:s64] = 0x34567890
674
- #
675
- #
676
- # LibTest.struct_s8s64_s64_ret_s64(s, 0x1eefdead1eefdead).should == 0x1eefdead1eefdead
677
- # end
678
-
679
- it 'parameter with preceding s32,ptr,s32' do
680
- s = LibTest::S8S32.new
681
- s[:s8] = 0x12
682
- s[:s32] = 0x34567890
683
- out = LibTest::S8S32.new
684
- expect(LibTest.struct_s32_ptr_s32_s8s32_ret_s32(0x1000000, out, 0x1eafbeef, s)).to eq(0x34567890)
685
- expect(out[:s8]).to eq(s[:s8])
686
- expect(out[:s32]).to eq(s[:s32])
687
- end
688
-
689
- it 'parameter with preceding s32,string,s32' do
690
- s = LibTest::S8S32.new
691
- s[:s8] = 0x12
692
- s[:s32] = 0x34567890
693
- out = 0.chr * 32
694
- expect(LibTest.struct_s32_ptr_s32_s8s32_ret_s32(0x1000000, out, 0x1eafbeef, s)).to eq(0x34567890)
695
- end
696
-
697
- it 'parameter, returning struct by value' do
698
- s = LibTest::S8S32.new
699
- s[:s8] = 0x12
700
- s[:s32] = 0x34567890
701
-
702
- ret = LibTest.struct_s8s32_ret_s8s32(s)
703
- expect(ret[:s8]).to eq(s[:s8])
704
- expect(ret[:s32]).to eq(s[:s32])
705
- end
706
-
707
- it 'varargs returning a struct' do
708
- string = "test"
709
- s = LibTest.struct_varargs_ret_struct_string(4, :string, string)
710
- expect(s[:len]).to eq(string.length)
711
- expect(s[:bytes]).to eq(string)
712
- end
713
- end
714
-
715
- describe FFI::Struct, ' with an array field' do
716
- module LibTest
717
- extend FFI::Library
718
- ffi_lib TestLibrary::PATH
719
- class StructWithArray < FFI::Struct
720
- layout :first, :char, :a, [:int, 5]
721
- end
722
- attach_function :struct_make_struct_with_array, [:int, :int, :int, :int, :int], :pointer
723
- attach_function :struct_field_array, [:pointer], :pointer
724
- end
725
- before do
726
- @s = LibTest::StructWithArray.new
727
- end
728
-
729
- it 'should correctly calculate StructWithArray size (in bytes)' do
730
- expect(LibTest::StructWithArray.size).to eq(24)
731
- end
732
-
733
- it 'should read values from memory' do
734
- @s = LibTest::StructWithArray.new(LibTest.struct_make_struct_with_array(0, 1, 2, 3, 4))
735
- expect(@s[:a].to_a).to eq([0, 1, 2, 3, 4])
736
- end
737
- # it 'should cache array object for successive calls' do
738
- # @s[:a].object_id.should == @s[:a].object_id
739
- # end
740
-
741
- it 'should return the number of elements in the array field' do
742
- @s = LibTest::StructWithArray.new(LibTest.struct_make_struct_with_array(0, 1, 2, 3, 4))
743
- expect(@s[:a].size).to eq(5)
744
- end
745
-
746
- it 'should allow iteration through the array elements' do
747
- @s = LibTest::StructWithArray.new(LibTest.struct_make_struct_with_array(0, 1, 2, 3, 4))
748
- @s[:a].each_with_index { |elem, i| expect(elem).to eq(i) }
749
- end
750
-
751
- it 'should return the pointer to the array' do
752
- @s = LibTest::StructWithArray.new(LibTest.struct_make_struct_with_array(0, 1, 2, 3, 4))
753
- expect(@s[:a].to_ptr).to eq(LibTest::struct_field_array(@s.to_ptr))
754
- end
755
- end
756
-
757
- describe 'BuggedStruct' do
758
- module LibTest
759
- extend FFI::Library
760
- ffi_lib TestLibrary::PATH
761
- class BuggedStruct < FFI::Struct
762
- layout :visible, :uchar,
763
- :x, :uint,
764
- :y, :uint,
765
- :rx, :short,
766
- :ry, :short,
767
- :order, :uchar,
768
- :size, :uchar
769
- end
770
- attach_function :bugged_struct_size, [], :uint
771
- end
772
-
773
- it 'should return its correct size' do
774
- expect(LibTest::BuggedStruct.size).to eq(LibTest.bugged_struct_size)
775
- end
776
-
777
- it "offsets within struct should be correct" do
778
- expect(LibTest::BuggedStruct.offset_of(:visible)).to eq(0)
779
- expect(LibTest::BuggedStruct.offset_of(:x)).to eq(4)
780
- expect(LibTest::BuggedStruct.offset_of(:y)).to eq(8)
781
- expect(LibTest::BuggedStruct.offset_of(:rx)).to eq(12)
782
- expect(LibTest::BuggedStruct.offset_of(:ry)).to eq(14)
783
- expect(LibTest::BuggedStruct.offset_of(:order)).to eq(16)
784
- expect(LibTest::BuggedStruct.offset_of(:size)).to eq(17)
785
- end
786
-
787
- it 'should return correct field/offset pairs' do
788
- expect(LibTest::BuggedStruct.offsets.sort do |a, b|
789
- a[1] <=> b[1]
790
- end).to eq([[:visible, 0], [:x, 4], [:y, 8], [:rx, 12], [:ry, 14], [:order, 16], [:size, 17]])
791
- end
792
- end
793
-
794
- describe "Struct allocation" do
795
- it "MemoryPointer.new(Struct, 2)" do
796
- class S < FFI::Struct
797
- layout :i, :uint
798
- end
799
- p = FFI::MemoryPointer.new(S, 2)
800
- expect(p.total).to eq(8)
801
- expect(p.type_size).to eq(4)
802
- p.put_uint(4, 0xdeadbeef)
803
- expect(S.new(p[1])[:i]).to eq(0xdeadbeef)
804
- expect(p[1].address).to eq((p[0].address + 4))
805
- end
806
-
807
- it "Buffer.new(Struct, 2)" do
808
- class S < FFI::Struct
809
- layout :i, :uint
810
- end
811
- p = FFI::Buffer.new(S, 2)
812
- expect(p.total).to eq(8)
813
- expect(p.type_size).to eq(4)
814
- p.put_uint(4, 0xdeadbeef)
815
- expect(S.new(p[1])[:i]).to eq(0xdeadbeef)
816
- end
817
-
818
- it "null? should be true when initialized with NULL pointer" do
819
- class S < FFI::Struct
820
- layout :i, :uint
821
- end
822
- expect(S.new(FFI::Pointer::NULL)).to be_null
823
- end
824
-
825
- it "null? should be false when initialized with non-NULL pointer" do
826
- class S < FFI::Struct
827
- layout :i, :uint
828
- end
829
- expect(S.new(FFI::MemoryPointer.new(S))).not_to be_null
830
- end
831
-
832
- it "supports :bool as a struct member" do
833
- expect do
834
- c = Class.new(FFI::Struct) do
835
- layout :b, :bool
836
- end
837
- struct = c.new
838
- struct[:b] = ! struct[:b]
839
- end.not_to raise_error Exception
840
- end
841
-
842
- end
843
-
844
- describe "variable-length arrays" do
845
- it "zero length array should be accepted as last field" do
846
- expect {
847
- Class.new(FFI::Struct) do
848
- layout :count, :int, :data, [ :char, 0 ]
849
- end
850
- }.not_to raise_error Exception
851
- end
852
-
853
- it "zero length array before last element should raise error" do
854
- expect {
855
- Class.new(FFI::Struct) do
856
- layout :data, [ :char, 0 ], :count, :int
857
- end
858
- }.to raise_error
859
- end
860
-
861
- it "can access elements of array" do
862
- struct_class = Class.new(FFI::Struct) do
863
- layout :count, :int, :data, [ :long, 0 ]
864
- end
865
- s = struct_class.new(FFI::MemoryPointer.new(1024))
866
- s[:data][0] = 0x1eadbeef
867
- s[:data][1] = 0x12345678
868
- expect(s[:data][0]).to eq(0x1eadbeef)
869
- expect(s[:data][1]).to eq(0x12345678)
870
- end
871
-
872
- it "non-variable length array is bounds checked" do
873
- struct_class = Class.new(FFI::Struct) do
874
- layout :count, :int, :data, [ :long, 1 ]
875
- end
876
- s = struct_class.new(FFI::MemoryPointer.new(1024))
877
- s[:data][0] = 0x1eadbeef
878
- expect { s[:data][1] = 0x12345678 }.to raise_error
879
- expect(s[:data][0]).to eq(0x1eadbeef)
880
- expect { expect(s[:data][1]).to == 0x12345678 }.to raise_error
881
- end
882
- end