rice 4.0.4 → 4.1.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 +30 -0
- data/Rakefile +1 -1
- data/include/rice/rice.hpp +2596 -1771
- data/include/rice/stl.hpp +1580 -271
- data/lib/mkmf-rice.rb +5 -2
- data/lib/version.rb +1 -1
- data/rice/Arg.hpp +6 -6
- data/rice/Arg.ipp +8 -9
- data/rice/Constructor.hpp +2 -2
- data/rice/Data_Object.ipp +69 -15
- data/rice/Data_Object_defn.hpp +1 -15
- data/rice/Data_Type.ipp +56 -86
- data/rice/Data_Type_defn.hpp +14 -17
- data/rice/Director.hpp +0 -1
- data/rice/Enum.ipp +31 -22
- data/rice/Exception.ipp +2 -3
- data/rice/Exception_defn.hpp +5 -5
- data/rice/HandlerRegistration.hpp +15 -0
- data/rice/Return.hpp +5 -4
- data/rice/Return.ipp +8 -3
- data/rice/detail/ExceptionHandler.hpp +8 -0
- data/rice/detail/ExceptionHandler.ipp +28 -0
- data/rice/detail/{Exception_Handler_defn.hpp → ExceptionHandler_defn.hpp} +17 -21
- data/rice/detail/HandlerRegistry.hpp +51 -0
- data/rice/detail/HandlerRegistry.ipp +20 -0
- data/rice/detail/InstanceRegistry.hpp +34 -0
- data/rice/detail/InstanceRegistry.ipp +50 -0
- data/rice/detail/MethodInfo.ipp +1 -1
- data/rice/detail/NativeAttribute.hpp +26 -15
- data/rice/detail/NativeAttribute.ipp +76 -47
- data/rice/detail/NativeFunction.hpp +60 -13
- data/rice/detail/NativeFunction.ipp +103 -85
- data/rice/detail/NativeIterator.hpp +49 -0
- data/rice/detail/NativeIterator.ipp +102 -0
- data/rice/detail/NativeRegistry.hpp +31 -0
- data/rice/detail/{method_data.ipp → NativeRegistry.ipp} +20 -16
- data/rice/detail/Registries.hpp +26 -0
- data/rice/detail/Registries.ipp +23 -0
- data/rice/detail/RubyFunction.hpp +6 -11
- data/rice/detail/RubyFunction.ipp +10 -22
- data/rice/detail/Type.hpp +1 -1
- data/rice/detail/Type.ipp +2 -2
- data/rice/detail/TypeRegistry.hpp +8 -11
- data/rice/detail/TypeRegistry.ipp +3 -28
- data/rice/detail/Wrapper.hpp +0 -2
- data/rice/detail/Wrapper.ipp +73 -23
- data/rice/detail/cpp_protect.hpp +93 -0
- data/rice/detail/default_allocation_func.ipp +1 -1
- data/rice/detail/from_ruby.ipp +206 -2
- data/rice/detail/to_ruby.ipp +39 -5
- data/rice/detail/to_ruby_defn.hpp +1 -1
- data/rice/forward_declares.ipp +6 -0
- data/rice/global_function.hpp +0 -4
- data/rice/global_function.ipp +0 -6
- data/rice/rice.hpp +29 -24
- data/rice/stl.hpp +6 -1
- data/test/embed_ruby.cpp +0 -15
- data/test/test_Array.cpp +20 -24
- data/test/test_Class.cpp +8 -47
- data/test/test_Constructor.cpp +0 -2
- data/test/test_Data_Object.cpp +25 -11
- data/test/test_Data_Type.cpp +124 -28
- data/test/test_Director.cpp +12 -13
- data/test/test_Enum.cpp +65 -26
- data/test/test_Inheritance.cpp +9 -9
- data/test/test_Iterator.cpp +134 -5
- data/test/test_Keep_Alive.cpp +7 -7
- data/test/test_Memory_Management.cpp +1 -1
- data/test/test_Module.cpp +25 -62
- data/test/test_Object.cpp +66 -3
- data/test/test_Ownership.cpp +12 -13
- data/test/test_Self.cpp +12 -13
- data/test/test_Stl_Map.cpp +696 -0
- data/test/test_Stl_Optional.cpp +3 -3
- data/test/test_Stl_Pair.cpp +38 -2
- data/test/test_Stl_Reference_Wrapper.cpp +102 -0
- data/test/test_Stl_SmartPointer.cpp +5 -5
- data/test/test_Stl_Unordered_Map.cpp +697 -0
- data/test/test_Stl_Variant.cpp +301 -0
- data/test/test_Stl_Vector.cpp +200 -41
- data/test/test_Struct.cpp +3 -3
- data/test/test_To_From_Ruby.cpp +6 -0
- data/test/test_Tracking.cpp +239 -0
- data/test/unittest.hpp +13 -4
- metadata +23 -13
- data/rice/detail/Exception_Handler.hpp +0 -8
- data/rice/detail/Exception_Handler.ipp +0 -28
- data/rice/detail/Iterator.hpp +0 -23
- data/rice/detail/Iterator.ipp +0 -47
- data/rice/detail/function_traits.hpp +0 -124
- data/rice/detail/method_data.hpp +0 -29
- data/rice/detail/rice_traits.hpp +0 -116
- data/rice/ruby_try_catch.hpp +0 -86
@@ -1,83 +1,112 @@
|
|
1
1
|
#include <array>
|
2
2
|
#include <algorithm>
|
3
3
|
|
4
|
-
#include "rice_traits.hpp"
|
5
|
-
#include "
|
4
|
+
#include "../traits/rice_traits.hpp"
|
5
|
+
#include "NativeRegistry.hpp"
|
6
6
|
#include "to_ruby_defn.hpp"
|
7
|
-
#include "
|
7
|
+
#include "cpp_protect.hpp"
|
8
8
|
|
9
9
|
namespace Rice::detail
|
10
10
|
{
|
11
|
-
template<typename
|
12
|
-
|
11
|
+
template<typename Attribute_T>
|
12
|
+
void NativeAttribute<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute, AttrAccess access)
|
13
13
|
{
|
14
|
-
|
14
|
+
// Create a NativeAttribute that Ruby will call to read/write C++ variables
|
15
|
+
NativeAttribute_T* native = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute), access);
|
16
|
+
|
17
|
+
if (access == AttrAccess::ReadWrite || access == AttrAccess::Read)
|
15
18
|
{
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
// Tell Ruby to invoke the static method read to get the attribute value
|
20
|
+
detail::protect(rb_define_method, klass, name.c_str(), (RUBY_METHOD_FUNC)&NativeAttribute_T::get, 0);
|
21
|
+
|
22
|
+
// Add to native registry
|
23
|
+
detail::Registries::instance.natives.add(klass, Identifier(name).id(), native);
|
19
24
|
}
|
20
|
-
|
25
|
+
|
26
|
+
if (access == AttrAccess::ReadWrite || access == AttrAccess::Write)
|
27
|
+
{
|
28
|
+
if (std::is_const_v<std::remove_pointer_t<T>>)
|
29
|
+
{
|
30
|
+
throw std::runtime_error(name + " is readonly");
|
31
|
+
}
|
32
|
+
|
33
|
+
// Define the write method name
|
34
|
+
std::string setter = name + "=";
|
35
|
+
|
36
|
+
// Tell Ruby to invoke the static method write to get the attribute value
|
37
|
+
detail::protect(rb_define_method, klass, setter.c_str(), (RUBY_METHOD_FUNC)&NativeAttribute_T::set, 1);
|
38
|
+
|
39
|
+
// Add to native registry
|
40
|
+
detail::Registries::instance.natives.add(klass, Identifier(setter).id(), native);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
template<typename Attribute_T>
|
45
|
+
inline VALUE NativeAttribute<Attribute_T>::get(VALUE self)
|
46
|
+
{
|
47
|
+
return cpp_protect([&]
|
48
|
+
{
|
49
|
+
using Native_Attr_T = NativeAttribute<Attribute_T>;
|
50
|
+
Native_Attr_T* attr = detail::Registries::instance.natives.lookup<Native_Attr_T*>();
|
51
|
+
return attr->read(self);
|
52
|
+
});
|
21
53
|
}
|
22
54
|
|
23
|
-
template<typename
|
24
|
-
inline VALUE NativeAttribute<
|
55
|
+
template<typename Attribute_T>
|
56
|
+
inline VALUE NativeAttribute<Attribute_T>::set(VALUE self, VALUE value)
|
25
57
|
{
|
26
|
-
|
58
|
+
return cpp_protect([&]
|
27
59
|
{
|
28
|
-
using Native_Attr_T = NativeAttribute<
|
29
|
-
Native_Attr_T* attr = detail::
|
60
|
+
using Native_Attr_T = NativeAttribute<Attribute_T>;
|
61
|
+
Native_Attr_T* attr = detail::Registries::instance.natives.lookup<Native_Attr_T*>();
|
30
62
|
return attr->write(self, value);
|
31
|
-
}
|
32
|
-
RUBY_CATCH
|
63
|
+
});
|
33
64
|
}
|
34
65
|
|
35
|
-
template<typename
|
36
|
-
NativeAttribute<
|
37
|
-
|
66
|
+
template<typename Attribute_T>
|
67
|
+
NativeAttribute<Attribute_T>::NativeAttribute(VALUE klass, std::string name,
|
68
|
+
Attribute_T attribute, AttrAccess access)
|
69
|
+
: klass_(klass), name_(name), attribute_(attribute), access_(access)
|
38
70
|
{
|
39
71
|
}
|
40
72
|
|
41
|
-
template<typename
|
42
|
-
inline VALUE NativeAttribute<
|
73
|
+
template<typename Attribute_T>
|
74
|
+
inline VALUE NativeAttribute<Attribute_T>::read(VALUE self)
|
43
75
|
{
|
44
|
-
using
|
45
|
-
if constexpr (std::is_member_object_pointer_v<
|
76
|
+
using T_Unqualified = remove_cv_recursive_t<T>;
|
77
|
+
if constexpr (std::is_member_object_pointer_v<Attribute_T>)
|
46
78
|
{
|
47
|
-
|
48
|
-
return To_Ruby<
|
79
|
+
Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
|
80
|
+
return To_Ruby<T_Unqualified>().convert(nativeSelf->*attribute_);
|
49
81
|
}
|
50
82
|
else
|
51
83
|
{
|
52
|
-
return To_Ruby<
|
84
|
+
return To_Ruby<T_Unqualified>().convert(*attribute_);
|
53
85
|
}
|
54
86
|
}
|
55
87
|
|
56
|
-
template<typename
|
57
|
-
inline VALUE NativeAttribute<
|
88
|
+
template<typename Attribute_T>
|
89
|
+
inline VALUE NativeAttribute<Attribute_T>::write(VALUE self, VALUE value)
|
58
90
|
{
|
59
|
-
if constexpr (
|
91
|
+
if constexpr (std::is_fundamental_v<intrinsic_type<T>> && std::is_pointer_v<T>)
|
60
92
|
{
|
61
|
-
|
62
|
-
nativeSelf->*attr_ = From_Ruby<Return_T>().convert(value);
|
93
|
+
static_assert(true, "An fundamental value, such as an integer, cannot be assigned to an attribute that is a pointer");
|
63
94
|
}
|
64
|
-
else if constexpr (
|
95
|
+
else if constexpr (std::is_same_v<intrinsic_type<T>, std::string> && std::is_pointer_v<T>)
|
65
96
|
{
|
66
|
-
|
97
|
+
static_assert(true, "An string cannot be assigned to an attribute that is a pointer");
|
98
|
+
}
|
99
|
+
|
100
|
+
if constexpr (!std::is_null_pointer_v<Receiver_T>)
|
101
|
+
{
|
102
|
+
Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
|
103
|
+
nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
|
104
|
+
}
|
105
|
+
else if constexpr (!std::is_const_v<std::remove_pointer_t<T>>)
|
106
|
+
{
|
107
|
+
*attribute_ = From_Ruby<T_Unqualified>().convert(value);
|
67
108
|
}
|
68
|
-
return value;
|
69
|
-
}
|
70
|
-
|
71
|
-
template<typename T>
|
72
|
-
auto* Make_Native_Attribute(T* attr, AttrAccess access)
|
73
|
-
{
|
74
|
-
return new NativeAttribute<T, T*>(attr, access);
|
75
|
-
}
|
76
109
|
|
77
|
-
|
78
|
-
auto* Make_Native_Attribute(T Class_T::* attr, AttrAccess access)
|
79
|
-
{
|
80
|
-
using Attr_T = T Class_T::*;
|
81
|
-
return new NativeAttribute<T, Attr_T, Class_T>(attr, access);
|
110
|
+
return value;
|
82
111
|
}
|
83
112
|
} // Rice
|
@@ -2,40 +2,86 @@
|
|
2
2
|
#define Rice__detail__Native_Function__hpp_
|
3
3
|
|
4
4
|
#include "ruby.hpp"
|
5
|
-
#include "
|
5
|
+
#include "ExceptionHandler_defn.hpp"
|
6
6
|
#include "MethodInfo.hpp"
|
7
|
-
#include "function_traits.hpp"
|
7
|
+
#include "../traits/function_traits.hpp"
|
8
|
+
#include "../traits/method_traits.hpp"
|
8
9
|
#include "from_ruby.hpp"
|
9
10
|
|
10
11
|
namespace Rice::detail
|
11
12
|
{
|
12
|
-
|
13
|
+
//! The NativeFunction class calls C++ functions/methods/lambdas on behalf of Ruby
|
14
|
+
/*! The NativeFunction class is an intermediate between Ruby and C++. Every method
|
15
|
+
* defined in Rice is associated with a NativeFuntion instance that is stored in
|
16
|
+
* a unordered_map maintained by the MethodData class. The key is the Ruby class
|
17
|
+
* and method.
|
18
|
+
*
|
19
|
+
* When Ruby calls into C++ it invokes the static NativeFunction.call method. This
|
20
|
+
* method then looks up the NativeFunction instance and calls its ->() operator.
|
21
|
+
*
|
22
|
+
* The instance then converts each of the arguments passed from Ruby into their
|
23
|
+
* C++ equivalents. It then retrieves the C++ object (if there is one, Ruby could
|
24
|
+
* be calling a free standing method or lambda). Then it calls the C++ method
|
25
|
+
* and gets back the result. If there is a result (so not void), it is converted
|
26
|
+
* from a C++ object to a Ruby object and returned back to Ruby.
|
27
|
+
*
|
28
|
+
* This class make heavy use of C++ Template metaprogramming to determine
|
29
|
+
* the types and parameters a method takes. It then uses that information
|
30
|
+
* to perform type conversion Ruby to C++.
|
31
|
+
*
|
32
|
+
* @tparam From_Ruby_T - The type of C++ class wrapped by Ruby. Note
|
33
|
+
* this may be different than the Class of Function_T. For example,
|
34
|
+
* std::map has a size() method but that is actually implemented on
|
35
|
+
* an ancestor class _Tree. Thus From_Ruby_T is std::map but
|
36
|
+
* Function_T::Class_T is _Tree. This typename must be specified
|
37
|
+
* by the calling code.
|
38
|
+
* @tparam Function_T - A template that represents the C++ function
|
39
|
+
* to call. This typename is automatically deduced by the compiler.
|
40
|
+
* @tparam IsMethod - A boolean specifying whether the function has
|
41
|
+
* a self parameter or not. Rice differentiates these two cases by
|
42
|
+
* calling them methods (self) or functions (no self).
|
43
|
+
*/
|
44
|
+
|
45
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
13
46
|
class NativeFunction
|
14
47
|
{
|
15
48
|
public:
|
49
|
+
using NativeFunction_T = NativeFunction<From_Ruby_T, Function_T, IsMethod>;
|
50
|
+
|
16
51
|
// We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
|
17
52
|
// have the concept of constants anyways
|
18
53
|
using Return_T = remove_cv_recursive_t<typename function_traits<Function_T>::return_type>;
|
19
|
-
using
|
54
|
+
using Class_T = typename method_traits<Function_T, IsMethod>::Class_T;
|
20
55
|
using Arg_Ts = typename method_traits<Function_T, IsMethod>::Arg_Ts;
|
21
|
-
using
|
56
|
+
using From_Ruby_Args_Ts = typename tuple_map<From_Ruby, Arg_Ts>::type;
|
57
|
+
|
58
|
+
// Register function with Ruby
|
59
|
+
static void define(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
|
22
60
|
|
23
61
|
// Static member function that Ruby calls
|
24
62
|
static VALUE call(int argc, VALUE* argv, VALUE self);
|
25
63
|
|
26
64
|
public:
|
27
|
-
|
65
|
+
// Disallow creating/copying/moving
|
66
|
+
NativeFunction() = delete;
|
67
|
+
NativeFunction(const NativeFunction_T&) = delete;
|
68
|
+
NativeFunction(NativeFunction_T&&) = delete;
|
69
|
+
void operator=(const NativeFunction_T&) = delete;
|
70
|
+
void operator=(NativeFunction_T&&) = delete;
|
28
71
|
|
29
72
|
// Invokes the wrapped function
|
30
73
|
VALUE operator()(int argc, VALUE* argv, VALUE self);
|
31
74
|
|
75
|
+
protected:
|
76
|
+
NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
|
77
|
+
|
32
78
|
private:
|
33
79
|
template<typename T, std::size_t I>
|
34
80
|
From_Ruby<T> createFromRuby();
|
35
81
|
|
36
82
|
// Create NativeArgs which are used to convert values from Ruby to C++
|
37
83
|
template<std::size_t...I>
|
38
|
-
|
84
|
+
From_Ruby_Args_Ts createFromRuby(std::index_sequence<I...>& indices);
|
39
85
|
|
40
86
|
To_Ruby<Return_T> createToRuby();
|
41
87
|
|
@@ -47,20 +93,21 @@ namespace Rice::detail
|
|
47
93
|
Arg_Ts getNativeValues(std::vector<VALUE>& values, std::index_sequence<I...>& indices);
|
48
94
|
|
49
95
|
// Figure out what self is
|
50
|
-
|
96
|
+
Class_T getReceiver(VALUE self);
|
51
97
|
|
52
98
|
// Do we need to keep alive any arguments?
|
53
99
|
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues);
|
54
100
|
|
55
101
|
// Call the underlying C++ function
|
56
|
-
VALUE invokeNativeFunction(Arg_Ts& nativeArgs);
|
57
|
-
VALUE invokeNativeMethod(VALUE self, Arg_Ts& nativeArgs);
|
102
|
+
VALUE invokeNativeFunction(const Arg_Ts& nativeArgs);
|
103
|
+
VALUE invokeNativeMethod(VALUE self, const Arg_Ts& nativeArgs);
|
58
104
|
|
59
105
|
private:
|
60
|
-
|
61
|
-
|
106
|
+
VALUE klass_;
|
107
|
+
std::string method_name_;
|
108
|
+
Function_T function_;
|
109
|
+
From_Ruby_Args_Ts fromRubys_;
|
62
110
|
To_Ruby<Return_T> toRuby_;
|
63
|
-
std::shared_ptr<Exception_Handler> handler_;
|
64
111
|
std::unique_ptr<MethodInfo> methodInfo_;
|
65
112
|
};
|
66
113
|
}
|
@@ -2,25 +2,43 @@
|
|
2
2
|
#include <algorithm>
|
3
3
|
#include <stdexcept>
|
4
4
|
|
5
|
-
#include "
|
5
|
+
#include "cpp_protect.hpp"
|
6
6
|
#include "to_ruby_defn.hpp"
|
7
|
-
#include "
|
7
|
+
#include "NativeRegistry.hpp"
|
8
8
|
|
9
9
|
namespace Rice::detail
|
10
10
|
{
|
11
|
-
template<typename Function_T, bool IsMethod>
|
12
|
-
|
11
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
12
|
+
void NativeFunction<From_Ruby_T, Function_T, IsMethod>::define(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
13
13
|
{
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
// Tell Ruby to invoke the static method call on this class
|
15
|
+
detail::protect(rb_define_method, klass, method_name.c_str(), (RUBY_METHOD_FUNC)&NativeFunction_T::call, -1);
|
16
|
+
|
17
|
+
// Now create a NativeFunction instance and save it to the natives registry keyed on
|
18
|
+
// Ruby klass and method id. There may be multiple NativeFunction instances
|
19
|
+
// because the same C++ method could be mapped to multiple Ruby methods.
|
20
|
+
NativeFunction_T* native = new NativeFunction_T(klass, method_name, std::forward<Function_T>(function), methodInfo);
|
21
|
+
detail::Registries::instance.natives.add(klass, Identifier(method_name).id(), native);
|
22
|
+
}
|
23
|
+
|
24
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
25
|
+
VALUE NativeFunction<From_Ruby_T, Function_T, IsMethod>::call(int argc, VALUE* argv, VALUE self)
|
26
|
+
{
|
27
|
+
// Look up the native function based on the Ruby klass and method id
|
28
|
+
NativeFunction_T* nativeFunction = detail::Registries::instance.natives.lookup<NativeFunction_T*>();
|
29
|
+
|
30
|
+
// Execute the function but make sure to catch any C++ exceptions!
|
31
|
+
return cpp_protect([&]
|
32
|
+
{
|
33
|
+
return nativeFunction->operator()(argc, argv, self);
|
34
|
+
});
|
17
35
|
}
|
18
36
|
|
19
|
-
template<typename Function_T, bool IsMethod>
|
20
|
-
NativeFunction<Function_T, IsMethod>::NativeFunction(
|
21
|
-
:
|
37
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
38
|
+
NativeFunction<From_Ruby_T, Function_T, IsMethod>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
39
|
+
: klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo)
|
22
40
|
{
|
23
|
-
|
41
|
+
// Create a tuple of NativeArgs that will convert the Ruby values to native values. For
|
24
42
|
// builtin types NativeArgs will keep a copy of the native value so that it
|
25
43
|
// can be passed by reference or pointer to the native function. For non-builtin types
|
26
44
|
// it will just pass the value through.
|
@@ -30,9 +48,9 @@ namespace Rice::detail
|
|
30
48
|
this->toRuby_ = this->createToRuby();
|
31
49
|
}
|
32
50
|
|
33
|
-
template<typename Function_T, bool IsMethod>
|
51
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
34
52
|
template<typename T, std::size_t I>
|
35
|
-
From_Ruby<T> NativeFunction<Function_T, IsMethod>::createFromRuby()
|
53
|
+
From_Ruby<T> NativeFunction<From_Ruby_T, Function_T, IsMethod>::createFromRuby()
|
36
54
|
{
|
37
55
|
// Does the From_Ruby instantiation work with Arg?
|
38
56
|
if constexpr (std::is_constructible_v<From_Ruby<T>, Arg*>)
|
@@ -45,8 +63,8 @@ namespace Rice::detail
|
|
45
63
|
}
|
46
64
|
}
|
47
65
|
|
48
|
-
template<typename Function_T, bool IsMethod>
|
49
|
-
To_Ruby<typename NativeFunction<Function_T, IsMethod>::Return_T> NativeFunction<Function_T, IsMethod>::createToRuby()
|
66
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
67
|
+
To_Ruby<typename NativeFunction<From_Ruby_T, Function_T, IsMethod>::Return_T> NativeFunction<From_Ruby_T, Function_T, IsMethod>::createToRuby()
|
50
68
|
{
|
51
69
|
// Does the From_Ruby instantiation work with ReturnInfo?
|
52
70
|
if constexpr (std::is_constructible_v<To_Ruby<Return_T>, Return*>)
|
@@ -59,41 +77,41 @@ namespace Rice::detail
|
|
59
77
|
}
|
60
78
|
}
|
61
79
|
|
62
|
-
template<typename Function_T, bool IsMethod>
|
80
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
63
81
|
template<std::size_t... I>
|
64
|
-
typename NativeFunction<Function_T, IsMethod>::
|
82
|
+
typename NativeFunction<From_Ruby_T, Function_T, IsMethod>::From_Ruby_Args_Ts NativeFunction<From_Ruby_T, Function_T, IsMethod>::createFromRuby(std::index_sequence<I...>& indices)
|
65
83
|
{
|
66
84
|
return std::make_tuple(createFromRuby<remove_cv_recursive_t<typename std::tuple_element<I, Arg_Ts>::type>, I>()...);
|
67
85
|
}
|
68
86
|
|
69
|
-
template<typename Function_T, bool IsMethod>
|
70
|
-
std::vector<VALUE> NativeFunction<Function_T, IsMethod>::getRubyValues(int argc, VALUE* argv)
|
87
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
88
|
+
std::vector<VALUE> NativeFunction<From_Ruby_T, Function_T, IsMethod>::getRubyValues(int argc, VALUE* argv)
|
71
89
|
{
|
72
|
-
// Setup a tuple
|
90
|
+
// Setup a tuple for the leading rb_scan_args arguments
|
73
91
|
std::string scanFormat = this->methodInfo_->formatString();
|
74
|
-
std::tuple<int, VALUE*, const char*>
|
92
|
+
std::tuple<int, VALUE*, const char*> rbScanArgs = std::forward_as_tuple(argc, argv, scanFormat.c_str());
|
75
93
|
|
76
|
-
// Create a vector to store the
|
77
|
-
std::vector<VALUE>
|
94
|
+
// Create a vector to store the VALUEs that will be returned by rb_scan_args
|
95
|
+
std::vector<VALUE> rbScanValues(std::tuple_size_v<Arg_Ts>, Qnil);
|
78
96
|
|
79
|
-
// Convert the vector to an array so it can
|
80
|
-
|
81
|
-
std::
|
97
|
+
// Convert the vector to an array so it can be concatenated to a tuple. As importantly
|
98
|
+
// fill it with pointers to rbScanValues
|
99
|
+
std::array<VALUE*, std::tuple_size_v<Arg_Ts>> rbScanValuePointers;
|
100
|
+
std::transform(rbScanValues.begin(), rbScanValues.end(), rbScanValuePointers.begin(),
|
82
101
|
[](VALUE& value)
|
83
102
|
{
|
84
103
|
return &value;
|
85
104
|
});
|
86
105
|
|
87
106
|
// Combine the tuples and call rb_scan_args
|
88
|
-
|
89
|
-
std::apply(rb_scan_args, rbScanArgs);
|
107
|
+
std::apply(rb_scan_args, std::tuple_cat(rbScanArgs, rbScanValuePointers));
|
90
108
|
|
91
|
-
return
|
109
|
+
return rbScanValues;
|
92
110
|
}
|
93
111
|
|
94
|
-
template<typename Function_T, bool IsMethod>
|
112
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
95
113
|
template<std::size_t... I>
|
96
|
-
typename NativeFunction<Function_T, IsMethod>::Arg_Ts NativeFunction<Function_T, IsMethod>::getNativeValues(std::vector<VALUE>& values,
|
114
|
+
typename NativeFunction<From_Ruby_T, Function_T, IsMethod>::Arg_Ts NativeFunction<From_Ruby_T, Function_T, IsMethod>::getNativeValues(std::vector<VALUE>& values,
|
97
115
|
std::index_sequence<I...>& indices)
|
98
116
|
{
|
99
117
|
// Convert each Ruby value to its native value by calling the appropriate fromRuby instance.
|
@@ -102,80 +120,91 @@ namespace Rice::detail
|
|
102
120
|
return std::forward_as_tuple(std::get<I>(this->fromRubys_).convert(values[I])...);
|
103
121
|
}
|
104
122
|
|
105
|
-
template<typename Function_T, bool IsMethod>
|
106
|
-
typename NativeFunction<Function_T, IsMethod>::
|
123
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
124
|
+
typename NativeFunction<From_Ruby_T, Function_T, IsMethod>::Class_T NativeFunction<From_Ruby_T, Function_T, IsMethod>::getReceiver(VALUE self)
|
107
125
|
{
|
108
126
|
// There is no self parameter
|
109
|
-
if constexpr (std::is_same_v<
|
127
|
+
if constexpr (std::is_same_v<Class_T, std::nullptr_t>)
|
110
128
|
{
|
111
129
|
return nullptr;
|
112
130
|
}
|
113
131
|
// Self parameter is a Ruby VALUE so no conversion is needed
|
114
|
-
else if constexpr (std::is_same_v<
|
132
|
+
else if constexpr (std::is_same_v<Class_T, VALUE>)
|
115
133
|
{
|
116
134
|
return self;
|
117
135
|
}
|
118
|
-
|
136
|
+
/* This case happens when a class wrapped by Rice is calling a method
|
137
|
+
defined on an ancestor class. For example, the std::map size method
|
138
|
+
is defined on _Tree not map. Rice needs to know the actual type
|
139
|
+
that was wrapped so it can correctly extract the C++ object from
|
140
|
+
the Ruby object. */
|
141
|
+
else if constexpr (!std::is_same_v<intrinsic_type<Class_T>, From_Ruby_T> &&
|
142
|
+
std::is_base_of_v<intrinsic_type<Class_T>, From_Ruby_T>)
|
143
|
+
{
|
144
|
+
From_Ruby_T* instance = From_Ruby<From_Ruby_T*>().convert(self);
|
145
|
+
return dynamic_cast<Class_T>(instance);
|
146
|
+
}
|
147
|
+
// Self parameter could be derived from Object or it is an C++ instance and
|
119
148
|
// needs to be unwrapped from Ruby
|
120
149
|
else
|
121
150
|
{
|
122
|
-
return From_Ruby<
|
151
|
+
return From_Ruby<Class_T>().convert(self);
|
123
152
|
}
|
124
153
|
}
|
125
154
|
|
126
|
-
template<typename Function_T, bool IsMethod>
|
127
|
-
VALUE NativeFunction<Function_T, IsMethod>::invokeNativeFunction(Arg_Ts& nativeArgs)
|
155
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
156
|
+
VALUE NativeFunction<From_Ruby_T, Function_T, IsMethod>::invokeNativeFunction(const Arg_Ts& nativeArgs)
|
128
157
|
{
|
129
158
|
if constexpr (std::is_void_v<Return_T>)
|
130
159
|
{
|
131
|
-
std::apply(this->
|
160
|
+
std::apply(this->function_, nativeArgs);
|
132
161
|
return Qnil;
|
133
162
|
}
|
134
163
|
else
|
135
164
|
{
|
136
165
|
// Call the native method and get the result
|
137
|
-
Return_T nativeResult = std::apply(this->
|
166
|
+
Return_T nativeResult = std::apply(this->function_, nativeArgs);
|
138
167
|
|
139
168
|
// Return the result
|
140
169
|
return this->toRuby_.convert(nativeResult);
|
141
170
|
}
|
142
171
|
}
|
143
172
|
|
144
|
-
template<typename Function_T, bool IsMethod>
|
145
|
-
VALUE NativeFunction<Function_T, IsMethod>::invokeNativeMethod(VALUE self, Arg_Ts& nativeArgs)
|
173
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
174
|
+
VALUE NativeFunction<From_Ruby_T, Function_T, IsMethod>::invokeNativeMethod(VALUE self, const Arg_Ts& nativeArgs)
|
146
175
|
{
|
147
|
-
|
176
|
+
Class_T receiver = this->getReceiver(self);
|
148
177
|
auto selfAndNativeArgs = std::tuple_cat(std::forward_as_tuple(receiver), nativeArgs);
|
149
178
|
|
150
179
|
if constexpr (std::is_void_v<Return_T>)
|
151
180
|
{
|
152
|
-
std::apply(this->
|
181
|
+
std::apply(this->function_, selfAndNativeArgs);
|
153
182
|
return Qnil;
|
154
183
|
}
|
155
184
|
else
|
156
185
|
{
|
157
|
-
Return_T nativeResult = (Return_T)std::apply(this->
|
186
|
+
Return_T nativeResult = (Return_T)std::apply(this->function_, selfAndNativeArgs);
|
158
187
|
|
159
188
|
// Special handling if the method returns self. If so we do not want
|
160
189
|
// to create a new Ruby wrapper object and instead return self.
|
161
|
-
if constexpr (std::is_same_v<intrinsic_type<Return_T>, intrinsic_type<
|
190
|
+
if constexpr (std::is_same_v<intrinsic_type<Return_T>, intrinsic_type<Class_T>>)
|
162
191
|
{
|
163
|
-
if constexpr (std::is_pointer_v<Return_T> && std::is_pointer_v<
|
192
|
+
if constexpr (std::is_pointer_v<Return_T> && std::is_pointer_v<Class_T>)
|
164
193
|
{
|
165
194
|
if (nativeResult == receiver)
|
166
195
|
return self;
|
167
196
|
}
|
168
|
-
else if constexpr (std::is_pointer_v<Return_T> && std::is_reference_v<
|
197
|
+
else if constexpr (std::is_pointer_v<Return_T> && std::is_reference_v<Class_T>)
|
169
198
|
{
|
170
199
|
if (nativeResult == &receiver)
|
171
200
|
return self;
|
172
201
|
}
|
173
|
-
else if constexpr (std::is_reference_v<Return_T> && std::is_pointer_v<
|
202
|
+
else if constexpr (std::is_reference_v<Return_T> && std::is_pointer_v<Class_T>)
|
174
203
|
{
|
175
204
|
if (&nativeResult == receiver)
|
176
205
|
return self;
|
177
206
|
}
|
178
|
-
else if constexpr (std::is_reference_v<Return_T> && std::is_reference_v<
|
207
|
+
else if constexpr (std::is_reference_v<Return_T> && std::is_reference_v<Class_T>)
|
179
208
|
{
|
180
209
|
if (&nativeResult == &receiver)
|
181
210
|
return self;
|
@@ -186,63 +215,52 @@ namespace Rice::detail
|
|
186
215
|
}
|
187
216
|
}
|
188
217
|
|
189
|
-
template<typename Function_T, bool IsMethod>
|
190
|
-
void NativeFunction<Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues)
|
218
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
219
|
+
void NativeFunction<From_Ruby_T, Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues)
|
191
220
|
{
|
192
221
|
// Check function arguments
|
193
222
|
Wrapper* selfWrapper = getWrapper(self);
|
194
223
|
for (const Arg& arg : (*this->methodInfo_))
|
195
224
|
{
|
196
|
-
if (arg.isKeepAlive)
|
225
|
+
if (arg.isKeepAlive())
|
197
226
|
{
|
198
227
|
selfWrapper->addKeepAlive(rubyValues[arg.position]);
|
199
228
|
}
|
200
229
|
}
|
201
230
|
|
202
231
|
// Check return value
|
203
|
-
if (this->methodInfo_->returnInfo.isKeepAlive)
|
232
|
+
if (this->methodInfo_->returnInfo.isKeepAlive())
|
204
233
|
{
|
205
234
|
Wrapper* returnWrapper = getWrapper(returnValue);
|
206
235
|
returnWrapper->addKeepAlive(self);
|
207
236
|
}
|
208
237
|
}
|
209
238
|
|
210
|
-
template<typename Function_T, bool IsMethod>
|
211
|
-
VALUE NativeFunction<Function_T, IsMethod>::operator()(int argc, VALUE* argv, VALUE self)
|
239
|
+
template<typename From_Ruby_T, typename Function_T, bool IsMethod>
|
240
|
+
VALUE NativeFunction<From_Ruby_T, Function_T, IsMethod>::operator()(int argc, VALUE* argv, VALUE self)
|
212
241
|
{
|
213
|
-
|
214
|
-
|
215
|
-
// Get the ruby values
|
216
|
-
std::vector<VALUE> rubyValues = this->getRubyValues(argc, argv);
|
217
|
-
|
218
|
-
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
219
|
-
|
220
|
-
// Convert the Ruby values to native values
|
221
|
-
Arg_Ts nativeValues = this->getNativeValues(rubyValues, indices);
|
242
|
+
// Get the ruby values
|
243
|
+
std::vector<VALUE> rubyValues = this->getRubyValues(argc, argv);
|
222
244
|
|
223
|
-
|
224
|
-
VALUE result = Qnil;
|
225
|
-
if constexpr (std::is_same_v<Self_T, std::nullptr_t>)
|
226
|
-
{
|
227
|
-
result = this->invokeNativeFunction(nativeValues);
|
228
|
-
}
|
229
|
-
else
|
230
|
-
{
|
231
|
-
result = this->invokeNativeMethod(self, nativeValues);
|
232
|
-
}
|
245
|
+
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
233
246
|
|
234
|
-
|
235
|
-
|
247
|
+
// Convert the Ruby values to native values
|
248
|
+
Arg_Ts nativeValues = this->getNativeValues(rubyValues, indices);
|
236
249
|
|
237
|
-
|
250
|
+
// Now call the native method
|
251
|
+
VALUE result = Qnil;
|
252
|
+
if constexpr (std::is_same_v<Class_T, std::nullptr_t>)
|
253
|
+
{
|
254
|
+
result = this->invokeNativeFunction(nativeValues);
|
238
255
|
}
|
239
|
-
|
256
|
+
else
|
240
257
|
{
|
241
|
-
|
242
|
-
{
|
243
|
-
return this->handler_->handle_exception();
|
244
|
-
}
|
245
|
-
RUBY_CATCH
|
258
|
+
result = this->invokeNativeMethod(self, nativeValues);
|
246
259
|
}
|
260
|
+
|
261
|
+
// Check if any function arguments or return values need to have their lifetimes tied to the receiver
|
262
|
+
this->checkKeepAlive(self, result, rubyValues);
|
263
|
+
|
264
|
+
return result;
|
247
265
|
}
|
248
266
|
}
|