rice 4.3.3 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -26
  3. data/README.md +7 -2
  4. data/Rakefile +7 -1
  5. data/include/rice/rice.hpp +7291 -4430
  6. data/include/rice/stl.hpp +769 -222
  7. data/lib/mkmf-rice.rb +37 -95
  8. data/rice/Address_Registration_Guard.hpp +72 -3
  9. data/rice/Arg.hpp +19 -5
  10. data/rice/Arg.ipp +24 -0
  11. data/rice/Callback.hpp +21 -0
  12. data/rice/Callback.ipp +13 -0
  13. data/rice/Constructor.hpp +4 -27
  14. data/rice/Constructor.ipp +79 -0
  15. data/rice/Data_Object.hpp +74 -3
  16. data/rice/Data_Object.ipp +324 -32
  17. data/rice/Data_Type.hpp +215 -3
  18. data/rice/Data_Type.ipp +125 -64
  19. data/rice/Director.hpp +0 -2
  20. data/rice/Enum.hpp +4 -6
  21. data/rice/Enum.ipp +101 -57
  22. data/rice/Exception.hpp +62 -2
  23. data/rice/Exception.ipp +7 -12
  24. data/rice/JumpException.hpp +44 -0
  25. data/rice/JumpException.ipp +48 -0
  26. data/rice/MemoryView.hpp +11 -0
  27. data/rice/MemoryView.ipp +43 -0
  28. data/rice/Return.hpp +6 -26
  29. data/rice/Return.ipp +10 -16
  30. data/rice/detail/DefaultHandler.hpp +12 -0
  31. data/rice/detail/DefaultHandler.ipp +8 -0
  32. data/rice/detail/HandlerRegistry.hpp +5 -35
  33. data/rice/detail/HandlerRegistry.ipp +7 -11
  34. data/rice/detail/InstanceRegistry.hpp +1 -4
  35. data/rice/detail/MethodInfo.hpp +15 -5
  36. data/rice/detail/MethodInfo.ipp +78 -6
  37. data/rice/detail/Native.hpp +32 -0
  38. data/rice/detail/Native.ipp +129 -0
  39. data/rice/detail/NativeAttributeGet.hpp +51 -0
  40. data/rice/detail/NativeAttributeGet.ipp +51 -0
  41. data/rice/detail/NativeAttributeSet.hpp +43 -0
  42. data/rice/detail/NativeAttributeSet.ipp +82 -0
  43. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  44. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  45. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  46. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  47. data/rice/detail/NativeFunction.hpp +20 -21
  48. data/rice/detail/NativeFunction.ipp +199 -64
  49. data/rice/detail/NativeIterator.hpp +8 -11
  50. data/rice/detail/NativeIterator.ipp +27 -31
  51. data/rice/detail/NativeRegistry.hpp +24 -15
  52. data/rice/detail/NativeRegistry.ipp +23 -48
  53. data/rice/detail/Proc.hpp +4 -0
  54. data/rice/detail/Proc.ipp +85 -0
  55. data/rice/detail/Registries.hpp +0 -7
  56. data/rice/detail/Registries.ipp +0 -18
  57. data/rice/detail/RubyFunction.hpp +0 -3
  58. data/rice/detail/RubyFunction.ipp +4 -8
  59. data/rice/detail/RubyType.hpp +19 -0
  60. data/rice/detail/RubyType.ipp +187 -0
  61. data/rice/detail/TupleIterator.hpp +14 -0
  62. data/rice/detail/Type.hpp +5 -6
  63. data/rice/detail/Type.ipp +150 -33
  64. data/rice/detail/TypeRegistry.hpp +15 -7
  65. data/rice/detail/TypeRegistry.ipp +105 -12
  66. data/rice/detail/Wrapper.hpp +6 -5
  67. data/rice/detail/Wrapper.ipp +45 -23
  68. data/rice/detail/cpp_protect.hpp +5 -6
  69. data/rice/detail/default_allocation_func.ipp +0 -2
  70. data/rice/detail/from_ruby.hpp +37 -3
  71. data/rice/detail/from_ruby.ipp +911 -454
  72. data/rice/detail/ruby.hpp +18 -0
  73. data/rice/detail/to_ruby.hpp +41 -3
  74. data/rice/detail/to_ruby.ipp +437 -113
  75. data/rice/global_function.hpp +0 -4
  76. data/rice/global_function.ipp +1 -2
  77. data/rice/rice.hpp +105 -22
  78. data/rice/ruby_mark.hpp +4 -3
  79. data/rice/stl.hpp +4 -0
  80. data/test/embed_ruby.cpp +4 -1
  81. data/test/extconf.rb +2 -0
  82. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  83. data/test/test_Address_Registration_Guard.cpp +5 -0
  84. data/test/test_Array.cpp +12 -1
  85. data/test/test_Attribute.cpp +103 -21
  86. data/test/test_Builtin_Object.cpp +5 -0
  87. data/test/test_Callback.cpp +231 -0
  88. data/test/test_Class.cpp +5 -31
  89. data/test/test_Constructor.cpp +69 -6
  90. data/test/test_Data_Object.cpp +9 -4
  91. data/test/test_Data_Type.cpp +428 -64
  92. data/test/test_Director.cpp +10 -5
  93. data/test/test_Enum.cpp +152 -40
  94. data/test/test_Exception.cpp +235 -0
  95. data/test/test_File.cpp +70 -0
  96. data/test/test_From_Ruby.cpp +542 -0
  97. data/test/test_Hash.cpp +5 -0
  98. data/test/test_Identifier.cpp +5 -0
  99. data/test/test_Inheritance.cpp +6 -1
  100. data/test/test_Iterator.cpp +5 -0
  101. data/test/test_JumpException.cpp +22 -0
  102. data/test/test_Keep_Alive.cpp +6 -1
  103. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
  104. data/test/test_Memory_Management.cpp +5 -0
  105. data/test/test_Module.cpp +118 -64
  106. data/test/test_Native_Registry.cpp +2 -33
  107. data/test/test_Object.cpp +5 -0
  108. data/test/test_Overloads.cpp +631 -0
  109. data/test/test_Ownership.cpp +67 -4
  110. data/test/test_Proc.cpp +45 -0
  111. data/test/test_Self.cpp +5 -0
  112. data/test/test_Stl_Exception.cpp +109 -0
  113. data/test/test_Stl_Map.cpp +22 -8
  114. data/test/test_Stl_Optional.cpp +5 -0
  115. data/test/test_Stl_Pair.cpp +7 -2
  116. data/test/test_Stl_Reference_Wrapper.cpp +5 -0
  117. data/test/test_Stl_SmartPointer.cpp +210 -5
  118. data/test/test_Stl_String.cpp +5 -0
  119. data/test/test_Stl_String_View.cpp +5 -0
  120. data/test/test_Stl_Type.cpp +147 -0
  121. data/test/test_Stl_Unordered_Map.cpp +18 -7
  122. data/test/test_Stl_Variant.cpp +5 -0
  123. data/test/test_Stl_Vector.cpp +130 -8
  124. data/test/test_String.cpp +5 -0
  125. data/test/test_Struct.cpp +5 -0
  126. data/test/test_Symbol.cpp +5 -0
  127. data/test/test_Template.cpp +192 -0
  128. data/test/test_To_Ruby.cpp +152 -0
  129. data/test/test_Tracking.cpp +1 -0
  130. data/test/test_Type.cpp +100 -0
  131. data/test/test_global_functions.cpp +53 -6
  132. data/test/unittest.cpp +8 -0
  133. metadata +37 -20
  134. data/lib/version.rb +0 -3
  135. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  136. data/rice/Data_Object_defn.hpp +0 -84
  137. data/rice/Data_Type_defn.hpp +0 -190
  138. data/rice/Exception_defn.hpp +0 -68
  139. data/rice/HandlerRegistration.hpp +0 -15
  140. data/rice/Identifier.hpp +0 -50
  141. data/rice/Identifier.ipp +0 -29
  142. data/rice/detail/ExceptionHandler.hpp +0 -8
  143. data/rice/detail/ExceptionHandler.ipp +0 -28
  144. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  145. data/rice/detail/Jump_Tag.hpp +0 -21
  146. data/rice/detail/NativeAttribute.hpp +0 -64
  147. data/rice/detail/NativeAttribute.ipp +0 -112
  148. data/rice/detail/from_ruby_defn.hpp +0 -38
  149. data/rice/detail/to_ruby_defn.hpp +0 -48
  150. data/test/test_Jump_Tag.cpp +0 -17
  151. data/test/test_To_From_Ruby.cpp +0 -399
@@ -0,0 +1,51 @@
1
+ #ifndef Rice__detail__Native_Attribute_Get__hpp_
2
+ #define Rice__detail__Native_Attribute_Get__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ enum class AttrAccess
7
+ {
8
+ ReadWrite,
9
+ Read,
10
+ Write
11
+ };
12
+
13
+ namespace detail
14
+ {
15
+ template<typename Attribute_T>
16
+ class NativeAttributeGet: Native
17
+ {
18
+ public:
19
+ using NativeAttribute_T = NativeAttributeGet<Attribute_T>;
20
+
21
+ using T = typename attribute_traits<Attribute_T>::attr_type;
22
+ using Receiver_T = typename attribute_traits<Attribute_T>::class_type;
23
+ using To_Ruby_T = remove_cv_recursive_t<T>;
24
+
25
+ public:
26
+ // Register attribute getter with Ruby
27
+ static void define(VALUE klass, std::string name, Attribute_T attribute);
28
+
29
+ public:
30
+ // Disallow creating/copying/moving
31
+ NativeAttributeGet() = delete;
32
+ NativeAttributeGet(const NativeAttribute_T&) = delete;
33
+ NativeAttributeGet(NativeAttribute_T&&) = delete;
34
+ void operator=(const NativeAttribute_T&) = delete;
35
+ void operator=(NativeAttribute_T&&) = delete;
36
+
37
+ Resolved matches(int argc, const VALUE* argv, VALUE self) override;
38
+ VALUE operator()(int argc, const VALUE* argv, VALUE self) override;
39
+
40
+ protected:
41
+ NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr);
42
+
43
+ private:
44
+ VALUE klass_;
45
+ std::string name_;
46
+ Attribute_T attribute_;
47
+ };
48
+ } // detail
49
+ } // Rice
50
+
51
+ #endif // Rice__detail__Native_Attribute_Get__hpp_
@@ -0,0 +1,51 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+
4
+
5
+ namespace Rice::detail
6
+ {
7
+ template<typename Attribute_T>
8
+ void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute)
9
+ {
10
+ // Create a NativeAttributeGet that Ruby will call to read/write C++ variables
11
+ NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute));
12
+ std::unique_ptr<Native> native(nativeAttribute);
13
+
14
+ detail::protect(rb_define_method, klass, name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
15
+
16
+ // Add to native registry. Since attributes cannot be overridden, there is no need to set the
17
+ // matches or calls function pointer. Instead Ruby can call the static call method defined on
18
+ // this class (&NativeAttribute_T::get).
19
+ Identifier identifier(name);
20
+ detail::Registries::instance.natives.add(klass, identifier.id(), native);
21
+ }
22
+
23
+ template<typename Attribute_T>
24
+ inline Resolved NativeAttributeGet<Attribute_T>::matches(int argc, const VALUE* argv, VALUE self)
25
+ {
26
+ if (argc == 0)
27
+ return Resolved { Convertible::Exact, 1, this };
28
+ else
29
+ return Resolved{ Convertible::None, 0, this };
30
+ }
31
+
32
+ template<typename Attribute_T>
33
+ NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute)
34
+ : klass_(klass), name_(name), attribute_(attribute)
35
+ {
36
+ }
37
+
38
+ template<typename Attribute_T>
39
+ inline VALUE NativeAttributeGet<Attribute_T>::operator()(int argc, const VALUE* argv, VALUE self)
40
+ {
41
+ if constexpr (std::is_member_object_pointer_v<Attribute_T>)
42
+ {
43
+ Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
44
+ return To_Ruby<To_Ruby_T>().convert(nativeSelf->*attribute_);
45
+ }
46
+ else
47
+ {
48
+ return To_Ruby<To_Ruby_T>().convert(*attribute_);
49
+ }
50
+ }
51
+ } // Rice
@@ -0,0 +1,43 @@
1
+ #ifndef Rice__detail__Native_Attribute_Set__hpp_
2
+ #define Rice__detail__Native_Attribute_Set__hpp_
3
+
4
+ namespace Rice
5
+ {
6
+ namespace detail
7
+ {
8
+ template<typename Attribute_T>
9
+ class NativeAttributeSet: Native
10
+ {
11
+ public:
12
+ using NativeAttribute_T = NativeAttributeSet<Attribute_T>;
13
+ using Attr_T = typename attribute_traits<Attribute_T>::attr_type;
14
+ using T_Unqualified = remove_cv_recursive_t<Attr_T>;
15
+ using Receiver_T = typename attribute_traits<Attribute_T>::class_type;
16
+
17
+ public:
18
+ // Register attribute getter/setter with Ruby
19
+ static void define(VALUE klass, std::string name, Attribute_T attribute);
20
+
21
+ public:
22
+ // Disallow creating/copying/moving
23
+ NativeAttributeSet() = delete;
24
+ NativeAttributeSet(const NativeAttribute_T&) = delete;
25
+ NativeAttributeSet(NativeAttribute_T&&) = delete;
26
+ void operator=(const NativeAttribute_T&) = delete;
27
+ void operator=(NativeAttribute_T&&) = delete;
28
+
29
+ Resolved matches(int argc, const VALUE* argv, VALUE self) override;
30
+ VALUE operator()(int argc, const VALUE* argv, VALUE self) override;
31
+
32
+ protected:
33
+ NativeAttributeSet(VALUE klass, std::string name, Attribute_T attr);
34
+
35
+ private:
36
+ VALUE klass_;
37
+ std::string name_;
38
+ Attribute_T attribute_;
39
+ };
40
+ } // detail
41
+ } // Rice
42
+
43
+ #endif // Rice__detail__Native_Attribute_Set__hpp_
@@ -0,0 +1,82 @@
1
+ #include <array>
2
+ #include <algorithm>
3
+
4
+
5
+ namespace Rice::detail
6
+ {
7
+ template<typename Attribute_T>
8
+ void NativeAttributeSet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute)
9
+ {
10
+ // Create a NativeAttributeSet that Ruby will call to read/write C++ variables
11
+ NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute));
12
+ std::unique_ptr<Native> native(nativeAttribute);
13
+
14
+ // Define the write method name
15
+ std::string setter = name + "=";
16
+
17
+ // Tell Ruby to invoke the static method write to get the attribute value
18
+ detail::protect(rb_define_method, klass, setter.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
19
+
20
+ // Add to native registry. Since attributes cannot be overridden, there is no need to set the
21
+ // matches or calls function pointer. Instead Ruby can call the static call method defined on
22
+ // this class (&NativeAttribute_T::set).
23
+ Identifier identifier(setter);
24
+ detail::Registries::instance.natives.add(klass, identifier.id(), native);
25
+ }
26
+
27
+ template<typename Attribute_T>
28
+ NativeAttributeSet<Attribute_T>::NativeAttributeSet(VALUE klass, std::string name, Attribute_T attribute)
29
+ : klass_(klass), name_(name), attribute_(attribute)
30
+ {
31
+ }
32
+
33
+ template<typename Attribute_T>
34
+ inline Resolved NativeAttributeSet<Attribute_T>::matches(int argc, const VALUE* argv, VALUE self)
35
+ {
36
+ if (argc == 1)
37
+ return Resolved{ Convertible::Exact, 1, this };
38
+ else
39
+ return Resolved{ Convertible::None, 0, this };
40
+ }
41
+
42
+ template<typename Attribute_T>
43
+ inline VALUE NativeAttributeSet<Attribute_T>::operator()(int argc, const VALUE* argv, VALUE self)
44
+ {
45
+ if constexpr (std::is_fundamental_v<intrinsic_type<Attr_T>> && std::is_pointer_v<Attr_T>)
46
+ {
47
+ static_assert(true, "An fundamental value, such as an integer, cannot be assigned to an attribute that is a pointer.");
48
+ }
49
+ else if constexpr (std::is_same_v<intrinsic_type<Attr_T>, std::string> && std::is_pointer_v<Attr_T>)
50
+ {
51
+ static_assert(true, "An string cannot be assigned to an attribute that is a pointer.");
52
+ }
53
+
54
+ if (argc != 1)
55
+ {
56
+ throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
57
+ }
58
+
59
+ VALUE value = argv[0];
60
+
61
+ if constexpr (!std::is_null_pointer_v<Receiver_T> &&
62
+ !std::is_const_v<Attr_T> &&
63
+ (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
64
+ {
65
+ Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
66
+ nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
67
+ }
68
+ else if constexpr (std::is_null_pointer_v<Receiver_T> &&
69
+ !std::is_const_v<Attr_T> &&
70
+ (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
71
+ {
72
+ *attribute_ = From_Ruby<T_Unqualified>().convert(value);
73
+ }
74
+ else
75
+ {
76
+ // Should never get here because define_attr won't compile this code, but just in case!
77
+ throw std::invalid_argument("Could not set attribute. Attribute: " + this->name_);
78
+ }
79
+
80
+ return value;
81
+ }
82
+ } // Rice
@@ -0,0 +1,55 @@
1
+ #ifndef Rice__detail__Native_Callback_Ffi_hpp_
2
+ #define Rice__detail__Native_Callback_Ffi_hpp_
3
+
4
+ #ifdef HAVE_LIBFFI
5
+
6
+ #include <ffi.h>
7
+
8
+ namespace Rice::detail
9
+ {
10
+ template<typename Callback_T>
11
+ class NativeCallbackFFI;
12
+
13
+ template<typename Return_T, typename ...Arg_Ts>
14
+ class NativeCallbackFFI<Return_T(*)(Arg_Ts...)>
15
+ {
16
+ public:
17
+ using Callback_T = Return_T(Arg_Ts...);
18
+ using Tuple_T = std::tuple<Arg_Ts...>;
19
+ static void ffiCallback(ffi_cif* cif, void* ret, void* args[], void* instance);
20
+ static VALUE finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
21
+ static void setMethodInfo(MethodInfo* methodInfo);
22
+
23
+ public:
24
+ NativeCallbackFFI(VALUE proc);
25
+ ~NativeCallbackFFI();
26
+ NativeCallbackFFI(const NativeCallbackFFI&) = delete;
27
+ NativeCallbackFFI(NativeCallbackFFI&&) = delete;
28
+ void operator=(const NativeCallbackFFI&) = delete;
29
+ void operator=(NativeCallbackFFI&&) = delete;
30
+
31
+ Return_T operator()(Arg_Ts...args);
32
+ Callback_T* callback();
33
+
34
+ private:
35
+ template <typename Arg_T>
36
+ static ffi_type* ffiType();
37
+
38
+ template<std::size_t... I>
39
+ static Tuple_T convertArgsToTuple(void* args[], std::index_sequence<I...>& indices);
40
+
41
+ static inline std::array<ffi_type*, sizeof...(Arg_Ts)> args_ = { ffiType<Arg_Ts>()... };
42
+ static inline ffi_cif cif_;
43
+ static inline ffi_closure* closure_ = nullptr;
44
+ static inline Callback_T* callback_ = nullptr;
45
+ static inline std::unique_ptr<MethodInfo> methodInfo_ = std::make_unique<MethodInfo>();
46
+
47
+ template<std::size_t... I>
48
+ Return_T callRuby(std::index_sequence<I...>& indices, Arg_Ts...args);
49
+ private:
50
+ VALUE proc_;
51
+ };
52
+ }
53
+ #endif // HAVE_LIBFFI
54
+
55
+ #endif // Rice__detail__Native_Callback_Ffi_hpp_
@@ -0,0 +1,151 @@
1
+ #ifdef HAVE_LIBFFI
2
+ #include <ffi.h>
3
+
4
+ namespace Rice::detail
5
+ {
6
+ template<typename Return_T, typename ...Arg_Ts>
7
+ template<typename Arg_T>
8
+ ffi_type* NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::ffiType()
9
+ {
10
+ std::map<std::type_index, ffi_type*> nativeToFfiMapping = {
11
+ {std::type_index(typeid(bool)), &ffi_type_uint8},
12
+ {std::type_index(typeid(bool)), &ffi_type_uint8},
13
+ {std::type_index(typeid(char)), &ffi_type_schar},
14
+ {std::type_index(typeid(unsigned char)), &ffi_type_uchar},
15
+ {std::type_index(typeid(signed char)), &ffi_type_schar},
16
+ {std::type_index(typeid(uint8_t)), &ffi_type_uint8},
17
+ {std::type_index(typeid(unsigned short)), &ffi_type_uint8},
18
+ {std::type_index(typeid(int8_t)), &ffi_type_sint8},
19
+ {std::type_index(typeid(short)), &ffi_type_sint8},
20
+ {std::type_index(typeid(uint16_t)), &ffi_type_uint16},
21
+ {std::type_index(typeid(int16_t)), &ffi_type_sint16},
22
+ {std::type_index(typeid(uint32_t)), &ffi_type_uint32},
23
+ {std::type_index(typeid(unsigned int)), &ffi_type_uint32},
24
+ {std::type_index(typeid(signed int)), &ffi_type_uint32},
25
+ {std::type_index(typeid(int32_t)), &ffi_type_sint32},
26
+ {std::type_index(typeid(uint64_t)), &ffi_type_uint64},
27
+ {std::type_index(typeid(unsigned long long)), &ffi_type_uint64},
28
+ {std::type_index(typeid(int64_t)), &ffi_type_sint64},
29
+ {std::type_index(typeid(signed long long)), &ffi_type_sint64},
30
+ {std::type_index(typeid(float)), &ffi_type_float},
31
+ {std::type_index(typeid(double)), &ffi_type_double},
32
+ {std::type_index(typeid(void)), &ffi_type_pointer},
33
+ {std::type_index(typeid(long double)), &ffi_type_longdouble}
34
+ };
35
+
36
+ if (sizeof(long) == 32)
37
+ {
38
+ nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint32;
39
+ nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint32;
40
+ }
41
+ else if (sizeof(long) == 64)
42
+ {
43
+ nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint64;
44
+ nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint64;
45
+ }
46
+
47
+ if (std::is_pointer_v<Arg_T>)
48
+ {
49
+ return &ffi_type_pointer;
50
+ }
51
+ else
52
+ {
53
+ const std::type_index& key = std::type_index(typeid(Arg_T));
54
+ return nativeToFfiMapping[key];
55
+ }
56
+ }
57
+
58
+ template<typename Return_T, typename ...Arg_Ts>
59
+ template<std::size_t... I>
60
+ typename NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::Tuple_T NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::convertArgsToTuple(void* args[], std::index_sequence<I...>& indices)
61
+ {
62
+ /* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
63
+ on the arguments (Arg_Ts) required by the C++ function. Arg_T may have const/volatile while
64
+ the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
65
+ which we let the compiler convert to const values as needed. This works except for
66
+ T** -> const T**, see comment in getNativeValue method. */
67
+ return std::forward_as_tuple(*(std::tuple_element_t<I, Tuple_T>*)(args[I])...);
68
+ }
69
+
70
+ template<typename Return_T, typename ...Arg_Ts>
71
+ void NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::ffiCallback(ffi_cif* cif, void* ret, void* args[], void* instance)
72
+ {
73
+ using Self_T = NativeCallbackFFI<Return_T(*)(Arg_Ts...)>;
74
+ Self_T* self = (Self_T*)instance;
75
+
76
+ auto indices = std::make_index_sequence<sizeof...(Arg_Ts)>{};
77
+
78
+ if constexpr (sizeof...(Arg_Ts) == 0)
79
+ {
80
+ *(Return_T*)ret = self->operator()();
81
+ }
82
+ else
83
+ {
84
+ std::tuple<Arg_Ts...> tuple = convertArgsToTuple(args, indices);
85
+ *(Return_T*)ret = std::apply(*self, tuple);
86
+ }
87
+ }
88
+
89
+ template<typename Return_T, typename ...Arg_Ts>
90
+ void NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::setMethodInfo(MethodInfo* methodInfo)
91
+ {
92
+ methodInfo_.reset(methodInfo);
93
+ }
94
+
95
+ template<typename Return_T, typename ...Arg_Ts>
96
+ NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::~NativeCallbackFFI()
97
+ {
98
+ this->proc_ = Qnil;
99
+ }
100
+
101
+ template<typename Return_T, typename ...Arg_Ts>
102
+ VALUE NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
103
+ {
104
+ using NativeCallback_T = NativeCallbackFFI<Return_T(*)(Arg_Ts...)>;
105
+ NativeCallback_T* nativeCallback = (NativeCallback_T*)callback_arg;
106
+ delete nativeCallback;
107
+ return Qnil;
108
+ }
109
+
110
+ template<typename Return_T, typename ...Arg_Ts>
111
+ NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::NativeCallbackFFI(VALUE proc) : proc_(proc)
112
+ {
113
+ // First setup desccription of callback
114
+ if (cif_.bytes == 0)
115
+ {
116
+ ffi_prep_cif(&cif_, FFI_DEFAULT_ABI, sizeof...(Arg_Ts), &ffi_type_pointer, args_.data());
117
+ }
118
+
119
+ // Create FFI closure
120
+ this->closure_ = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), (void**)(&this->callback_));
121
+ ffi_status status = ffi_prep_closure_loc(this->closure_, &cif_, ffiCallback, (void*)this, (void*)this->callback_);
122
+ }
123
+
124
+ template<typename Return_T, typename ...Arg_Ts>
125
+ typename NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::Callback_T* NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::callback()
126
+ {
127
+ return (Callback_T*)this->callback_;
128
+ }
129
+
130
+ template<typename Return_T, typename ...Arg_Ts>
131
+ template<std::size_t... I>
132
+ Return_T NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::callRuby(std::index_sequence<I...>& indices, Arg_Ts...args)
133
+ {
134
+ static Identifier id("call");
135
+ std::array<VALUE, sizeof...(Arg_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>(methodInfo_->arg(I)).convert(args)... };
136
+ VALUE result = detail::protect(rb_funcallv, this->proc_, id.id(), (int)sizeof...(Arg_Ts), values.data());
137
+ if constexpr (!std::is_void_v<Return_T>)
138
+ {
139
+ static From_Ruby<Return_T> fromRuby(dynamic_cast<Arg*>(&methodInfo_->returnInfo));
140
+ return fromRuby.convert(result);
141
+ }
142
+ }
143
+
144
+ template<typename Return_T, typename ...Arg_Ts>
145
+ Return_T NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::operator()(Arg_Ts...args)
146
+ {
147
+ auto indices = std::make_index_sequence<sizeof...(Arg_Ts)>{};
148
+ return NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::callRuby(indices, args...);
149
+ }
150
+ }
151
+ #endif // HAVE_LIBFFI
@@ -0,0 +1,30 @@
1
+ #ifndef Rice__detail__Native_Callback_Simple_hpp_
2
+ #define Rice__detail__Native_Callback_Simple_hpp_
3
+
4
+ namespace Rice::detail
5
+ {
6
+ template<typename Callback_T>
7
+ class NativeCallbackSimple;
8
+
9
+ template<typename Return_T, typename ...Arg_Ts>
10
+ class NativeCallbackSimple<Return_T(*)(Arg_Ts...)>
11
+ {
12
+ public:
13
+ static Return_T callback(Arg_Ts...args);
14
+ static inline VALUE proc = Qnil;
15
+ static void setMethodInfo(MethodInfo* methodInfo);
16
+
17
+ public:
18
+ NativeCallbackSimple() = delete;
19
+ NativeCallbackSimple(const NativeCallbackSimple&) = delete;
20
+ NativeCallbackSimple(NativeCallbackSimple&&) = delete;
21
+ void operator=(const NativeCallbackSimple&) = delete;
22
+ void operator=(NativeCallbackSimple&&) = delete;
23
+
24
+ private:
25
+ template<std::size_t... I>
26
+ static Return_T callRuby(std::index_sequence<I...>& indices, Arg_Ts...args);
27
+ static inline std::unique_ptr<MethodInfo> methodInfo_ = std::make_unique<MethodInfo>();
28
+ };
29
+ }
30
+ #endif // Rice__detail__Native_Callback_Simple_hpp_
@@ -0,0 +1,29 @@
1
+ namespace Rice::detail
2
+ {
3
+ template<typename Return_T, typename ...Arg_Ts>
4
+ void NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::setMethodInfo(MethodInfo* methodInfo)
5
+ {
6
+ methodInfo_.reset(methodInfo);
7
+ }
8
+
9
+ template<typename Return_T, typename ...Arg_Ts>
10
+ template<std::size_t... I>
11
+ Return_T NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::callRuby(std::index_sequence<I...>& indices, Arg_Ts...args)
12
+ {
13
+ static Identifier id("call");
14
+ std::array<VALUE, sizeof...(Arg_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>(methodInfo_->arg(I)).convert(args)... };
15
+ VALUE result = detail::protect(rb_funcallv, proc, id.id(), (int)sizeof...(Arg_Ts), values.data());
16
+ if constexpr (!std::is_void_v<Return_T>)
17
+ {
18
+ static From_Ruby<Return_T> fromRuby(dynamic_cast<Arg*>(&methodInfo_->returnInfo));
19
+ return fromRuby.convert(result);
20
+ }
21
+ }
22
+
23
+ template<typename Return_T, typename ...Arg_Ts>
24
+ Return_T NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::callback(Arg_Ts...args)
25
+ {
26
+ auto indices = std::make_index_sequence<sizeof...(Arg_Ts)>{};
27
+ return NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::callRuby(indices, args...);
28
+ }
29
+ }
@@ -1,13 +1,6 @@
1
1
  #ifndef Rice__detail__Native_Function__hpp_
2
2
  #define Rice__detail__Native_Function__hpp_
3
3
 
4
- #include "ruby.hpp"
5
- #include "ExceptionHandler_defn.hpp"
6
- #include "MethodInfo.hpp"
7
- #include "../traits/function_traits.hpp"
8
- #include "../traits/method_traits.hpp"
9
- #include "from_ruby.hpp"
10
-
11
4
  namespace Rice::detail
12
5
  {
13
6
  //! The NativeFunction class calls C++ functions/methods/lambdas on behalf of Ruby
@@ -43,24 +36,26 @@ namespace Rice::detail
43
36
  */
44
37
 
45
38
  template<typename Class_T, typename Function_T, bool IsMethod>
46
- class NativeFunction
39
+ class NativeFunction: Native
47
40
  {
48
41
  public:
49
42
  using NativeFunction_T = NativeFunction<Class_T, Function_T, IsMethod>;
50
43
 
51
44
  // We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
52
45
  // have the concept of constants anyways
53
- using Return_T = remove_cv_recursive_t<typename function_traits<Function_T>::return_type>;
46
+ using Return_T = typename function_traits<Function_T>::return_type;
54
47
  using Receiver_T = typename method_traits<Function_T, IsMethod>::Class_T;
55
48
  using Arg_Ts = typename method_traits<Function_T, IsMethod>::Arg_Ts;
49
+ static constexpr std::size_t arity = method_traits<Function_T, IsMethod>::arity;
56
50
  using From_Ruby_Args_Ts = typename tuple_map<From_Ruby, Arg_Ts>::type;
51
+ using To_Ruby_T = remove_cv_recursive_t<Return_T>;
57
52
 
58
53
  // Register function with Ruby
59
54
  static void define(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
60
55
 
61
- // Static member function that Ruby calls
62
- static VALUE call(int argc, VALUE* argv, VALUE self);
63
-
56
+ // Proc entry
57
+ static VALUE procEntry(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
58
+ static VALUE finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
64
59
  public:
65
60
  // Disallow creating/copying/moving
66
61
  NativeFunction() = delete;
@@ -69,11 +64,12 @@ namespace Rice::detail
69
64
  void operator=(const NativeFunction_T&) = delete;
70
65
  void operator=(NativeFunction_T&&) = delete;
71
66
 
72
- // Invokes the wrapped function
73
- VALUE operator()(int argc, VALUE* argv, VALUE self);
67
+ Resolved matches(int argc, const VALUE* argv, VALUE self) override;
68
+ VALUE operator()(int argc, const VALUE* argv, VALUE self) override;
74
69
 
75
- protected:
70
+ NativeFunction(Function_T function);
76
71
  NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
72
+ protected:
77
73
 
78
74
  private:
79
75
  template<typename T, std::size_t I>
@@ -83,10 +79,14 @@ namespace Rice::detail
83
79
  template<std::size_t...I>
84
80
  From_Ruby_Args_Ts createFromRuby(std::index_sequence<I...>& indices);
85
81
 
86
- To_Ruby<Return_T> createToRuby();
82
+ // Convert C++ value to Ruby
83
+ To_Ruby<To_Ruby_T> createToRuby();
87
84
 
88
85
  // Convert Ruby argv pointer to Ruby values
89
- std::vector<VALUE> getRubyValues(int argc, VALUE* argv);
86
+ std::vector<VALUE> getRubyValues(int argc, const VALUE* argv, bool validate);
87
+
88
+ template<typename Arg_T, int I>
89
+ Arg_T getNativeValue(std::vector<VALUE>& values);
90
90
 
91
91
  // Convert Ruby values to C++ values
92
92
  template<typename std::size_t...I>
@@ -102,18 +102,17 @@ namespace Rice::detail
102
102
  void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues);
103
103
 
104
104
  // Call the underlying C++ function
105
- VALUE invokeNativeFunction(const Arg_Ts& nativeArgs);
106
- VALUE invokeNativeMethod(VALUE self, const Arg_Ts& nativeArgs);
105
+ VALUE invokeNativeFunction(Arg_Ts&& nativeArgs);
106
+ VALUE invokeNativeMethod(VALUE self, Arg_Ts&& nativeArgs);
107
107
 
108
108
  private:
109
109
  VALUE klass_;
110
110
  std::string method_name_;
111
111
  Function_T function_;
112
112
  From_Ruby_Args_Ts fromRubys_;
113
- To_Ruby<Return_T> toRuby_;
113
+ To_Ruby<To_Ruby_T> toRuby_;
114
114
  std::unique_ptr<MethodInfo> methodInfo_;
115
115
  };
116
116
  }
117
- #include "NativeFunction.ipp"
118
117
 
119
118
  #endif // Rice__detail__Native_Function__hpp_