summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/ffi_c/Type.c36
-rw-r--r--lib/ffi/types.rb26
-rw-r--r--spec/ffi/rbx/memory_pointer_spec.rb14
3 files changed, 71 insertions, 5 deletions
diff --git a/ext/ffi_c/Type.c b/ext/ffi_c/Type.c
index 3431681..9bf5681 100644
--- a/ext/ffi_c/Type.c
+++ b/ext/ffi_c/Type.c
@@ -33,6 +33,9 @@
#include <sys/types.h>
#include <ruby.h>
+#if HAVE_RB_EXT_RACTOR_SAFE
+#include <ruby/ractor.h>
+#endif
#include <ffi.h>
#include "rbffi.h"
#include "compat.h"
@@ -54,6 +57,9 @@ static VALUE classBuiltinType = Qnil;
static VALUE moduleNativeType = Qnil;
static VALUE typeMap = Qnil;
static ID id_type_size = 0, id_size = 0;
+#if HAVE_RB_EXT_RACTOR_SAFE
+static rb_ractor_local_key_t custom_typedefs_key;
+#endif
const rb_data_type_t rbffi_type_data_type = { /* extern */
.wrap_struct_name = "FFI::Type",
@@ -245,6 +251,25 @@ rbffi_type_size(VALUE type)
}
}
+static VALUE
+custom_typedefs(VALUE self)
+{
+#if HAVE_RB_EXT_RACTOR_SAFE
+ VALUE hash = rb_ractor_local_storage_value(custom_typedefs_key);
+ if (hash == Qnil) {
+ hash = rb_hash_new();
+ rb_ractor_local_storage_value_set(custom_typedefs_key, hash);
+ }
+#else
+ static VALUE hash = Qundef;
+ if (hash == Qundef) {
+ rb_global_variable(&hash);
+ hash = rb_hash_new();
+ }
+#endif
+ return hash;
+}
+
VALUE
rbffi_Type_Lookup(VALUE name)
{
@@ -254,6 +279,12 @@ rbffi_Type_Lookup(VALUE name)
* Try looking up directly in the type map
*/
VALUE nType;
+ VALUE cust = custom_typedefs(Qnil);
+
+ if ((nType = rb_hash_lookup(cust, name)) != Qnil && rb_obj_is_kind_of(nType, rbffi_TypeClass)) {
+ return nType;
+ }
+
if ((nType = rb_hash_lookup(typeMap, name)) != Qnil && rb_obj_is_kind_of(nType, rbffi_TypeClass)) {
return nType;
}
@@ -286,6 +317,11 @@ rbffi_Type_Init(VALUE moduleFFI)
id_type_size = rb_intern("type_size");
id_size = rb_intern("size");
+#if HAVE_RB_EXT_RACTOR_SAFE
+ custom_typedefs_key = rb_ractor_local_storage_value_newkey();
+#endif
+ rb_define_module_function(moduleFFI, "custom_typedefs", custom_typedefs, 0);
+
/*
* Document-class: FFI::Type::Builtin
* Class for Built-in types.
diff --git a/lib/ffi/types.rb b/lib/ffi/types.rb
index 90f50c1..da214ee 100644
--- a/lib/ffi/types.rb
+++ b/lib/ffi/types.rb
@@ -37,8 +37,11 @@ module FFI
# @param [Symbol] add new type definition's name to add
# @return [Type]
# Add a definition type to type definitions.
+ #
+ # The type definition is local per Ractor.
def self.typedef(old, add)
- TypeDefs[add] = self.find_type(old)
+ tm = custom_typedefs
+ tm[add] = self.find_type(old)
end
# (see FFI.typedef)
@@ -46,6 +49,14 @@ module FFI
typedef old, add
end
+ class << self
+ private def __typedef(old, add)
+ TypeDefs[add] = self.find_type(old)
+ end
+
+ private :custom_typedefs
+ end
+
# @param [Type, DataConverter, Symbol] name
# @param [Hash] type_map if nil, {FFI::TypeDefs} is used
@@ -57,9 +68,12 @@ module FFI
if name.is_a?(Type)
name
- elsif type_map && type_map.has_key?(name)
+ elsif type_map&.has_key?(name)
type_map[name]
+ elsif (tm=custom_typedefs).has_key?(name)
+ tm[name]
+
elsif TypeDefs.has_key?(name)
TypeDefs[name]
@@ -168,7 +182,7 @@ module FFI
end
end
- typedef(StrPtrConverter, :strptr)
+ __typedef(StrPtrConverter, :strptr)
# @param type +type+ is an instance of class accepted by {FFI.find_type}
# @return [Numeric]
@@ -184,11 +198,13 @@ module FFI
f.each_line { |line|
if line.index(prefix) == 0
new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/)
- typedef(orig_type.to_sym, new_type.to_sym)
+ __typedef(orig_type.to_sym, new_type.to_sym)
end
}
end
- typedef :pointer, :caddr_t
+ __typedef :pointer, :caddr_t
rescue Errno::ENOENT
end
+
+ FFI.make_shareable(TypeDefs)
end
diff --git a/spec/ffi/rbx/memory_pointer_spec.rb b/spec/ffi/rbx/memory_pointer_spec.rb
index 2db89a9..83d77c3 100644
--- a/spec/ffi/rbx/memory_pointer_spec.rb
+++ b/spec/ffi/rbx/memory_pointer_spec.rb
@@ -104,6 +104,20 @@ 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
+ begin
+ FFI.typedef :uint32, :char
+ expect(FFI.find_type(:char)).to eq(FFI::Type::Builtin::UINT32)
+ ensure
+ FFI.typedef FFI::Type::Builtin::CHAR, :char
+ end
+ end
+
it "allows writing a custom typedef" do
FFI.typedef :uint, :fubar_t
FFI.typedef :size_t, :fubar2_t