summaryrefslogtreecommitdiff
path: root/spec/ffi
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2023-05-08 13:21:33 +0200
committerLars Kanis <lars@greiz-reinsdorf.de>2023-05-08 13:21:33 +0200
commitc6b7139d0394638ef51b451b81dcd2ffefb94160 (patch)
treef1513b0afc5ef798382100a53c3191ff52e66d3e /spec/ffi
parentc1e6a14476e210efeac79aa260c2eb2d1d98a580 (diff)
parent938b5d8590361acf871fddb9149fe725f65d781f (diff)
downloadffi-c6b7139d0394638ef51b451b81dcd2ffefb94160.tar.gz
Merge branch 'ractor'
Diffstat (limited to 'spec/ffi')
-rw-r--r--spec/ffi/async_callback_spec.rb23
-rw-r--r--spec/ffi/dynamic_library_spec.rb60
-rw-r--r--spec/ffi/enum_spec.rb38
-rw-r--r--spec/ffi/errno_spec.rb8
-rw-r--r--spec/ffi/fixtures/compile.rb2
-rw-r--r--spec/ffi/function_spec.rb24
-rw-r--r--spec/ffi/function_type_spec.rb2
-rw-r--r--spec/ffi/library_spec.rb100
-rw-r--r--spec/ffi/memorypointer_spec.rb34
-rw-r--r--spec/ffi/platform_spec.rb13
-rw-r--r--spec/ffi/pointer_spec.rb12
-rw-r--r--spec/ffi/rbx/memory_pointer_spec.rb12
-rw-r--r--spec/ffi/spec_helper.rb1
-rw-r--r--spec/ffi/struct_by_ref_spec.rb9
-rw-r--r--spec/ffi/struct_spec.rb64
-rw-r--r--spec/ffi/type_spec.rb35
-rw-r--r--spec/ffi/variadic_spec.rb32
17 files changed, 434 insertions, 35 deletions
diff --git a/spec/ffi/async_callback_spec.rb b/spec/ffi/async_callback_spec.rb
index 51a4886..7bb9f70 100644
--- a/spec/ffi/async_callback_spec.rb
+++ b/spec/ffi/async_callback_spec.rb
@@ -50,4 +50,27 @@ describe "async callback" do
expect(callback_runner_thread.name).to eq("FFI Callback Runner")
end
+
+ it "works in Ractor", :ractor do
+ skip "not yet supported on TruffleRuby" if RUBY_ENGINE == "truffleruby"
+
+ res = Ractor.new do
+ v = 0xdeadbeef
+ correct_ractor = false
+ correct_thread = false
+ thread = Thread.current
+ rac = Ractor.current
+ cb = Proc.new do |i|
+ v = i
+ correct_ractor = rac == Ractor.current
+ correct_thread = thread != Thread.current
+ end
+ LibTest.testAsyncCallback(cb, 0x7fffffff)
+
+ [v, correct_ractor, correct_thread]
+ end.take
+
+ expect(res).to eq([0x7fffffff, true, true])
+ end
+
end
diff --git a/spec/ffi/dynamic_library_spec.rb b/spec/ffi/dynamic_library_spec.rb
new file mode 100644
index 0000000..088a822
--- /dev/null
+++ b/spec/ffi/dynamic_library_spec.rb
@@ -0,0 +1,60 @@
+#
+# This file is part of ruby-ffi.
+# For licensing, see LICENSE.SPECS
+#
+
+require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
+
+describe FFI::DynamicLibrary do
+ it "should be shareable for Ractor", :ractor do
+ libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
+ FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
+
+ res = Ractor.new(libtest) do |libtest2|
+ libtest2.find_symbol("testClosureVrV").address
+ end.take
+
+ expect( res ).to be > 0
+ end
+
+ it "load a library in a Ractor", :ractor do
+ res = Ractor.new do
+ libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
+ FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
+ libtest.find_symbol("testClosureVrV")
+ end.take
+
+ expect(res.address).to be > 0
+ end
+
+ it "has a memsize function", skip: RUBY_ENGINE != "ruby" do
+ base_size = ObjectSpace.memsize_of(Object.new)
+
+ libtest = FFI::DynamicLibrary.open(TestLibrary::PATH,
+ FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
+ size = ObjectSpace.memsize_of(libtest)
+ expect(size).to be > base_size
+ end
+
+ describe Symbol do
+ before do
+ @libtest = FFI::DynamicLibrary.open(
+ TestLibrary::PATH,
+ FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL,
+ )
+ end
+
+ it "has a memsize function", skip: RUBY_ENGINE != "ruby" do
+ base_size = ObjectSpace.memsize_of(Object.new)
+
+ symbol = @libtest.find_symbol("gvar_gstruct_set")
+ size = ObjectSpace.memsize_of(symbol)
+ expect(size).to be > base_size
+ end
+
+ it "should be shareable for Ractor", :ractor do
+ symbol = @libtest.find_symbol("gvar_gstruct_set")
+ expect(Ractor.shareable?(symbol)).to be true
+ end
+ end
+end
diff --git a/spec/ffi/enum_spec.rb b/spec/ffi/enum_spec.rb
index b8c5b57..7a55b07 100644
--- a/spec/ffi/enum_spec.rb
+++ b/spec/ffi/enum_spec.rb
@@ -26,14 +26,18 @@ module TestEnum3
ffi_lib TestLibrary::PATH
enum :enum_type1, [:c1, :c2, :c3, :c4]
- enum :enum_type2, [:c5, 42, :c6, :c7, :c8]
- enum :enum_type3, [:c9, 42, :c10, :c11, 4242, :c12]
- enum :enum_type4, [:c13, 42, :c14, 4242, :c15, 424242, :c16, 42424242]
-
attach_function :test_tagged_typedef_enum1, [:enum_type1], :enum_type1
+
+ enum :enum_type2, [:c5, 42, :c6, :c7, :c8]
attach_function :test_tagged_typedef_enum2, [:enum_type2], :enum_type2
+
+ enum :enum_type3, [:c9, 42, :c10, :c11, 4242, :c12]
attach_function :test_tagged_typedef_enum3, [:enum_type3], :enum_type3
+
+ enum :enum_type4, [:c13, 42, :c14, 4242, :c15, 424242, :c16, 42424242]
attach_function :test_tagged_typedef_enum4, [:enum_type4], :enum_type4
+
+ freeze
end
module TestEnum4
@@ -44,18 +48,22 @@ module TestEnum4
enum :enum_type1, [:c5, 0x42, :c6, :c7, :c8]
enum :enum_type2, [:c9, 0x42, :c10, :c11, 0x4242, :c12]
enum :enum_type3, [:c13, 0x42, :c14, 0x4242, :c15, 0x42424242, :c16, 0x4242424242424242]
- enum FFI::Type::UINT16, :enum_type4, [:c17, 0x42, :c18, :c19, :c20]
- enum FFI::Type::UINT32, :enum_type5, [:c21, 0x42, :c22, :c23, 0x4242, :c24]
- enum FFI::Type::UINT64, :enum_type6, [:c25, 0x42, :c26, 0x4242, :c27, 0x42424242, :c28, 0x4242424242424242]
- enum FFI::Type::UINT64, [:c29, 0x4242424242424242, :c30, :c31, :c32]
attach_function :test_untagged_nonint_enum, [:uint8], :uint8
attach_function :test_tagged_nonint_enum1, [:uint16], :uint16
attach_function :test_tagged_nonint_enum2, [:uint32], :uint32
attach_function :test_tagged_nonint_enum3, [:uint64], :uint64
+
+ enum FFI::Type::UINT16, :enum_type4, [:c17, 0x42, :c18, :c19, :c20]
+ enum FFI::Type::UINT32, :enum_type5, [:c21, 0x42, :c22, :c23, 0x4242, :c24]
+ enum FFI::Type::UINT64, :enum_type6, [:c25, 0x42, :c26, 0x4242, :c27, 0x42424242, :c28, 0x4242424242424242]
+ enum FFI::Type::UINT64, [:c29, 0x4242424242424242, :c30, :c31, :c32]
+
attach_function :test_tagged_nonint_enum4, :test_tagged_nonint_enum1, [:enum_type4], :enum_type4
attach_function :test_tagged_nonint_enum5, :test_tagged_nonint_enum2, [:enum_type5], :enum_type5
attach_function :test_tagged_nonint_enum6, :test_tagged_nonint_enum3, [:enum_type6], :enum_type6
+
+ freeze
end
describe "A library with no enum defined" do
@@ -430,4 +438,18 @@ describe "All enums" do
end
end.to raise_error(ArgumentError, /duplicate/)
end
+
+ it "should be usable in Ractor", :ractor do
+ res = Ractor.new do
+ [
+ TestEnum1.test_untagged_enum(:c1),
+ TestEnum3.test_tagged_typedef_enum1(:c1),
+ TestEnum4.test_tagged_nonint_enum4(0x45),
+ TestEnum3.enum_type(:enum_type1)[0],
+ TestEnum4.enum_type(:enum_type6)[0x4242424242424242],
+ TestEnum4.enum_value(:c3)
+ ]
+ end.take
+ expect( res ).to eq( [0, :c1, :c20, :c1, :c28, 2] )
+ end
end
diff --git a/spec/ffi/errno_spec.rb b/spec/ffi/errno_spec.rb
index 4170f92..c0207b8 100644
--- a/spec/ffi/errno_spec.rb
+++ b/spec/ffi/errno_spec.rb
@@ -34,4 +34,12 @@ describe "FFI.errno" do
expect(FFI.errno).to eq(0x12345678)
end
end
+
+ it "works in Ractor", :ractor do
+ res = Ractor.new do
+ LibTest.setLastError(0x12345678)
+ FFI.errno
+ end.take
+ expect(res).to eq(0x12345678)
+ end
end
diff --git a/spec/ffi/fixtures/compile.rb b/spec/ffi/fixtures/compile.rb
index 58ee561..2be97cb 100644
--- a/spec/ffi/fixtures/compile.rb
+++ b/spec/ffi/fixtures/compile.rb
@@ -69,5 +69,5 @@ module TestLibrary
lib
end
- PATH = compile_library(".", "libtest.#{FFI::Platform::LIBSUFFIX}")
+ PATH = FFI.make_shareable(compile_library(".", "libtest.#{FFI::Platform::LIBSUFFIX}"))
end
diff --git a/spec/ffi/function_spec.rb b/spec/ffi/function_spec.rb
index 7f90ea3..77d09d8 100644
--- a/spec/ffi/function_spec.rb
+++ b/spec/ffi/function_spec.rb
@@ -48,6 +48,30 @@ describe FFI::Function do
expect(LibTest.testFunctionAdd(10, 10, function_add)).to eq(20)
end
+ def adder(a, b)
+ a + b
+ end
+
+ it "can be made shareable for Ractor", :ractor do
+ add = FFI::Function.new(:int, [:int, :int], &method(:adder))
+ Ractor.make_shareable(add)
+
+ res = Ractor.new(add) do |add2|
+ LibTest.testFunctionAdd(10, 10, add2)
+ end.take
+
+ expect( res ).to eq(20)
+ end
+
+ it "should be usable with Ractor", :ractor do
+ res = Ractor.new do
+ function_add = FFI::Function.new(:int, [:int, :int]) { |a, b| a + b }
+ LibTest.testFunctionAdd(10, 10, function_add)
+ end.take
+
+ expect( res ).to eq(20)
+ end
+
it 'can be used to wrap an existing function pointer' do
expect(FFI::Function.new(:int, [:int, :int], @libtest.find_function('testAdd')).call(10, 10)).to eq(20)
end
diff --git a/spec/ffi/function_type_spec.rb b/spec/ffi/function_type_spec.rb
index 54e1c48..2f171d8 100644
--- a/spec/ffi/function_type_spec.rb
+++ b/spec/ffi/function_type_spec.rb
@@ -8,7 +8,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
describe "FFI::FunctionType", skip: RUBY_ENGINE != "ruby" do
it 'is initialized with return type and a list of parameter types' do
function_type = FFI::FunctionType.new(:int, [ :char, :ulong ])
- expect(function_type.result_type).to be == FFI::Type::Builtin::INT
+ expect(function_type.return_type).to be == FFI::Type::Builtin::INT
expect(function_type.param_types).to be == [ FFI::Type::Builtin::CHAR, FFI::Type::Builtin::ULONG ]
end
diff --git a/spec/ffi/library_spec.rb b/spec/ffi/library_spec.rb
index a17d673..8691b17 100644
--- a/spec/ffi/library_spec.rb
+++ b/spec/ffi/library_spec.rb
@@ -5,6 +5,12 @@
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
+module TestEnumValueRactor
+ extend FFI::Library
+ enum :something, [:one, :two]
+ freeze
+end
+
describe "Library" do
describe ".enum_value" do
m = Module.new do
@@ -20,6 +26,14 @@ describe "Library" do
it "should return nil for an invalid key" do
expect(m.enum_value(:three)).to be nil
end
+
+ it "should be queryable in Ractor", :ractor do
+ res = Ractor.new do
+ TestEnumValueRactor.enum_value(:one)
+ end.take
+
+ expect( res ).to eq(0)
+ end
end
describe "#ffi_convention" do
@@ -184,15 +198,49 @@ describe "Library" do
end.getpid).to eq(Process.pid)
}.to raise_error(LoadError)
end
+ end
- it "attach_function :bool_return_true from [ File.expand_path(#{TestLibrary::PATH.inspect}) ]" do
- mod = Module.new do |m|
- m.extend FFI::Library
- ffi_lib File.expand_path(TestLibrary::PATH)
- attach_function :bool_return_true, [ ], :bool
- end
- expect(mod.bool_return_true).to be true
+ it "attach_function :bool_return_true from [ File.expand_path(#{TestLibrary::PATH.inspect}) ]" do
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :bool_return_true, [ ], :bool
+ end
+ expect(mod.bool_return_true).to be true
+ end
+
+ it "can define a foo! function" do
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :foo!, :bool_return_true, [], :bool
end
+ expect(mod.foo!).to be true
+ end
+
+ it "can define a foo? function" do
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :foo?, :bool_return_true, [], :bool
+ end
+ expect(mod.foo?).to be true
+ end
+
+ it "can reveal the function type" do
+ skip 'this is not yet implemented on JRuby' if RUBY_ENGINE == 'jruby'
+ skip 'this is not yet implemented on Truffleruby' if RUBY_ENGINE == 'truffleruby'
+
+ mod = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib File.expand_path(TestLibrary::PATH)
+ attach_function :bool_return_true, [ :string ], :bool
+ end
+
+ fun = mod.attached_functions
+ expect(fun.keys).to eq([:bool_return_true])
+ expect(fun[:bool_return_true].param_types).to eq([FFI::Type::STRING])
+ expect(fun[:bool_return_true].return_type).to eq(FFI::Type::BOOL)
end
def gvar_lib(name, type)
@@ -323,20 +371,34 @@ describe "Library" do
end
end
- describe "Symbol" do
- before do
- @libtest = FFI::DynamicLibrary.open(
- TestLibrary::PATH,
- FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL,
- )
+ it "can reveal its attached global struct based variables" do
+ lib = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib TestLibrary::PATH
+ attach_variable :gvari, "gvar_gstruct", GlobalStruct
end
+ expect(lib.attached_variables).to eq({ gvari: GlobalStruct })
+ end
- it "has a memsize function", skip: RUBY_ENGINE != "ruby" do
- base_size = ObjectSpace.memsize_of(Object.new)
-
- symbol = @libtest.find_symbol("gvar_gstruct_set")
- size = ObjectSpace.memsize_of(symbol)
- expect(size).to be > base_size
+ it "can reveal its attached global variables" do
+ lib = Module.new do |m|
+ m.extend FFI::Library
+ ffi_lib TestLibrary::PATH
+ attach_variable "gvaro", "gvar_u32", :uint32
end
+ expect(lib.attached_variables).to eq({ gvaro: FFI::Type::UINT32 })
+ end
+
+ it "should have shareable constants for Ractor", :ractor do
+ res = Ractor.new do
+ [
+ FFI::Library::LIBC,
+ FFI::Library::CURRENT_PROCESS,
+ FFI::CURRENT_PROCESS,
+ FFI::USE_THIS_PROCESS_AS_LIBRARY,
+ ]
+ end.take
+
+ expect( res.size ).to be > 0
end
end
diff --git a/spec/ffi/memorypointer_spec.rb b/spec/ffi/memorypointer_spec.rb
index c8d1b42..f29e2cb 100644
--- a/spec/ffi/memorypointer_spec.rb
+++ b/spec/ffi/memorypointer_spec.rb
@@ -28,6 +28,21 @@ describe "MemoryPointer#total" do
expect(MemoryPointer.new(1024).total).to eq 1024
end
end
+describe "MemoryPointer#clear" do
+ it "should clear the memory" do
+ ptr = MemoryPointer.new(:long)
+ ptr.write_long 1234
+ expect(ptr.read_long).to eq(1234)
+ ptr.clear
+ expect(ptr.read_long).to eq(0)
+ end
+ it "should deny changes when frozen" do
+ skip "not yet supported on TruffleRuby" if RUBY_ENGINE == "truffleruby"
+ skip "not yet supported on JRuby" if RUBY_ENGINE == "jruby"
+ ptr = MemoryPointer.new(:long).freeze
+ expect{ ptr.clear }.to raise_error(RuntimeError, /memory write/)
+ end
+end
describe "MemoryPointer#read_array_of_long" do
it "foo" do
ptr = MemoryPointer.new(:long, 1024)
@@ -76,3 +91,22 @@ describe "MemoryPointer return value" do
expect(Stdio.fclose(fp)).to eq 0 unless fp.nil? or fp.null?
end
end
+describe "#autorelease" do
+ it "should be true by default" do
+ expect(MemoryPointer.new(8).autorelease?).to be true
+ end
+
+ it "should return false when autorelease=(false)" do
+ ptr = MemoryPointer.new(8)
+ ptr.autorelease = false
+ expect(ptr.autorelease?).to be false
+ ptr.free
+ end
+
+ it "should deny changes when frozen" do
+ skip "not yet supported on TruffleRuby" if RUBY_ENGINE == "truffleruby"
+ skip "not yet supported on JRuby" if RUBY_ENGINE == "jruby"
+ ptr = MemoryPointer.new(8).freeze
+ expect{ ptr.autorelease = false }.to raise_error(FrozenError)
+ end
+end
diff --git a/spec/ffi/platform_spec.rb b/spec/ffi/platform_spec.rb
index ad23621..8890b07 100644
--- a/spec/ffi/platform_spec.rb
+++ b/spec/ffi/platform_spec.rb
@@ -134,4 +134,17 @@ describe "FFI::Platform.unix?" do
expect(FFI::Platform::BYTE_ORDER).to eq(order)
end
end
+
+ it "should have shareable constants for Ractor", :ractor do
+ res = Ractor.new do
+ [
+ FFI::Platform::OS,
+ FFI::Platform::CPU,
+ FFI::Platform::ARCH,
+ FFI::Platform::OS,
+ ]
+ end.take
+
+ expect( res.size ).to be > 0
+ end
end
diff --git a/spec/ffi/pointer_spec.rb b/spec/ffi/pointer_spec.rb
index 820e144..8716d30 100644
--- a/spec/ffi/pointer_spec.rb
+++ b/spec/ffi/pointer_spec.rb
@@ -90,6 +90,13 @@ describe "Pointer" do
expect(PointerTestLib.ptr_ret_pointer(memory, 0).address).to eq(0xdeadbeef)
end
+ it "#write_pointer frozen object" do
+ skip "not yet supported on TruffleRuby" if RUBY_ENGINE == "truffleruby"
+ skip "not yet supported on JRuby" if RUBY_ENGINE == "jruby"
+ memory = FFI::MemoryPointer.new(:pointer).freeze
+ expect{ memory.write_pointer(PointerTestLib.ptr_from_address(0xdeadbeef)) }.to raise_error(RuntimeError, /memory write/)
+ end
+
it "#read_array_of_pointer" do
values = [0x12345678, 0xfeedf00d, 0xdeadbeef]
memory = FFI::MemoryPointer.new :pointer, values.size
@@ -364,6 +371,11 @@ describe "AutoPointer" do
ptr.autorelease = false
expect(ptr.autorelease?).to be false
end
+
+ it "should deny changes when frozen" do
+ ptr = ptr_class.new(FFI::Pointer.new(0xdeadbeef)).freeze
+ expect{ ptr.autorelease = false }.to raise_error(FrozenError)
+ end
end
describe "#type_size" do
diff --git a/spec/ffi/rbx/memory_pointer_spec.rb b/spec/ffi/rbx/memory_pointer_spec.rb
index 2db89a9..1270c9b 100644
--- a/spec/ffi/rbx/memory_pointer_spec.rb
+++ b/spec/ffi/rbx/memory_pointer_spec.rb
@@ -104,6 +104,18 @@ describe "MemoryPointer" do
expect(m.read FFI::Type::BOOL).to eq(false)
end
+ it "allows definition of a custom typedef" do
+ FFI.typedef :uint32, :fubar_t
+ expect(FFI.find_type(:fubar_t)).to eq(FFI::Type::Builtin::UINT32)
+ end
+
+ it "allows overwriting of a default typedef" do
+ FFI.typedef :uint32, :char
+ expect(FFI.find_type(:char)).to eq(FFI::Type::Builtin::UINT32)
+ ensure
+ FFI.typedef FFI::Type::Builtin::CHAR, :char
+ end
+
it "allows writing a custom typedef" do
FFI.typedef :uint, :fubar_t
FFI.typedef :size_t, :fubar2_t
diff --git a/spec/ffi/spec_helper.rb b/spec/ffi/spec_helper.rb
index a0adbed..22d1c47 100644
--- a/spec/ffi/spec_helper.rb
+++ b/spec/ffi/spec_helper.rb
@@ -9,6 +9,7 @@ require 'objspace'
RSpec.configure do |c|
c.filter_run_excluding gc_dependent: true unless ENV['FFI_TEST_GC'] == 'true'
+ c.filter_run_excluding( :ractor ) unless defined?(Ractor) && RUBY_VERSION >= "3.1"
end
module TestLibrary
diff --git a/spec/ffi/struct_by_ref_spec.rb b/spec/ffi/struct_by_ref_spec.rb
index 0858423..a775f92 100644
--- a/spec/ffi/struct_by_ref_spec.rb
+++ b/spec/ffi/struct_by_ref_spec.rb
@@ -39,5 +39,14 @@ describe FFI::Struct, ' by_ref' do
expect { @api.struct_test(other_class.new) }.to raise_error(TypeError)
end
+
+ it "can reveal the mapped type converter" do
+ skip 'this is not yet implemented on JRuby' if RUBY_ENGINE == 'jruby'
+ skip 'this is not yet implemented on Truffleruby' if RUBY_ENGINE == 'truffleruby'
+
+ param_type = @api.attached_functions[:struct_test].param_types[0]
+ expect(param_type).to be_a(FFI::Type::Mapped)
+ expect(param_type.converter).to be_a(FFI::StructByReference)
+ end
end
diff --git a/spec/ffi/struct_spec.rb b/spec/ffi/struct_spec.rb
index 0ce5273..ab62da1 100644
--- a/spec/ffi/struct_spec.rb
+++ b/spec/ffi/struct_spec.rb
@@ -410,6 +410,7 @@ module StructSpecsStructTests
s.pointer.put_double(0, 1.0)
expect(s.pointer.get_double(0)).to eq(1.0)
end
+
module EnumFields
extend FFI::Library
TestEnum = enum :test_enum, [:c1, 10, :c2, 20, :c3, 30, :c4, 40]
@@ -456,13 +457,24 @@ module StructSpecsStructTests
end
it "Can have CallbackInfo struct field" do
+ s = CallbackMember::TestStruct.new
+ add_proc = lambda { |a, b| a + b }
+ sub_proc = lambda { |a, b| a - b }
+ s[:add] = add_proc
+ s[:sub] = sub_proc
+ expect(CallbackMember.struct_call_add_cb(s, 40, 2)).to eq(42)
+ expect(CallbackMember.struct_call_sub_cb(s, 44, 2)).to eq(42)
+ end
+
+ it "Can use CallbackInfo struct field in Ractor", :ractor do
+ res = Ractor.new do
s = CallbackMember::TestStruct.new
- add_proc = lambda { |a, b| a+b }
- sub_proc = lambda { |a, b| a-b }
+ add_proc = lambda { |a, b| a + b }
s[:add] = add_proc
- s[:sub] = sub_proc
- expect(CallbackMember.struct_call_add_cb(s, 40, 2)).to eq(42)
- expect(CallbackMember.struct_call_sub_cb(s, 44, 2)).to eq(42)
+ CallbackMember.struct_call_add_cb(s, 40, 2)
+ end.take
+
+ expect( res ).to eq(42)
end
it "Can return its members as a list" do
@@ -532,6 +544,34 @@ module StructSpecsStructTests
expect(a.members).to eq([:a])
expect(b.members).to eq([:a, :b])
end
+
+ it "can be made shareable for Ractor", :ractor do
+ a = Class.new(FFI::Struct) do
+ layout :a, :char
+ end.new
+ a[:a] = -34
+ Ractor.make_shareable(a)
+
+ res = Ractor.new(a) do |a2|
+ a2[:a]
+ end.take
+
+ expect( res ).to eq(-34)
+ end
+
+ it "should be usable with Ractor", :ractor do
+ class TestStructRactor < FFI::Struct
+ layout :i, :int
+ end
+
+ res = Ractor.new do
+ s = TestStructRactor.new
+ s[:i] = 0x14
+ LibTest.ptr_ret_int32_t(s, 0)
+ end.take
+
+ expect( res ).to eq(0x14)
+ end
end
end
@@ -1069,6 +1109,20 @@ describe "Struct memsize functions", skip: RUBY_ENGINE != "ruby" do
size = ObjectSpace.memsize_of(layout[:pointer])
expect(size).to be > base_size
end
+
+ it "StructLayout should be shareable with Ractor", :ractor do
+ kl = Class.new(FFI::Struct) do
+ layout :ptr, :pointer
+ end
+ expect(Ractor.shareable?(kl.layout)).to eq(true)
+ end
+
+ it "StructField should be shareable with Ractor", :ractor do
+ kl = Class.new(FFI::Struct) do
+ layout :ptr, :pointer
+ end
+ expect(Ractor.shareable?(kl.layout[:ptr])).to eq(true)
+ end
end
diff --git a/spec/ffi/type_spec.rb b/spec/ffi/type_spec.rb
index eb48a43..e880c83 100644
--- a/spec/ffi/type_spec.rb
+++ b/spec/ffi/type_spec.rb
@@ -5,7 +5,7 @@
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
-describe "FFI::Type" do
+describe FFI::Type do
it 'has a memsize function', skip: RUBY_ENGINE != "ruby" do
base_size = ObjectSpace.memsize_of(Object.new)
@@ -40,4 +40,37 @@ describe "FFI::Type" do
size = ObjectSpace.memsize_of(FFI::Type::Builtin::CHAR)
expect(size).to be > base_size
end
+
+ it "should be shareable with Ractor", :ractor do
+ expect(Ractor.shareable?(FFI::Type.new(5))).to eq(true)
+ end
+
+ describe :Builtin do
+ it "should be shareable with Ractor", :ractor do
+ expect(Ractor.shareable?(FFI::Type::INT32)).to eq(true)
+ end
+ end
+
+ describe :Mapped do
+ it "should be shareable with Ractor", :ractor do
+ converter = Module.new do
+ extend FFI::DataConverter
+
+ def self.native_type
+ FFI::Type::INT32
+ end
+
+ def self.to_native(val, ctx)
+ ToNativeMap[val]
+ end
+
+ def self.from_native(val, ctx)
+ FromNativeMap[val]
+ end
+ end
+ expect(Ractor.shareable?(converter)).to eq(true)
+ type = FFI::Type::Mapped.new(converter)
+ expect(Ractor.shareable?(type)).to eq(true)
+ end
+ end
end
diff --git a/spec/ffi/variadic_spec.rb b/spec/ffi/variadic_spec.rb
index f379ed4..b528c09 100644
--- a/spec/ffi/variadic_spec.rb
+++ b/spec/ffi/variadic_spec.rb
@@ -23,6 +23,8 @@ describe "Function with variadic arguments" do
attach_function :testBlockingClose, [ :pointer ], :void
attach_function :testCallbackVrDva, :testClosureVrDva, [ :double, :varargs ], :double
attach_function :testCallbackVrILva, :testClosureVrILva, [ :int, :long, :varargs ], :long
+
+ freeze
end
it "takes enum arguments" do
@@ -37,6 +39,15 @@ describe "Function with variadic arguments" do
expect(LibTest.pack_varargs2(buf, :c1, "ii", :int, :c3, :int, :c4)).to eq(:c2)
end
+ it "can reveal its return and parameters" do
+ skip 'this is not yet implemented on JRuby' if RUBY_ENGINE == 'jruby'
+ skip 'this is not yet implemented on Truffleruby' if RUBY_ENGINE == 'truffleruby'
+
+ fun = LibTest.attached_functions[:testBlockingWRva]
+ expect(fun.param_types).to eq([FFI::Type::POINTER, FFI::Type::CHAR, FFI::Type::VARARGS])
+ expect(fun.return_type).to eq(FFI::Type::INT8)
+ end
+
it 'can wrap a blocking function with varargs' do
handle = LibTest.testBlockingOpen
expect(handle).not_to be_null
@@ -87,12 +98,33 @@ describe "Function with variadic arguments" do
expect(LibTest.testCallbackVrDva(3.0, :cbVrD, pr)).to be_within(0.0000001).of(45.0)
end
+ it "can be called as instance method" do
+ kl = Class.new do
+ include LibTest
+ def call
+ pr = proc { 42.0 }
+ testCallbackVrDva(3.0, :cbVrD, pr)
+ end
+ end
+ expect(kl.new.call).to be_within(0.0000001).of(45.0)
+ end
+
it "call variadic with several callback arguments" do
pr1 = proc { |i| i + 1 }
pr2 = proc { |l| l + 2 }
expect(LibTest.testCallbackVrILva(5, 6, :cbVrI, pr1, :cbVrL, pr2)).to eq(14)
end
+ it "should be usable with Ractor", :ractor do
+ res = Ractor.new do
+ pr = proc { 42.0 }
+ LibTest.testCallbackVrDva(3.0, :cbVrD, pr)
+ end.take
+
+ expect(res).to be_within(0.0000001).of(45.0)
+ end
+
+
module Varargs
PACK_VALUES = {
'c' => [ 0x12 ],