rice 4.3.3 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
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_