diff options
-rw-r--r-- | ext/ffi_c/Type.c | 36 | ||||
-rw-r--r-- | lib/ffi/types.rb | 26 | ||||
-rw-r--r-- | spec/ffi/rbx/memory_pointer_spec.rb | 14 |
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 |