rice 4.7.1 → 4.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -1
- data/CMakeLists.txt +14 -22
- data/CMakePresets.json +203 -75
- data/FindRuby.cmake +358 -123
- data/bin/rice-doc.rb +56 -141
- data/include/rice/api.hpp +248 -0
- data/include/rice/rice.hpp +2237 -1657
- data/include/rice/stl.hpp +346 -443
- data/lib/rice/doc/config.rb +70 -0
- data/lib/rice/doc/cpp_reference.rb +1 -4
- data/lib/rice/doc/mkdocs.rb +58 -20
- data/lib/rice/doc/rice.rb +20 -0
- data/lib/rice/doc.rb +1 -0
- data/lib/rice/make_rice_headers.rb +7 -0
- data/lib/rice/native_registry.rb +2 -2
- data/lib/rice/rbs.rb +2 -2
- data/lib/rice/version.rb +1 -1
- data/lib/rubygems_plugin.rb +12 -9
- data/rice/Arg.hpp +12 -6
- data/rice/Arg.ipp +14 -7
- data/rice/Buffer.ipp +44 -40
- data/rice/Callback.hpp +1 -1
- data/rice/Callback.ipp +2 -7
- data/rice/Constructor.hpp +1 -1
- data/rice/Constructor.ipp +11 -11
- data/rice/Data_Object.ipp +15 -15
- data/rice/Data_Type.hpp +9 -10
- data/rice/Data_Type.ipp +22 -25
- data/rice/Director.hpp +1 -0
- data/rice/Enum.ipp +58 -39
- data/rice/Exception.hpp +4 -4
- data/rice/Exception.ipp +7 -7
- data/rice/NoGVL.hpp +13 -0
- data/rice/Reference.hpp +56 -0
- data/rice/Reference.ipp +96 -0
- data/rice/Return.hpp +4 -1
- data/rice/Return.ipp +0 -6
- data/rice/cpp_api/Array.hpp +41 -4
- data/rice/cpp_api/Array.ipp +105 -9
- data/rice/cpp_api/Class.hpp +2 -2
- data/rice/cpp_api/Class.ipp +4 -4
- data/rice/cpp_api/Hash.ipp +7 -4
- data/rice/cpp_api/Module.hpp +4 -4
- data/rice/cpp_api/Module.ipp +12 -10
- data/rice/cpp_api/Object.hpp +4 -4
- data/rice/cpp_api/Object.ipp +15 -12
- data/rice/cpp_api/String.hpp +2 -2
- data/rice/cpp_api/String.ipp +11 -8
- data/rice/cpp_api/Symbol.ipp +7 -7
- data/rice/cpp_api/shared_methods.hpp +5 -9
- data/rice/detail/InstanceRegistry.hpp +0 -2
- data/rice/detail/Native.hpp +31 -21
- data/rice/detail/Native.ipp +282 -130
- data/rice/detail/NativeAttributeGet.hpp +5 -7
- data/rice/detail/NativeAttributeGet.ipp +26 -26
- data/rice/detail/NativeAttributeSet.hpp +2 -4
- data/rice/detail/NativeAttributeSet.ipp +20 -16
- data/rice/detail/NativeCallback.hpp +77 -0
- data/rice/detail/NativeCallback.ipp +280 -0
- data/rice/detail/NativeFunction.hpp +11 -21
- data/rice/detail/NativeFunction.ipp +58 -119
- data/rice/detail/NativeInvoker.hpp +4 -4
- data/rice/detail/NativeInvoker.ipp +7 -7
- data/rice/detail/NativeIterator.hpp +2 -4
- data/rice/detail/NativeIterator.ipp +18 -14
- data/rice/detail/NativeMethod.hpp +10 -20
- data/rice/detail/NativeMethod.ipp +54 -114
- data/rice/detail/NativeProc.hpp +5 -7
- data/rice/detail/NativeProc.ipp +39 -28
- data/rice/detail/NativeRegistry.hpp +0 -1
- data/rice/detail/Parameter.hpp +15 -8
- data/rice/detail/Parameter.ipp +102 -43
- data/rice/detail/Proc.ipp +14 -28
- data/rice/detail/RubyType.ipp +2 -53
- data/rice/detail/Type.hpp +23 -7
- data/rice/detail/Type.ipp +73 -93
- data/rice/detail/TypeRegistry.ipp +5 -4
- data/rice/detail/Wrapper.hpp +1 -1
- data/rice/detail/Wrapper.ipp +18 -10
- data/rice/detail/from_ruby.hpp +8 -6
- data/rice/detail/from_ruby.ipp +306 -173
- data/rice/detail/ruby.hpp +23 -0
- data/rice/libc/file.hpp +4 -4
- data/rice/rice.hpp +6 -8
- data/rice/rice_api/Native.ipp +5 -1
- data/rice/rice_api/Parameter.ipp +1 -1
- data/rice/ruby_mark.hpp +2 -1
- data/rice/stl/complex.ipp +12 -8
- data/rice/stl/map.ipp +27 -22
- data/rice/stl/monostate.ipp +16 -12
- data/rice/stl/multimap.hpp +0 -2
- data/rice/stl/multimap.ipp +27 -22
- data/rice/stl/optional.ipp +27 -11
- data/rice/stl/pair.ipp +5 -5
- data/rice/stl/reference_wrapper.ipp +5 -4
- data/rice/stl/set.ipp +16 -16
- data/rice/stl/shared_ptr.hpp +0 -16
- data/rice/stl/shared_ptr.ipp +34 -190
- data/rice/stl/string.ipp +18 -18
- data/rice/stl/string_view.ipp +1 -1
- data/rice/stl/tuple.ipp +15 -36
- data/rice/stl/unique_ptr.ipp +18 -8
- data/rice/stl/unordered_map.ipp +20 -15
- data/rice/stl/variant.ipp +37 -21
- data/rice/stl/vector.ipp +41 -36
- data/rice/traits/function_traits.hpp +19 -19
- data/rice/traits/method_traits.hpp +4 -4
- data/rice/traits/rice_traits.hpp +162 -39
- data/rice.gemspec +1 -3
- data/test/test_Array.cpp +261 -3
- data/test/test_Attribute.cpp +6 -3
- data/test/test_Buffer.cpp +6 -42
- data/test/test_Callback.cpp +77 -23
- data/test/test_Data_Object.cpp +1 -1
- data/test/test_Data_Type.cpp +21 -22
- data/test/test_Director.cpp +2 -4
- data/test/test_Enum.cpp +34 -5
- data/test/test_File.cpp +9 -5
- data/test/test_From_Ruby.cpp +4 -3
- data/test/test_GVL.cpp +3 -3
- data/test/test_Hash.cpp +1 -1
- data/test/test_Iterator.cpp +54 -22
- data/test/test_Keep_Alive.cpp +1 -1
- data/test/test_Keep_Alive_No_Wrapper.cpp +1 -1
- data/test/test_Module.cpp +5 -5
- data/test/test_Overloads.cpp +345 -48
- data/test/test_Proc.cpp +54 -0
- data/test/test_Reference.cpp +181 -0
- data/test/test_Self.cpp +2 -2
- data/test/test_Stl_Set.cpp +6 -6
- data/test/test_Stl_SharedPtr.cpp +54 -30
- data/test/test_Stl_String_View.cpp +4 -2
- data/test/test_Stl_Tuple.cpp +1 -1
- data/test/test_Stl_Variant.cpp +6 -14
- data/test/test_Stl_Vector.cpp +61 -30
- data/test/test_String.cpp +4 -2
- data/test/test_Struct.cpp +1 -1
- data/test/test_Symbol.cpp +1 -1
- data/test/test_To_Ruby.cpp +1 -0
- data/test/test_Type.cpp +36 -35
- data/test/test_global_functions.cpp +1 -1
- data/test/unittest.cpp +1 -1
- data/test/unittest.hpp +5 -5
- metadata +10 -10
- data/rice/Function.hpp +0 -17
- data/rice/Function.ipp +0 -13
- data/rice/detail/MethodInfo.hpp +0 -48
- data/rice/detail/MethodInfo.ipp +0 -99
- data/rice/detail/NativeCallbackFFI.hpp +0 -55
- data/rice/detail/NativeCallbackFFI.ipp +0 -152
- data/rice/detail/NativeCallbackSimple.hpp +0 -30
- data/rice/detail/NativeCallbackSimple.ipp +0 -29
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
namespace Rice::detail
|
|
5
5
|
{
|
|
6
6
|
template<typename Attribute_T>
|
|
7
|
-
|
|
7
|
+
template<typename...Arg_Ts>
|
|
8
|
+
void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute, Arg_Ts&...args)
|
|
8
9
|
{
|
|
9
10
|
// Verify attribute type
|
|
10
|
-
Native::verify_type<Attr_T
|
|
11
|
+
Native::verify_type<Attr_T, is_one_of_v<ReturnBuffer, Arg_Ts...>>();
|
|
12
|
+
|
|
13
|
+
// Create return info
|
|
14
|
+
std::unique_ptr<Return> returnInfo = Native::create_return<Arg_Ts...>(args...);
|
|
11
15
|
|
|
12
16
|
// Create a NativeAttributeGet that Ruby will call to read/write C++ variables
|
|
13
|
-
NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute), returnInfo);
|
|
17
|
+
NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute), std::move(returnInfo));
|
|
14
18
|
std::unique_ptr<Native> native(nativeAttribute);
|
|
15
19
|
|
|
16
20
|
detail::protect(rb_define_method, klass, name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
|
|
@@ -23,22 +27,23 @@ namespace Rice::detail
|
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
template<typename Attribute_T>
|
|
26
|
-
inline Resolved NativeAttributeGet<Attribute_T>::matches(
|
|
30
|
+
inline Resolved NativeAttributeGet<Attribute_T>::matches(std::map<std::string, VALUE>& values)
|
|
27
31
|
{
|
|
28
|
-
if (
|
|
29
|
-
return Resolved
|
|
32
|
+
if (values.size() == 0)
|
|
33
|
+
return Resolved{ Convertible::Exact, this };
|
|
30
34
|
else
|
|
31
|
-
return Resolved{ Convertible::None,
|
|
35
|
+
return Resolved{ Convertible::None, this };
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
template<typename Attribute_T>
|
|
35
|
-
NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute, Return returnInfo)
|
|
36
|
-
:
|
|
39
|
+
NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute, std::unique_ptr<Return>&& returnInfo)
|
|
40
|
+
: Native(name, std::move(returnInfo)),
|
|
41
|
+
klass_(klass), attribute_(attribute)
|
|
37
42
|
{
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
template<typename Attribute_T>
|
|
41
|
-
inline VALUE NativeAttributeGet<Attribute_T>::operator()(
|
|
46
|
+
inline VALUE NativeAttributeGet<Attribute_T>::operator()(std::map<std::string, VALUE>&, VALUE self)
|
|
42
47
|
{
|
|
43
48
|
if constexpr (std::is_member_object_pointer_v<Attribute_T>)
|
|
44
49
|
{
|
|
@@ -46,42 +51,42 @@ namespace Rice::detail
|
|
|
46
51
|
|
|
47
52
|
if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>>)
|
|
48
53
|
{
|
|
49
|
-
return To_Ruby<To_Ruby_T>(
|
|
54
|
+
return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
|
|
50
55
|
}
|
|
51
56
|
else if constexpr (std::is_array_v<To_Ruby_T>)
|
|
52
57
|
{
|
|
53
|
-
return To_Ruby<To_Ruby_T>(
|
|
58
|
+
return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
|
|
54
59
|
}
|
|
55
60
|
else if constexpr (std::is_pointer_v<To_Ruby_T>)
|
|
56
61
|
{
|
|
57
|
-
return To_Ruby<To_Ruby_T>(
|
|
62
|
+
return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
|
|
58
63
|
}
|
|
59
64
|
else
|
|
60
65
|
{
|
|
61
66
|
// If the attribute is an object return a reference to avoid a copy (and avoid issues with
|
|
62
67
|
// attributes that are not assignable, copy constructible or move constructible)
|
|
63
|
-
return To_Ruby<To_Ruby_T&>(
|
|
68
|
+
return To_Ruby<To_Ruby_T&>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
71
|
else
|
|
67
72
|
{
|
|
68
73
|
if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>>)
|
|
69
74
|
{
|
|
70
|
-
return To_Ruby<To_Ruby_T>(
|
|
75
|
+
return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(*attribute_);
|
|
71
76
|
}
|
|
72
77
|
else if constexpr (std::is_array_v<To_Ruby_T>)
|
|
73
78
|
{
|
|
74
|
-
return To_Ruby<To_Ruby_T>(
|
|
79
|
+
return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(*attribute_);
|
|
75
80
|
}
|
|
76
81
|
else if constexpr (std::is_pointer_v<To_Ruby_T>)
|
|
77
82
|
{
|
|
78
|
-
return To_Ruby<To_Ruby_T>(
|
|
83
|
+
return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(*attribute_);
|
|
79
84
|
}
|
|
80
85
|
else
|
|
81
86
|
{
|
|
82
87
|
// If the attribute is an object return a reference to avoid a copy (and avoid issues with
|
|
83
88
|
// attributes that are not assignable, copy constructible or move constructible)
|
|
84
|
-
return To_Ruby<To_Ruby_T&>(
|
|
89
|
+
return To_Ruby<To_Ruby_T&>(this->returnInfo_.get()).convert(*attribute_);
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
}
|
|
@@ -92,12 +97,6 @@ namespace Rice::detail
|
|
|
92
97
|
return "";
|
|
93
98
|
}
|
|
94
99
|
|
|
95
|
-
template<typename Attribute_T>
|
|
96
|
-
inline std::string NativeAttributeGet<Attribute_T>::name()
|
|
97
|
-
{
|
|
98
|
-
return this->name_;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
100
|
template<typename Attribute_T>
|
|
102
101
|
inline NativeKind NativeAttributeGet<Attribute_T>::kind()
|
|
103
102
|
{
|
|
@@ -108,9 +107,10 @@ namespace Rice::detail
|
|
|
108
107
|
inline VALUE NativeAttributeGet<Attribute_T>::returnKlass()
|
|
109
108
|
{
|
|
110
109
|
// Check if an array is being returned
|
|
111
|
-
|
|
110
|
+
bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
|
|
111
|
+
if (isBuffer)
|
|
112
112
|
{
|
|
113
|
-
TypeMapper<Pointer<Attr_T
|
|
113
|
+
TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Attr_T>>>> typeMapper;
|
|
114
114
|
return typeMapper.rubyKlass();
|
|
115
115
|
}
|
|
116
116
|
else
|
|
@@ -26,11 +26,10 @@ namespace Rice
|
|
|
26
26
|
void operator=(const NativeAttribute_T&) = delete;
|
|
27
27
|
void operator=(NativeAttribute_T&&) = delete;
|
|
28
28
|
|
|
29
|
-
Resolved matches(
|
|
30
|
-
VALUE operator()(
|
|
29
|
+
Resolved matches(std::map<std::string, VALUE>& values) override;
|
|
30
|
+
VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
|
|
31
31
|
std::string toString() override;
|
|
32
32
|
|
|
33
|
-
std::string name() override;
|
|
34
33
|
NativeKind kind() override;
|
|
35
34
|
VALUE returnKlass() override;
|
|
36
35
|
|
|
@@ -39,7 +38,6 @@ namespace Rice
|
|
|
39
38
|
|
|
40
39
|
private:
|
|
41
40
|
VALUE klass_;
|
|
42
|
-
std::string name_;
|
|
43
41
|
Attribute_T attribute_;
|
|
44
42
|
};
|
|
45
43
|
} // detail
|
|
@@ -26,28 +26,28 @@ namespace Rice::detail
|
|
|
26
26
|
|
|
27
27
|
template<typename Attribute_T>
|
|
28
28
|
NativeAttributeSet<Attribute_T>::NativeAttributeSet(VALUE klass, std::string name, Attribute_T attribute)
|
|
29
|
-
:
|
|
29
|
+
: Native(name), klass_(klass), attribute_(attribute)
|
|
30
30
|
{
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
template<typename Attribute_T>
|
|
34
|
-
inline Resolved NativeAttributeSet<Attribute_T>::matches(
|
|
34
|
+
inline Resolved NativeAttributeSet<Attribute_T>::matches(std::map<std::string, VALUE>& values)
|
|
35
35
|
{
|
|
36
|
-
if (
|
|
37
|
-
return Resolved{ Convertible::Exact,
|
|
36
|
+
if (values.size() == 1)
|
|
37
|
+
return Resolved{ Convertible::Exact, this };
|
|
38
38
|
else
|
|
39
|
-
return Resolved{ Convertible::None,
|
|
39
|
+
return Resolved{ Convertible::None, this };
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
template<typename Attribute_T>
|
|
43
|
-
inline VALUE NativeAttributeSet<Attribute_T>::operator()(
|
|
43
|
+
inline VALUE NativeAttributeSet<Attribute_T>::operator()(std::map<std::string, VALUE>& values, VALUE self)
|
|
44
44
|
{
|
|
45
|
-
if (
|
|
45
|
+
if (values.size() != 1)
|
|
46
46
|
{
|
|
47
47
|
throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
VALUE value =
|
|
50
|
+
VALUE value = values.begin()->second;
|
|
51
51
|
|
|
52
52
|
if constexpr (!std::is_null_pointer_v<Receiver_T>)
|
|
53
53
|
{
|
|
@@ -77,12 +77,6 @@ namespace Rice::detail
|
|
|
77
77
|
return "";
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
template<typename Attribute_T>
|
|
81
|
-
inline std::string NativeAttributeSet<Attribute_T>::name()
|
|
82
|
-
{
|
|
83
|
-
return this->name_;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
80
|
template<typename Attribute_T>
|
|
87
81
|
inline NativeKind NativeAttributeSet<Attribute_T>::kind()
|
|
88
82
|
{
|
|
@@ -92,7 +86,17 @@ namespace Rice::detail
|
|
|
92
86
|
template<typename Attribute_T>
|
|
93
87
|
inline VALUE NativeAttributeSet<Attribute_T>::returnKlass()
|
|
94
88
|
{
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
// Check if an array is being returned
|
|
90
|
+
bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
|
|
91
|
+
if (isBuffer)
|
|
92
|
+
{
|
|
93
|
+
TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Attr_T>>>> typeMapper;
|
|
94
|
+
return typeMapper.rubyKlass();
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
{
|
|
98
|
+
TypeMapper<Attr_T> typeMapper;
|
|
99
|
+
return typeMapper.rubyKlass();
|
|
100
|
+
}
|
|
97
101
|
}
|
|
98
102
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#ifndef Rice__detail__Native_Callback_Ffi_hpp_
|
|
2
|
+
#define Rice__detail__Native_Callback_Ffi_hpp_
|
|
3
|
+
|
|
4
|
+
#ifdef HAVE_LIBFFI
|
|
5
|
+
#include <ffi.h>
|
|
6
|
+
#endif //HAVE_LIBFFI
|
|
7
|
+
|
|
8
|
+
namespace Rice::detail
|
|
9
|
+
{
|
|
10
|
+
template<typename Callback_T>
|
|
11
|
+
class NativeCallback;
|
|
12
|
+
|
|
13
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
14
|
+
class NativeCallback<Return_T(*)(Parameter_Ts...)> : public Native
|
|
15
|
+
{
|
|
16
|
+
public:
|
|
17
|
+
using Callback_T = Return_T(*)(Parameter_Ts...);
|
|
18
|
+
using NativeCallback_T = NativeCallback<Callback_T>;
|
|
19
|
+
using Tuple_T = std::tuple<Parameter_Ts...>;
|
|
20
|
+
|
|
21
|
+
static VALUE finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
|
|
22
|
+
|
|
23
|
+
template<typename ...Arg_Ts>
|
|
24
|
+
static void define(Arg_Ts&& ...args);
|
|
25
|
+
|
|
26
|
+
static Return_T invoke(Parameter_Ts...args);
|
|
27
|
+
public:
|
|
28
|
+
NativeCallback(VALUE proc);
|
|
29
|
+
~NativeCallback();
|
|
30
|
+
NativeCallback(const NativeCallback&) = delete;
|
|
31
|
+
NativeCallback(NativeCallback&&) = delete;
|
|
32
|
+
void operator=(const NativeCallback&) = delete;
|
|
33
|
+
void operator=(NativeCallback&&) = delete;
|
|
34
|
+
|
|
35
|
+
Callback_T callback();
|
|
36
|
+
private:
|
|
37
|
+
template<typename Parameter_T>
|
|
38
|
+
static Parameter_T extractArg(void* arg);
|
|
39
|
+
|
|
40
|
+
template<std::size_t... I>
|
|
41
|
+
static Tuple_T convertArgsToTuple(void* args[], std::index_sequence<I...>& indices);
|
|
42
|
+
Callback_T callback_ = nullptr;
|
|
43
|
+
|
|
44
|
+
template<std::size_t... I>
|
|
45
|
+
static void copyParametersImpl(std::vector<std::unique_ptr<ParameterAbstract>>& result, std::index_sequence<I...> indices);
|
|
46
|
+
static std::vector<std::unique_ptr<ParameterAbstract>> copyParameters();
|
|
47
|
+
static std::unique_ptr<Return> copyReturnInfo();
|
|
48
|
+
|
|
49
|
+
static inline std::vector<std::unique_ptr<ParameterAbstract>> parameters_;
|
|
50
|
+
static inline std::unique_ptr<Return> returnInfo_;
|
|
51
|
+
static inline NativeCallback_T* native_;
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
|
|
55
|
+
std::string toString() override;
|
|
56
|
+
NativeKind kind() override;
|
|
57
|
+
VALUE returnKlass() override;
|
|
58
|
+
|
|
59
|
+
template<std::size_t... I>
|
|
60
|
+
Return_T callRuby(std::index_sequence<I...>& indices, Parameter_Ts...args);
|
|
61
|
+
|
|
62
|
+
VALUE proc_;
|
|
63
|
+
From_Ruby<Return_T> fromRuby_;
|
|
64
|
+
|
|
65
|
+
#ifdef HAVE_LIBFFI
|
|
66
|
+
template <typename Arg_T>
|
|
67
|
+
static ffi_type* ffiType();
|
|
68
|
+
|
|
69
|
+
static void invokeFFI(ffi_cif* cif, void* ret, void* args[], void* instance);
|
|
70
|
+
|
|
71
|
+
static inline std::array<ffi_type*, sizeof...(Parameter_Ts)> args_ = { ffiType<Parameter_Ts>()... };
|
|
72
|
+
static inline ffi_cif cif_;
|
|
73
|
+
ffi_closure* closure_ = nullptr;
|
|
74
|
+
#endif //HAVE_LIBFFI
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
#endif // Rice__detail__Native_Callback_Ffi_hpp_
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
namespace Rice::detail
|
|
2
|
+
{
|
|
3
|
+
#ifdef HAVE_LIBFFI
|
|
4
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
5
|
+
template<typename Arg_T>
|
|
6
|
+
ffi_type* NativeCallback<Return_T(*)(Parameter_Ts...)>::ffiType()
|
|
7
|
+
{
|
|
8
|
+
std::map<std::type_index, ffi_type*> nativeToFfiMapping = {
|
|
9
|
+
{std::type_index(typeid(bool)), &ffi_type_uint8},
|
|
10
|
+
{std::type_index(typeid(bool)), &ffi_type_uint8},
|
|
11
|
+
{std::type_index(typeid(char)), &ffi_type_schar},
|
|
12
|
+
{std::type_index(typeid(unsigned char)), &ffi_type_uchar},
|
|
13
|
+
{std::type_index(typeid(signed char)), &ffi_type_schar},
|
|
14
|
+
{std::type_index(typeid(uint8_t)), &ffi_type_uint8},
|
|
15
|
+
{std::type_index(typeid(unsigned short)), &ffi_type_uint8},
|
|
16
|
+
{std::type_index(typeid(int8_t)), &ffi_type_sint8},
|
|
17
|
+
{std::type_index(typeid(short)), &ffi_type_sint8},
|
|
18
|
+
{std::type_index(typeid(uint16_t)), &ffi_type_uint16},
|
|
19
|
+
{std::type_index(typeid(int16_t)), &ffi_type_sint16},
|
|
20
|
+
{std::type_index(typeid(uint32_t)), &ffi_type_uint32},
|
|
21
|
+
{std::type_index(typeid(unsigned int)), &ffi_type_uint32},
|
|
22
|
+
{std::type_index(typeid(signed int)), &ffi_type_uint32},
|
|
23
|
+
{std::type_index(typeid(int32_t)), &ffi_type_sint32},
|
|
24
|
+
{std::type_index(typeid(uint64_t)), &ffi_type_uint64},
|
|
25
|
+
{std::type_index(typeid(unsigned long long)), &ffi_type_uint64},
|
|
26
|
+
{std::type_index(typeid(int64_t)), &ffi_type_sint64},
|
|
27
|
+
{std::type_index(typeid(signed long long)), &ffi_type_sint64},
|
|
28
|
+
{std::type_index(typeid(float)), &ffi_type_float},
|
|
29
|
+
{std::type_index(typeid(double)), &ffi_type_double},
|
|
30
|
+
{std::type_index(typeid(void)), &ffi_type_pointer},
|
|
31
|
+
{std::type_index(typeid(long double)), &ffi_type_longdouble}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
if (sizeof(long) == 32)
|
|
35
|
+
{
|
|
36
|
+
nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint32;
|
|
37
|
+
nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint32;
|
|
38
|
+
}
|
|
39
|
+
else if (sizeof(long) == 64)
|
|
40
|
+
{
|
|
41
|
+
nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint64;
|
|
42
|
+
nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint64;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if constexpr (std::is_pointer_v<Arg_T> || std::is_reference_v<Arg_T>)
|
|
46
|
+
{
|
|
47
|
+
return &ffi_type_pointer;
|
|
48
|
+
}
|
|
49
|
+
else
|
|
50
|
+
{
|
|
51
|
+
const std::type_index& key = std::type_index(typeid(Arg_T));
|
|
52
|
+
return nativeToFfiMapping[key];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// This is the function provided to the C++ callback with FFI
|
|
57
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
58
|
+
void NativeCallback<Return_T(*)(Parameter_Ts...)>::invokeFFI(ffi_cif*, void* ret, void* args[], void* instance)
|
|
59
|
+
{
|
|
60
|
+
NativeCallback_T* self = (NativeCallback_T*)instance;
|
|
61
|
+
|
|
62
|
+
// Define a helper lambda to invoke callRuby with unpacked args
|
|
63
|
+
auto indices = std::make_index_sequence<sizeof...(Parameter_Ts)>{};
|
|
64
|
+
auto helper = [&](auto&&... args)
|
|
65
|
+
{
|
|
66
|
+
if constexpr (!std::is_void_v<Return_T>)
|
|
67
|
+
{
|
|
68
|
+
*(Return_T*)ret = self->callRuby(indices, std::forward<Parameter_Ts>(args)...);
|
|
69
|
+
}
|
|
70
|
+
else
|
|
71
|
+
{
|
|
72
|
+
self->callRuby(indices, std::forward<Parameter_Ts>(args)...);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Convert the C style array to a tuple
|
|
77
|
+
Tuple_T argsTuple = convertArgsToTuple(args, indices);
|
|
78
|
+
|
|
79
|
+
// Now use std::apply to unpack the tuple and call the lamba helper
|
|
80
|
+
std::apply(helper, std::forward<Tuple_T>(argsTuple));
|
|
81
|
+
}
|
|
82
|
+
#endif //HAVE_LIBFFI
|
|
83
|
+
|
|
84
|
+
// This is the function provided to the C++ callback without FFI
|
|
85
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
86
|
+
inline Return_T NativeCallback<Return_T(*)(Parameter_Ts...)>::invoke(Parameter_Ts...args)
|
|
87
|
+
{
|
|
88
|
+
auto indices = std::make_index_sequence<sizeof...(Parameter_Ts)>{};
|
|
89
|
+
|
|
90
|
+
if constexpr (std::is_void_v<Return_T>)
|
|
91
|
+
{
|
|
92
|
+
NativeCallback::native_->callRuby(indices, args...);
|
|
93
|
+
}
|
|
94
|
+
else
|
|
95
|
+
{
|
|
96
|
+
return NativeCallback::native_->callRuby(indices, args...);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
101
|
+
std::vector<std::unique_ptr<ParameterAbstract>> NativeCallback<Return_T(*)(Parameter_Ts...)>::copyParameters()
|
|
102
|
+
{
|
|
103
|
+
std::vector<std::unique_ptr<ParameterAbstract>> result;
|
|
104
|
+
|
|
105
|
+
if (sizeof...(Parameter_Ts) > 0 && parameters_.empty())
|
|
106
|
+
{
|
|
107
|
+
NativeCallback_T::define();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (parameters_.size() > 0)
|
|
111
|
+
{
|
|
112
|
+
auto indices = std::make_index_sequence<sizeof...(Parameter_Ts)>{};
|
|
113
|
+
copyParametersImpl(result, indices);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
119
|
+
template<std::size_t... I>
|
|
120
|
+
void NativeCallback<Return_T(*)(Parameter_Ts...)>::copyParametersImpl(std::vector<std::unique_ptr<ParameterAbstract>>& result, std::index_sequence<I...>)
|
|
121
|
+
{
|
|
122
|
+
(result.push_back(std::make_unique<Parameter<Parameter_Ts>>(*(Parameter<Parameter_Ts>*)parameters_[I].get())), ...);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
126
|
+
std::unique_ptr<Return> NativeCallback<Return_T(*)(Parameter_Ts...)>::copyReturnInfo()
|
|
127
|
+
{
|
|
128
|
+
if (!returnInfo_)
|
|
129
|
+
{
|
|
130
|
+
NativeCallback_T::define();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return std::make_unique<Return>(*returnInfo_);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
137
|
+
template<typename Parameter_T>
|
|
138
|
+
Parameter_T NativeCallback<Return_T(*)(Parameter_Ts...)>::extractArg(void* arg)
|
|
139
|
+
{
|
|
140
|
+
if constexpr (std::is_reference_v<Parameter_T>)
|
|
141
|
+
{
|
|
142
|
+
// We told libffi to pass references as pointers, so arg points to the pointer
|
|
143
|
+
return static_cast<Parameter_T>(**reinterpret_cast<std::remove_reference_t<Parameter_T>**>(arg));
|
|
144
|
+
}
|
|
145
|
+
else
|
|
146
|
+
{
|
|
147
|
+
return *reinterpret_cast<Parameter_T*>(arg);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
152
|
+
template<std::size_t... I>
|
|
153
|
+
typename NativeCallback<Return_T(*)(Parameter_Ts...)>::Tuple_T NativeCallback<Return_T(*)(Parameter_Ts...)>::convertArgsToTuple(void* args[], std::index_sequence<I...>&)
|
|
154
|
+
{
|
|
155
|
+
/* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
|
|
156
|
+
on the arguments (Parameter_Ts) required by the C++ function. Arg_T may have const/volatile while
|
|
157
|
+
the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
|
|
158
|
+
which we let the compiler convert to const values as needed. This works except for
|
|
159
|
+
T** -> const T**, see comment in convertToNative method. */
|
|
160
|
+
return std::forward_as_tuple(extractArg<Parameter_Ts>(args[I])...);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
164
|
+
VALUE NativeCallback<Return_T(*)(Parameter_Ts...)>::finalizerCallback(VALUE, VALUE callback_arg, int, const VALUE*, VALUE)
|
|
165
|
+
{
|
|
166
|
+
NativeCallback_T* nativeCallback = (NativeCallback_T*)callback_arg;
|
|
167
|
+
delete nativeCallback;
|
|
168
|
+
return Qnil;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
template<typename Return_T, typename...Parameter_Ts>
|
|
172
|
+
template<typename ...Arg_Ts>
|
|
173
|
+
inline void NativeCallback<Return_T(*)(Parameter_Ts...)>::define(Arg_Ts&& ...args)
|
|
174
|
+
{
|
|
175
|
+
// Create parameters and save them in static member so we can use them later when constructing an instance
|
|
176
|
+
using Parameter_Tuple = std::tuple<Parameter_Ts...>;
|
|
177
|
+
NativeCallback_T::parameters_ = Native::create_parameters<Parameter_Tuple>(std::forward<Arg_Ts>(args)...);
|
|
178
|
+
|
|
179
|
+
// Create Return and save it in static member so we can use them later when constructing an instance
|
|
180
|
+
NativeCallback_T::returnInfo_ = Native::create_return<Arg_Ts...>(args...);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
184
|
+
NativeCallback<Return_T(*)(Parameter_Ts...)>::NativeCallback(VALUE proc) :
|
|
185
|
+
Native("callback", copyReturnInfo(), copyParameters()),
|
|
186
|
+
proc_(proc), fromRuby_(returnInfo_.get())
|
|
187
|
+
{
|
|
188
|
+
// Tie the lifetime of the NativeCallback C++ instance to the lifetime of the Ruby proc object
|
|
189
|
+
VALUE finalizer = rb_proc_new(NativeCallback_T::finalizerCallback, (VALUE)this);
|
|
190
|
+
rb_define_finalizer(proc, finalizer);
|
|
191
|
+
|
|
192
|
+
#ifdef HAVE_LIBFFI
|
|
193
|
+
// First setup description of callback
|
|
194
|
+
if (cif_.bytes == 0)
|
|
195
|
+
{
|
|
196
|
+
ffi_prep_cif(&cif_, FFI_DEFAULT_ABI, sizeof...(Parameter_Ts), ffiType<Return_T>(), args_.data());
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Now allocate memory
|
|
200
|
+
this->closure_ = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), (void**)(&this->callback_));
|
|
201
|
+
// Now create the closure which will create a C++ callback
|
|
202
|
+
ffi_prep_closure_loc(this->closure_, &cif_, invokeFFI, (void*)this, (void*)this->callback_);
|
|
203
|
+
#else
|
|
204
|
+
NativeCallback_T::callback_ = &NativeCallback_T::invoke;
|
|
205
|
+
NativeCallback_T::native_ = this;
|
|
206
|
+
#endif
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
210
|
+
NativeCallback<Return_T(*)(Parameter_Ts...)>::~NativeCallback()
|
|
211
|
+
{
|
|
212
|
+
#ifdef HAVE_LIBFFI
|
|
213
|
+
ffi_closure_free(this->closure_);
|
|
214
|
+
#endif
|
|
215
|
+
|
|
216
|
+
NativeCallback_T::callback_ = nullptr;
|
|
217
|
+
NativeCallback_T::native_ = nullptr;
|
|
218
|
+
|
|
219
|
+
this->proc_ = Qnil;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
223
|
+
typename NativeCallback<Return_T(*)(Parameter_Ts...)>::Callback_T NativeCallback<Return_T(*)(Parameter_Ts...)>::callback()
|
|
224
|
+
{
|
|
225
|
+
return this->callback_;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
229
|
+
template<std::size_t... I>
|
|
230
|
+
Return_T NativeCallback<Return_T(*)(Parameter_Ts...)>::callRuby(std::index_sequence<I...>&, Parameter_Ts...args)
|
|
231
|
+
{
|
|
232
|
+
// Convert the C++ arguments to Ruby VALUEs
|
|
233
|
+
std::array<VALUE, sizeof...(Parameter_Ts)> values = {
|
|
234
|
+
dynamic_cast<Parameter<Parameter_Ts>*>(this->parameters_[I].get())->
|
|
235
|
+
convertToRuby(args)... };
|
|
236
|
+
|
|
237
|
+
static Identifier id("call");
|
|
238
|
+
VALUE result = detail::protect(rb_funcallv, this->proc_, id.id(), (int)sizeof...(Parameter_Ts), values.data());
|
|
239
|
+
if constexpr (!std::is_void_v<Return_T>)
|
|
240
|
+
{
|
|
241
|
+
return this->fromRuby_.convert(result);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
246
|
+
inline VALUE NativeCallback<Return_T(*)(Parameter_Ts...)>::operator()(std::map<std::string, VALUE>&, VALUE)
|
|
247
|
+
{
|
|
248
|
+
return Qnil;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
252
|
+
inline std::string NativeCallback<Return_T(*)(Parameter_Ts...)>::toString()
|
|
253
|
+
{
|
|
254
|
+
return "";
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
//NativeKind kind() override;
|
|
258
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
259
|
+
inline NativeKind NativeCallback<Return_T(*)(Parameter_Ts...)>::kind()
|
|
260
|
+
{
|
|
261
|
+
return NativeKind::Callback;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
template<typename Return_T, typename ...Parameter_Ts>
|
|
265
|
+
inline VALUE NativeCallback<Return_T(*)(Parameter_Ts...)>::returnKlass()
|
|
266
|
+
{
|
|
267
|
+
// Check if an array is being returned
|
|
268
|
+
bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
|
|
269
|
+
if (isBuffer)
|
|
270
|
+
{
|
|
271
|
+
TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Return_T>>>> typeMapper;
|
|
272
|
+
return typeMapper.rubyKlass();
|
|
273
|
+
}
|
|
274
|
+
else
|
|
275
|
+
{
|
|
276
|
+
TypeMapper<Return_T> typeMapper;
|
|
277
|
+
return typeMapper.rubyKlass();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -35,55 +35,45 @@ namespace Rice::detail
|
|
|
35
35
|
* calling them methods (self) or functions (no self).
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
|
-
template<typename Function_T>
|
|
38
|
+
template<typename Function_T, bool NoGVL = false>
|
|
39
39
|
class NativeFunction: Native
|
|
40
40
|
{
|
|
41
41
|
public:
|
|
42
|
-
using NativeFunction_T = NativeFunction<Function_T>;
|
|
42
|
+
using NativeFunction_T = NativeFunction<Function_T, NoGVL>;
|
|
43
43
|
|
|
44
44
|
// We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
|
|
45
45
|
// have the concept of constants anyways
|
|
46
46
|
using Return_T = typename function_traits<Function_T>::return_type;
|
|
47
47
|
using Class_T = typename function_traits<Function_T>::class_type;
|
|
48
|
-
using
|
|
48
|
+
using Parameter_Ts = typename function_traits<Function_T>::arg_types;
|
|
49
49
|
using To_Ruby_T = remove_cv_recursive_t<Return_T>;
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
static void define(VALUE klass, std::string
|
|
51
|
+
template<typename ...Arg_Ts>
|
|
52
|
+
static void define(VALUE klass, std::string function_name, Function_T function, Arg_Ts&& ...args);
|
|
53
53
|
|
|
54
54
|
public:
|
|
55
|
-
NativeFunction(VALUE klass, std::string method_name, Function_T function,
|
|
55
|
+
NativeFunction(VALUE klass, std::string method_name, Function_T function, std::unique_ptr<Return>&& returnInfo, std::vector<std::unique_ptr<ParameterAbstract>>&& parameters);
|
|
56
56
|
|
|
57
|
-
VALUE operator()(
|
|
57
|
+
VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
|
|
58
58
|
std::string toString() override;
|
|
59
59
|
|
|
60
|
-
std::string name() override;
|
|
61
60
|
NativeKind kind() override;
|
|
62
61
|
VALUE returnKlass() override;
|
|
63
62
|
|
|
64
63
|
private:
|
|
65
|
-
|
|
66
|
-
std::vector<std::string> argTypeNames(std::ostringstream& stream, std::index_sequence<I...>& indices);
|
|
64
|
+
std::vector<std::string> argTypeNames();
|
|
67
65
|
|
|
68
66
|
// Convert Ruby values to C++ values
|
|
69
67
|
template<typename std::size_t...I>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// Throw an exception when wrapper cannot be extracted
|
|
73
|
-
[[noreturn]] void noWrapper(const VALUE klass, const std::string& wrapper);
|
|
74
|
-
|
|
75
|
-
// Do we need to keep alive any arguments?
|
|
76
|
-
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues);
|
|
68
|
+
Parameter_Ts getNativeValues(std::vector<std::optional<VALUE>>& values, std::index_sequence<I...>& indices);
|
|
77
69
|
|
|
78
70
|
// Call the underlying C++ function
|
|
79
|
-
VALUE invoke(
|
|
80
|
-
VALUE invokeNoGVL(
|
|
71
|
+
VALUE invoke(Parameter_Ts&& nativeArgs);
|
|
72
|
+
VALUE invokeNoGVL(Parameter_Ts&& nativeArgs);
|
|
81
73
|
|
|
82
74
|
private:
|
|
83
75
|
VALUE klass_;
|
|
84
|
-
std::string method_name_;
|
|
85
76
|
Function_T function_;
|
|
86
|
-
std::unique_ptr<MethodInfo> methodInfo_;
|
|
87
77
|
To_Ruby<To_Ruby_T> toRuby_;
|
|
88
78
|
};
|
|
89
79
|
}
|