rice 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -0
  3. data/CONTRIBUTORS.md +19 -0
  4. data/Gemfile +3 -0
  5. data/README.md +44 -1025
  6. data/Rakefile +95 -12
  7. data/include/rice/rice.hpp +7766 -0
  8. data/lib/mkmf-rice.rb +127 -0
  9. data/lib/version.rb +3 -0
  10. data/rice/Address_Registration_Guard.ipp +75 -32
  11. data/rice/Address_Registration_Guard_defn.hpp +60 -56
  12. data/rice/Arg.hpp +80 -4
  13. data/rice/Arg.ipp +51 -0
  14. data/rice/Constructor.hpp +12 -14
  15. data/rice/Data_Object.ipp +234 -107
  16. data/rice/Data_Object_defn.hpp +77 -117
  17. data/rice/Data_Type.hpp +1 -2
  18. data/rice/Data_Type.ipp +251 -295
  19. data/rice/Data_Type_defn.hpp +175 -243
  20. data/rice/Director.hpp +11 -6
  21. data/rice/Enum.hpp +54 -104
  22. data/rice/Enum.ipp +104 -230
  23. data/rice/Exception.hpp +2 -8
  24. data/rice/Exception.ipp +65 -0
  25. data/rice/Exception_defn.hpp +46 -47
  26. data/rice/Identifier.hpp +28 -28
  27. data/rice/Identifier.ipp +23 -27
  28. data/rice/Return.hpp +39 -0
  29. data/rice/Return.ipp +33 -0
  30. data/rice/detail/Exception_Handler.ipp +22 -62
  31. data/rice/detail/Exception_Handler_defn.hpp +76 -91
  32. data/rice/detail/Iterator.hpp +18 -88
  33. data/rice/detail/Iterator.ipp +47 -0
  34. data/rice/detail/Jump_Tag.hpp +21 -0
  35. data/rice/detail/MethodInfo.hpp +44 -0
  36. data/rice/detail/MethodInfo.ipp +78 -0
  37. data/rice/detail/NativeAttribute.hpp +53 -0
  38. data/rice/detail/NativeAttribute.ipp +83 -0
  39. data/rice/detail/NativeFunction.hpp +69 -0
  40. data/rice/detail/NativeFunction.ipp +248 -0
  41. data/rice/detail/RubyFunction.hpp +39 -0
  42. data/rice/detail/RubyFunction.ipp +92 -0
  43. data/rice/detail/Type.hpp +29 -0
  44. data/rice/detail/Type.ipp +138 -0
  45. data/rice/detail/TypeRegistry.hpp +50 -0
  46. data/rice/detail/TypeRegistry.ipp +106 -0
  47. data/rice/detail/Wrapper.hpp +51 -0
  48. data/rice/detail/Wrapper.ipp +151 -0
  49. data/rice/detail/default_allocation_func.hpp +8 -19
  50. data/rice/detail/default_allocation_func.ipp +9 -8
  51. data/rice/detail/from_ruby.hpp +2 -37
  52. data/rice/detail/from_ruby.ipp +1020 -46
  53. data/rice/detail/from_ruby_defn.hpp +38 -0
  54. data/rice/detail/function_traits.hpp +124 -0
  55. data/rice/detail/method_data.hpp +23 -15
  56. data/rice/detail/method_data.ipp +53 -0
  57. data/rice/detail/rice_traits.hpp +116 -0
  58. data/rice/detail/ruby.hpp +9 -46
  59. data/rice/detail/to_ruby.hpp +3 -17
  60. data/rice/detail/to_ruby.ipp +409 -31
  61. data/rice/detail/to_ruby_defn.hpp +48 -0
  62. data/rice/forward_declares.ipp +82 -0
  63. data/rice/global_function.hpp +16 -20
  64. data/rice/global_function.ipp +8 -17
  65. data/rice/rice.hpp +59 -0
  66. data/rice/ruby_mark.hpp +5 -3
  67. data/rice/ruby_try_catch.hpp +4 -4
  68. data/rice/stl.hpp +11 -0
  69. data/sample/callbacks/extconf.rb +3 -0
  70. data/sample/callbacks/sample_callbacks.cpp +10 -13
  71. data/sample/enum/extconf.rb +3 -0
  72. data/sample/enum/sample_enum.cpp +3 -17
  73. data/sample/enum/test.rb +2 -2
  74. data/sample/inheritance/animals.cpp +8 -24
  75. data/sample/inheritance/extconf.rb +3 -0
  76. data/sample/inheritance/test.rb +1 -1
  77. data/sample/map/extconf.rb +3 -0
  78. data/sample/map/map.cpp +10 -18
  79. data/sample/map/test.rb +1 -1
  80. data/test/embed_ruby.cpp +18 -5
  81. data/test/ext/t1/extconf.rb +3 -0
  82. data/test/ext/t1/t1.cpp +1 -3
  83. data/test/ext/t2/extconf.rb +3 -0
  84. data/test/ext/t2/t2.cpp +1 -1
  85. data/test/extconf.rb +23 -0
  86. data/test/ruby/test_callbacks_sample.rb +28 -0
  87. data/test/ruby/test_multiple_extensions.rb +18 -0
  88. data/test/ruby/test_multiple_extensions_same_class.rb +14 -0
  89. data/test/ruby/test_multiple_extensions_with_inheritance.rb +20 -0
  90. data/test/test_Address_Registration_Guard.cpp +23 -10
  91. data/test/test_Array.cpp +129 -73
  92. data/test/test_Attribute.cpp +147 -0
  93. data/test/test_Builtin_Object.cpp +34 -14
  94. data/test/test_Class.cpp +149 -275
  95. data/test/test_Constructor.cpp +10 -9
  96. data/test/test_Data_Object.cpp +133 -192
  97. data/test/test_Data_Type.cpp +322 -252
  98. data/test/test_Director.cpp +54 -41
  99. data/test/test_Enum.cpp +228 -103
  100. data/test/test_Exception.cpp +5 -6
  101. data/test/test_Hash.cpp +31 -30
  102. data/test/test_Identifier.cpp +4 -5
  103. data/test/test_Inheritance.cpp +221 -0
  104. data/test/test_Iterator.cpp +161 -0
  105. data/test/test_Jump_Tag.cpp +1 -1
  106. data/test/test_Keep_Alive.cpp +161 -0
  107. data/test/test_Memory_Management.cpp +2 -4
  108. data/test/test_Module.cpp +167 -110
  109. data/test/test_Object.cpp +41 -21
  110. data/test/test_Ownership.cpp +275 -0
  111. data/test/test_Self.cpp +205 -0
  112. data/test/test_Stl_Optional.cpp +90 -0
  113. data/test/test_Stl_Pair.cpp +144 -0
  114. data/test/test_Stl_SmartPointer.cpp +200 -0
  115. data/test/test_Stl_String.cpp +74 -0
  116. data/test/test_Stl_Vector.cpp +652 -0
  117. data/test/test_String.cpp +1 -2
  118. data/test/test_Struct.cpp +29 -39
  119. data/test/test_Symbol.cpp +1 -2
  120. data/test/test_To_From_Ruby.cpp +249 -285
  121. data/test/test_global_functions.cpp +39 -19
  122. data/test/unittest.hpp +0 -4
  123. metadata +63 -139
  124. data/Doxyfile +0 -2268
  125. data/Makefile.am +0 -26
  126. data/Makefile.in +0 -931
  127. data/README.mingw +0 -8
  128. data/aclocal.m4 +0 -1085
  129. data/ax_cxx_compile_stdcxx.m4 +0 -951
  130. data/bootstrap +0 -8
  131. data/config.guess +0 -1421
  132. data/config.sub +0 -1807
  133. data/configure +0 -7792
  134. data/configure.ac +0 -55
  135. data/depcomp +0 -791
  136. data/doxygen.ac +0 -314
  137. data/doxygen.am +0 -186
  138. data/extconf.rb +0 -70
  139. data/install-sh +0 -501
  140. data/missing +0 -215
  141. data/post-autoconf.rb +0 -22
  142. data/post-automake.rb +0 -28
  143. data/rice/Address_Registration_Guard.cpp +0 -22
  144. data/rice/Arg_impl.hpp +0 -129
  145. data/rice/Arg_operators.cpp +0 -21
  146. data/rice/Arg_operators.hpp +0 -19
  147. data/rice/Array.hpp +0 -214
  148. data/rice/Array.ipp +0 -256
  149. data/rice/Builtin_Object.hpp +0 -8
  150. data/rice/Builtin_Object.ipp +0 -50
  151. data/rice/Builtin_Object_defn.hpp +0 -50
  152. data/rice/Class.cpp +0 -57
  153. data/rice/Class.hpp +0 -8
  154. data/rice/Class.ipp +0 -6
  155. data/rice/Class_defn.hpp +0 -84
  156. data/rice/Data_Type.cpp +0 -54
  157. data/rice/Data_Type_fwd.hpp +0 -12
  158. data/rice/Director.cpp +0 -13
  159. data/rice/Exception.cpp +0 -54
  160. data/rice/Exception_Base.hpp +0 -8
  161. data/rice/Exception_Base.ipp +0 -13
  162. data/rice/Exception_Base_defn.hpp +0 -27
  163. data/rice/Hash.hpp +0 -230
  164. data/rice/Hash.ipp +0 -329
  165. data/rice/Identifier.cpp +0 -8
  166. data/rice/Jump_Tag.hpp +0 -24
  167. data/rice/Makefile.am +0 -121
  168. data/rice/Makefile.in +0 -884
  169. data/rice/Module.cpp +0 -84
  170. data/rice/Module.hpp +0 -8
  171. data/rice/Module.ipp +0 -6
  172. data/rice/Module_defn.hpp +0 -88
  173. data/rice/Module_impl.hpp +0 -281
  174. data/rice/Module_impl.ipp +0 -345
  175. data/rice/Object.cpp +0 -169
  176. data/rice/Object.hpp +0 -8
  177. data/rice/Object.ipp +0 -33
  178. data/rice/Object_defn.hpp +0 -214
  179. data/rice/Require_Guard.hpp +0 -21
  180. data/rice/String.cpp +0 -89
  181. data/rice/String.hpp +0 -91
  182. data/rice/Struct.cpp +0 -117
  183. data/rice/Struct.hpp +0 -162
  184. data/rice/Struct.ipp +0 -26
  185. data/rice/Symbol.cpp +0 -25
  186. data/rice/Symbol.hpp +0 -66
  187. data/rice/Symbol.ipp +0 -44
  188. data/rice/config.hpp +0 -47
  189. data/rice/config.hpp.in +0 -46
  190. data/rice/detail/Arguments.hpp +0 -118
  191. data/rice/detail/Auto_Function_Wrapper.hpp +0 -898
  192. data/rice/detail/Auto_Function_Wrapper.ipp +0 -3181
  193. data/rice/detail/Auto_Member_Function_Wrapper.hpp +0 -897
  194. data/rice/detail/Auto_Member_Function_Wrapper.ipp +0 -2501
  195. data/rice/detail/Caster.hpp +0 -103
  196. data/rice/detail/Not_Copyable.hpp +0 -25
  197. data/rice/detail/Wrapped_Function.hpp +0 -33
  198. data/rice/detail/cfp.hpp +0 -24
  199. data/rice/detail/cfp.ipp +0 -51
  200. data/rice/detail/check_ruby_type.cpp +0 -27
  201. data/rice/detail/check_ruby_type.hpp +0 -23
  202. data/rice/detail/creation_funcs.hpp +0 -37
  203. data/rice/detail/creation_funcs.ipp +0 -36
  204. data/rice/detail/define_method_and_auto_wrap.hpp +0 -31
  205. data/rice/detail/define_method_and_auto_wrap.ipp +0 -30
  206. data/rice/detail/demangle.cpp +0 -56
  207. data/rice/detail/demangle.hpp +0 -19
  208. data/rice/detail/env.hpp +0 -11
  209. data/rice/detail/method_data.cpp +0 -92
  210. data/rice/detail/node.hpp +0 -13
  211. data/rice/detail/protect.cpp +0 -29
  212. data/rice/detail/protect.hpp +0 -34
  213. data/rice/detail/ruby_version_code.hpp +0 -6
  214. data/rice/detail/ruby_version_code.hpp.in +0 -6
  215. data/rice/detail/st.hpp +0 -22
  216. data/rice/detail/win32.hpp +0 -16
  217. data/rice/detail/wrap_function.hpp +0 -66
  218. data/rice/protect.hpp +0 -38
  219. data/rice/protect.ipp +0 -1134
  220. data/rice/rubypp.rb +0 -97
  221. data/rice/to_from_ruby.hpp +0 -8
  222. data/rice/to_from_ruby.ipp +0 -418
  223. data/rice/to_from_ruby_defn.hpp +0 -70
  224. data/ruby.ac +0 -135
  225. data/ruby/Makefile.am +0 -1
  226. data/ruby/Makefile.in +0 -628
  227. data/ruby/lib/Makefile.am +0 -3
  228. data/ruby/lib/Makefile.in +0 -506
  229. data/ruby/lib/mkmf-rice.rb.in +0 -217
  230. data/ruby/lib/version.rb +0 -3
  231. data/sample/Makefile.am +0 -53
  232. data/sample/Makefile.in +0 -495
  233. data/test/Makefile.am +0 -73
  234. data/test/Makefile.in +0 -1219
  235. data/test/ext/Makefile.am +0 -41
  236. data/test/ext/Makefile.in +0 -483
  237. data/test/test_rice.rb +0 -45
@@ -1,11 +1,11 @@
1
1
  #ifndef Rice__Data_Object_defn__hpp_
2
2
  #define Rice__Data_Object_defn__hpp_
3
3
 
4
- #include "Object_defn.hpp"
5
- #include "Data_Type_fwd.hpp"
6
- #include "ruby_mark.hpp"
4
+ #include <optional>
5
+
7
6
  #include "detail/to_ruby.hpp"
8
7
  #include "detail/ruby.hpp"
8
+ #include "cpp_api/Object_defn.hpp"
9
9
 
10
10
  /*! \file
11
11
  * \brief Provides a helper class for wrapping and unwrapping C++
@@ -14,124 +14,84 @@
14
14
 
15
15
  namespace Rice
16
16
  {
17
-
18
- template<typename T>
19
- struct Default_Mark_Function
20
- {
21
- typedef void (*Ruby_Data_Func)(T * obj);
22
- static const Ruby_Data_Func mark;
23
- };
24
-
25
- template<typename T>
26
- struct Default_Free_Function
27
- {
28
- static void free(T * obj) { delete obj; }
29
- };
30
-
31
-
32
- //! A smartpointer-like wrapper for Ruby data objects.
33
- /*! A data object is a ruby object of type T_DATA, which is usually
34
- * created by using the Data_Wrap_Struct or Data_Make_Struct macro.
35
- * This class wraps creation of the data structure, providing a
36
- * type-safe object-oriented interface to the underlying C interface.
37
- * This class works in conjunction with the Data_Type class to ensure
38
- * type safety.
39
- *
40
- * Example:
41
- * \code
42
- * class Foo { };
43
- * ...
44
- * Data_Type<Foo> rb_cFoo = define_class("Foo");
45
- * ...
46
- * // Wrap:
47
- * Data_Object<Foo> foo1(new Foo);
48
- *
49
- * // Get value to return:
50
- * VALUE v = foo1.value()
51
- *
52
- * // Unwrap:
53
- * Data_Object<Foo> foo2(v, rb_cFoo);
54
- * \endcode
55
- */
56
- template<typename T>
57
- class Data_Object
58
- : public Object
59
- {
60
- public:
61
- //! A function that takes a T* and returns void.
62
- typedef void (*Ruby_Data_Func)(T * obj);
63
-
64
- //! Wrap a C++ object.
65
- /*! This constructor is analogous to calling Data_Wrap_Struct. Be
66
- * careful not to call this function more than once for the same
67
- * pointer (in general, it should only be called for newly
68
- * constructed objects that need to be managed by Ruby's garbage
69
- * collector).
70
- * \param obj the object to wrap.
71
- * \param klass the Ruby class to use for the newly created Ruby
72
- * object.
73
- * \param mark_func a function that gets called by the garbage
74
- * collector to mark the object's children.
75
- * \param free_func a function that gets called by the garbage
76
- * collector to free the object.
77
- */
78
- Data_Object(
79
- T * obj,
80
- VALUE klass = Data_Type<T>::klass(),
81
- Ruby_Data_Func mark_func = Default_Mark_Function<T>::mark,
82
- Ruby_Data_Func free_func = Default_Free_Function<T>::free);
83
-
84
- //! Unwrap a Ruby object.
85
- /*! This constructor is analogous to calling Data_Get_Struct. Uses
86
- * Data_Type<T>::klass as the class of the object.
87
- * \param value the Ruby object to unwrap.
17
+ //! A smartpointer-like wrapper for Ruby data objects.
18
+ /*! A data object is a ruby object of type T_DATA, which is usually
19
+ * created by using the Data_Wrap_Struct or Data_Make_Struct macro.
20
+ * This class wraps creation of the data structure, providing a
21
+ * type-safe object-oriented interface to the underlying C interface.
22
+ * This class works in conjunction with the Data_Type class to ensure
23
+ * type safety.
24
+ *
25
+ * Example:
26
+ * \code
27
+ * class Foo { };
28
+ * ...
29
+ * Data_Type<Foo> rb_cFoo = define_class("Foo");
30
+ * ...
31
+ * // Wrap:
32
+ * Data_Object<Foo> foo1(new Foo);
33
+ *
34
+ * // Get value to return:
35
+ * VALUE v = foo1.value()
36
+ *
37
+ * // Unwrap:
38
+ * Data_Object<Foo> foo2(v, rb_cFoo);
39
+ * \endcode
88
40
  */
89
- Data_Object(
90
- Object value);
91
-
92
- //! Unwrap a Ruby object.
93
- /*! This constructor is analogous to calling Data_Get_Struct. Will
94
- * throw an exception if the class of the object differs from the
95
- * specified class.
96
- * \param value the Ruby object to unwrap.
97
- * \param klass the expected class of the object.
98
- */
99
- template<typename U>
100
- Data_Object(
101
- Object value,
102
- Data_Type<U> const & klass = Data_Type<T>::klass());
103
-
104
- //! Make a copy of a Data_Object
105
- /*! \param other the Data_Object to copy.
106
- */
107
- Data_Object(Data_Object const & other);
108
-
109
- T & operator*() const { return *obj_; } //!< Return a reference to obj_
110
- T * operator->() const { return obj_; } //!< Return a pointer to obj_
111
- T * get() const { return obj_; } //!< Return a pointer to obj_
112
-
113
- //! Swap with another data object of the same type
114
- /*! \param ref the object with which to swap.
115
- */
116
- template<typename U>
117
- void swap(Data_Object<U> & ref);
118
-
119
- private:
120
- static void check_cpp_type(Data_Type<T> const & klass);
121
-
122
- private:
123
- T * obj_;
124
- };
125
-
126
- namespace detail
127
- {
128
41
  template<typename T>
129
- struct to_ruby_<Data_Object<T> >
42
+ class Data_Object : public Object
130
43
  {
131
- static Rice::Object convert(Data_Object<T> const & x);
44
+ static_assert(!std::is_pointer_v<T>);
45
+ static_assert(!std::is_reference_v<T>);
46
+ static_assert(!std::is_const_v<T>);
47
+ static_assert(!std::is_volatile_v<T>);
48
+
49
+ public:
50
+ static T* from_ruby(VALUE value);
51
+ static std::optional<T> implicit_from_ruby(VALUE value);
52
+
53
+ public:
54
+ //! Wrap a C++ object.
55
+ /*! This constructor is analogous to calling Data_Wrap_Struct. Be
56
+ * careful not to call this function more than once for the same
57
+ * pointer (in general, it should only be called for newly
58
+ * constructed objects that need to be managed by Ruby's garbage
59
+ * collector).
60
+ * \param obj the object to wrap.
61
+ * \param klass the Ruby class to use for the newly created Ruby
62
+ * object.
63
+ * \param mark_func a function that gets called by the garbage
64
+ * collector to mark the object's children.
65
+ * \param free_func a function that gets called by the garbage
66
+ * collector to free the object.
67
+ */
68
+ Data_Object(T* obj, bool isOwner = false, Class klass = Data_Type<T>::klass());
69
+ Data_Object(T& obj, bool isOwner = false, Class klass = Data_Type<T>::klass());
70
+
71
+ //! Unwrap a Ruby object.
72
+ /*! This constructor is analogous to calling Data_Get_Struct. Uses
73
+ * Data_Type<T>::klass as the class of the object.
74
+ * \param value the Ruby object to unwrap.
75
+ */
76
+ Data_Object(Object value);
77
+
78
+ //! Unwrap a Ruby object.
79
+ /*! This constructor is analogous to calling Data_Get_Struct. Will
80
+ * throw an exception if the class of the object differs from the
81
+ * specified class.
82
+ * \param value the Ruby object to unwrap.
83
+ * \param klass the expected class of the object.
84
+ */
85
+ template<typename U>
86
+ Data_Object(Object value);
87
+
88
+ T& operator*() const; //!< Return a reference to obj_
89
+ T* operator->() const; //!< Return a pointer to obj_
90
+ T* get() const; //!< Return a pointer to obj_
91
+
92
+ private:
93
+ static void check_ruby_type(VALUE value);
132
94
  };
133
- }
134
-
135
95
  } // namespace Rice
136
96
 
137
97
  #endif // Rice__Data_Object_defn__hpp_
data/rice/Data_Type.hpp CHANGED
@@ -4,5 +4,4 @@
4
4
  #include "Data_Type_defn.hpp"
5
5
  #include "Data_Type.ipp"
6
6
 
7
- #endif // Rice__Data_Type__hpp_
8
-
7
+ #endif // Rice__Data_Type__hpp_
data/rice/Data_Type.ipp CHANGED
@@ -1,365 +1,321 @@
1
1
  #ifndef Rice__Data_Type__ipp_
2
2
  #define Rice__Data_Type__ipp_
3
3
 
4
+ #include "detail/method_data.hpp"
5
+ #include "detail/NativeAttribute.hpp"
6
+ #include "detail/default_allocation_func.hpp"
7
+ #include "detail/TypeRegistry.hpp"
8
+ #include "detail/Wrapper.hpp"
9
+ #include "detail/Iterator.hpp"
4
10
  #include "Class.hpp"
5
11
  #include "String.hpp"
6
- #include "Data_Object.hpp"
7
- #include "detail/default_allocation_func.hpp"
8
- #include "detail/creation_funcs.hpp"
9
- #include "detail/method_data.hpp"
10
- #include "detail/Caster.hpp"
11
- #include "detail/demangle.hpp"
12
12
 
13
13
  #include <stdexcept>
14
- #include <typeinfo>
15
14
 
16
- template<typename T>
17
- VALUE Rice::Data_Type<T>::klass_ = Qnil;
15
+ namespace Rice
16
+ {
17
+ template<typename T>
18
+ void ruby_mark_internal(detail::Wrapper* wrapper)
19
+ {
20
+ // Tell the wrapper to mark the objects its keeping alive
21
+ wrapper->ruby_mark();
18
22
 
19
- template<typename T>
20
- std_unique_ptr<Rice::detail::Abstract_Caster> Rice::Data_Type<T>::caster_;
23
+ // Get the underlying data and call custom mark function (if any)
24
+ T* data = static_cast<T*>(wrapper->get());
25
+ ruby_mark<T>(data);
26
+ }
21
27
 
22
- template<typename T>
23
- template<typename Base_T>
24
- inline Rice::Data_Type<T> Rice::Data_Type<T>::
25
- bind(Module const & klass)
26
- {
27
- if(klass.value() == klass_)
28
+ template<typename T>
29
+ void ruby_free_internal(detail::Wrapper* wrapper)
28
30
  {
29
- return Data_Type<T>();
31
+ delete wrapper;
30
32
  }
31
33
 
32
- if(is_bound())
34
+ template<typename T>
35
+ size_t ruby_size_internal(const T* data)
33
36
  {
34
- std::string s;
35
- s = "Data type ";
36
- s += detail::demangle(typeid(T).name());
37
- s += " is already bound to a different type";
38
- throw std::runtime_error(s.c_str());
37
+ return sizeof(T);
39
38
  }
40
39
 
41
- // TODO: Make sure base type is bound; throw an exception otherwise.
42
- // We can't do this just yet, because we don't have a specialization
43
- // for binding to void.
44
- klass_ = klass;
40
+ template<typename T>
41
+ template <typename Base_T>
42
+ inline Data_Type<T> Data_Type<T>::bind(Module const& klass)
43
+ {
44
+ if (is_bound())
45
+ {
46
+ std::string message = "Type " + detail::typeName(typeid(T)) + " is already bound to a different type";
47
+ throw std::runtime_error(message.c_str());
48
+ }
49
+
50
+ klass_ = klass;
45
51
 
46
- // TODO: do we need to unregister when the program exits? we have to
47
- // be careful if we do, because the ruby interpreter might have
48
- // already shut down. The correct behavior is probably to register an
49
- // exit proc with the interpreter, so the proc gets called before the
50
- // GC shuts down.
51
- rb_gc_register_address(&klass_);
52
+ rb_type_ = new rb_data_type_t();
53
+ rb_type_->wrap_struct_name = strdup(Rice::detail::protect(rb_class2name, klass_));
54
+ rb_type_->function.dmark = reinterpret_cast<void(*)(void*)>(&Rice::ruby_mark_internal<T>);
55
+ rb_type_->function.dfree = reinterpret_cast<void(*)(void*)>(&Rice::ruby_free_internal<T>);
56
+ rb_type_->function.dsize = reinterpret_cast<size_t(*)(const void*)>(&Rice::ruby_size_internal<T>);
57
+ rb_type_->data = nullptr;
58
+ rb_type_->flags = RUBY_TYPED_FREE_IMMEDIATELY;
52
59
 
53
- for(typename Instances::iterator it = unbound_instances().begin(),
60
+ if constexpr (!std::is_void_v<Base_T>)
61
+ {
62
+ rb_type_->parent = Data_Type<Base_T>::rb_type();
63
+ }
64
+
65
+ // Now register with the type registry
66
+ detail::TypeRegistry::add<T>(klass_, rb_type_);
67
+
68
+ for (typename Instances::iterator it = unbound_instances().begin(),
54
69
  end = unbound_instances().end();
55
70
  it != end;
56
71
  unbound_instances().erase(it++))
72
+ {
73
+ (*it)->set_value(klass);
74
+ }
75
+
76
+ return Data_Type<T>();
77
+ }
78
+
79
+ template<typename T>
80
+ inline void Data_Type<T>::unbind()
57
81
  {
58
- (*it)->set_value(klass);
82
+ detail::TypeRegistry::remove<T>();
83
+
84
+ if (klass_ != Qnil)
85
+ {
86
+ klass_ = Qnil;
87
+ }
88
+
89
+ // There could be objects floating around using the existing rb_type so
90
+ // do not delete it. This is of course a memory leak.
91
+ rb_type_ = nullptr;
59
92
  }
60
93
 
61
- detail::Abstract_Caster * base_caster = Data_Type<Base_T>().caster();
62
- caster_.reset(new detail::Caster<T, Base_T>(base_caster, klass));
63
- Data_Type_Base::casters().insert(std::make_pair(klass, caster_.get()));
64
- return Data_Type<T>();
65
- }
94
+ template<typename T>
95
+ inline Data_Type<T>::Data_Type() : Class(klass_ == Qnil ? rb_cObject : klass_)
96
+ {
97
+ if (!is_bound())
98
+ {
99
+ unbound_instances().insert(this);
100
+ }
101
+ }
66
102
 
67
- template<typename T>
68
- inline Rice::Data_Type<T>::
69
- Data_Type()
70
- : Module_impl<Data_Type_Base, Data_Type<T> >(
71
- klass_ == Qnil ? rb_cObject : klass_)
72
- {
73
- if(!is_bound())
103
+ template<typename T>
104
+ inline Data_Type<T>::Data_Type(Module const& klass) : Class(klass)
74
105
  {
75
- unbound_instances().insert(this);
106
+ this->bind(klass);
76
107
  }
77
- }
78
108
 
79
- template<typename T>
80
- inline Rice::Data_Type<T>::
81
- Data_Type(Module const & klass)
82
- : Module_impl<Data_Type_Base, Data_Type<T> >(
83
- klass)
84
- {
85
- this->bind<void>(klass);
86
- }
109
+ template<typename T>
110
+ inline Data_Type<T>::~Data_Type()
111
+ {
112
+ unbound_instances().erase(this);
113
+ }
87
114
 
88
- template<typename T>
89
- inline Rice::Data_Type<T>::
90
- ~Data_Type()
91
- {
92
- unbound_instances().erase(this);
93
- }
115
+ template<typename T>
116
+ inline rb_data_type_t* Data_Type<T>::rb_type()
117
+ {
118
+ check_is_bound();
119
+ return rb_type_;
120
+ }
94
121
 
95
- template<typename T>
96
- Rice::Module
97
- Rice::Data_Type<T>::
98
- klass() {
99
- if(is_bound())
122
+ template<typename T>
123
+ inline Class Data_Type<T>::klass()
100
124
  {
125
+ check_is_bound();
101
126
  return klass_;
102
127
  }
103
- else
128
+
129
+ template<typename T>
130
+ inline Data_Type<T>& Data_Type<T>::operator=(Module const& klass)
104
131
  {
105
- std::string s;
106
- s += detail::demangle(typeid(T *).name());
107
- s += " is unbound";
108
- throw std::runtime_error(s.c_str());
132
+ this->bind(klass);
133
+ return *this;
109
134
  }
110
- }
111
135
 
112
- template<typename T>
113
- Rice::Data_Type<T> & Rice::Data_Type<T>::
114
- operator=(Module const & klass)
115
- {
116
- this->bind<void>(klass);
117
- return *this;
118
- }
119
-
120
- template<typename T>
121
- template<typename Constructor_T>
122
- inline Rice::Data_Type<T> & Rice::Data_Type<T>::
123
- define_constructor(
124
- Constructor_T /* constructor */,
125
- Arguments* arguments)
126
- {
127
- check_is_bound();
128
-
129
- // Normal constructor pattern with new/initialize
130
- rb_define_alloc_func(
131
- static_cast<VALUE>(*this),
132
- detail::default_allocation_func<T>);
133
- this->define_method(
134
- "initialize",
135
- &Constructor_T::construct,
136
- arguments
137
- );
138
-
139
- return *this;
140
- }
136
+ template<typename T>
137
+ template<typename Constructor_T>
138
+ inline Data_Type<T>& Data_Type<T>::define_constructor(Constructor_T, MethodInfo* methodInfo)
139
+ {
140
+ check_is_bound();
141
141
 
142
- template<typename T>
143
- template<typename Constructor_T>
144
- inline Rice::Data_Type<T> & Rice::Data_Type<T>::
145
- define_constructor(
146
- Constructor_T constructor,
147
- Arg const& arg)
148
- {
149
- Arguments* args = new Arguments();
150
- args->add(arg);
151
- return define_constructor(constructor, args);
152
- }
142
+ // Normal constructor pattern with new/initialize
143
+ detail::protect(rb_define_alloc_func, static_cast<VALUE>(*this), detail::default_allocation_func<T>);
144
+ this->define_method("initialize", &Constructor_T::construct, methodInfo);
153
145
 
146
+ return *this;
147
+ }
154
148
 
155
- template<typename T>
156
- template<typename Director_T>
157
- inline Rice::Data_Type<T>& Rice::Data_Type<T>::
158
- define_director()
159
- {
160
- Rice::Data_Type<Director_T>::template bind<T>(*this);
161
- return *this;
162
- }
149
+ template<typename T>
150
+ template<typename Constructor_T, typename...Arg_Ts>
151
+ inline Data_Type<T>& Data_Type<T>::define_constructor(Constructor_T constructor, Arg_Ts const& ...args)
152
+ {
153
+ check_is_bound();
163
154
 
164
- template<typename T>
165
- inline T * Rice::Data_Type<T>::
166
- from_ruby(Object x)
167
- {
168
- check_is_bound();
155
+ // Define a Ruby allocator which creates the Ruby object
156
+ detail::protect(rb_define_alloc_func, static_cast<VALUE>(*this), detail::default_allocation_func<T>);
169
157
 
170
- void * v = DATA_PTR(x.value());
171
- Class klass = x.class_of();
158
+ // Define an initialize function that will create the C++ object
159
+ this->define_method("initialize", &Constructor_T::construct, args...);
172
160
 
173
- if(klass.value() == klass_)
174
- {
175
- // Great, not converting to a base/derived type
176
- Data_Type<T> data_klass;
177
- Data_Object<T> obj(x, data_klass);
178
- return obj.get();
161
+ return *this;
179
162
  }
180
163
 
181
- Data_Type_Base::Casters::const_iterator it = Data_Type_Base::casters().begin();
182
- Data_Type_Base::Casters::const_iterator end = Data_Type_Base::casters().end();
183
-
184
- // Finding the bound type that relates to the given klass is
185
- // a two step process. We iterate over the list of known type casters,
186
- // looking for:
187
- //
188
- // 1) casters that handle this direct type
189
- // 2) casters that handle types that are ancestors of klass
190
- //
191
- // Step 2 allows us to handle the case where a Rice-wrapped class
192
- // is subclassed in Ruby but then an instance of that class is passed
193
- // back into C++ (say, in a Listener / callback construction)
194
- //
195
-
196
- VALUE ancestors = rb_mod_ancestors(klass.value());
197
-
198
- long earliest = RARRAY_LEN(ancestors) + 1;
199
-
200
- int index;
201
- VALUE indexFound;
202
- Data_Type_Base::Casters::const_iterator toUse = end;
203
-
204
- for(; it != end; it++) {
205
- // Do we match directly?
206
- if(klass.value() == it->first) {
207
- toUse = it;
208
- break;
164
+ template<typename T>
165
+ template<typename Director_T>
166
+ inline Data_Type<T>& Data_Type<T>::define_director()
167
+ {
168
+ if (!detail::TypeRegistry::isDefined<Director_T>())
169
+ {
170
+ Data_Type<Director_T>::bind(*this);
209
171
  }
210
172
 
211
- // Check for ancestors. Trick is, we need to find the lowest
212
- // ancestor that does have a Caster to make sure that we're casting
213
- // to the closest C++ type that the Ruby class is subclassing.
214
- // There might be multiple ancestors that are also wrapped in
215
- // the extension, so find the earliest in the list and use that one.
216
- indexFound = rb_funcall(ancestors, rb_intern("index"), 1, it->first);
173
+ // TODO - hack to fake Ruby into thinking that a Director is
174
+ // the same as the base data type
175
+ Data_Type<Director_T>::rb_type_ = Data_Type<T>::rb_type_;
176
+ return *this;
177
+ }
217
178
 
218
- if(indexFound != Qnil) {
219
- index = NUM2INT(indexFound);
179
+ template<typename T>
180
+ inline bool Data_Type<T>::is_bound()
181
+ {
182
+ return klass_ != Qnil;
183
+ }
220
184
 
221
- if(index < earliest) {
222
- earliest = index;
223
- toUse = it;
224
- }
185
+ template<typename T>
186
+ inline bool Data_Type<T>::is_descendant(VALUE value)
187
+ {
188
+ check_is_bound();
189
+ return detail::protect(rb_obj_is_kind_of, value, klass_) == Qtrue;
190
+ }
191
+
192
+ template<typename T>
193
+ inline void Data_Type<T>::check_is_bound()
194
+ {
195
+ if (!is_bound())
196
+ {
197
+ std::string message = "Type " + detail::typeName(typeid(T)) + " is not bound";
198
+ throw std::runtime_error(message.c_str());
225
199
  }
226
200
  }
227
-
228
- if(toUse == end)
201
+
202
+ template<typename T, typename Base_T>
203
+ inline Data_Type<T> define_class_under(Object module, char const* name)
229
204
  {
230
- std::string s = "Class ";
231
- s += klass.name().str();
232
- s += " is not registered/bound in Rice";
233
- throw std::runtime_error(s);
205
+ if (detail::TypeRegistry::isDefined<T>())
206
+ {
207
+ return Data_Type<T>();
208
+ }
209
+
210
+ Class superKlass;
211
+
212
+ if constexpr (std::is_void_v<Base_T>)
213
+ {
214
+ superKlass = rb_cObject;
215
+ }
216
+ else
217
+ {
218
+ superKlass = Data_Type<Base_T>::klass();
219
+ }
220
+
221
+ Class c = define_class_under(module, name, superKlass);
222
+ c.undef_creation_funcs();
223
+ return Data_Type<T>::template bind<Base_T>(c);
234
224
  }
235
225
 
236
- detail::Abstract_Caster * caster = toUse->second;
237
- if(caster)
226
+ template<typename T, typename Base_T>
227
+ inline Data_Type<T> define_class(char const* name)
238
228
  {
239
- T * result = static_cast<T *>(caster->cast_to_base(v, klass_));
240
- return result;
229
+ if (detail::TypeRegistry::isDefined<T>())
230
+ {
231
+ return Data_Type<T>();
232
+ }
233
+
234
+ Class superKlass;
235
+ if constexpr (std::is_void_v<Base_T>)
236
+ {
237
+ superKlass = rb_cObject;
238
+ }
239
+ else
240
+ {
241
+ superKlass = Data_Type<Base_T>::klass();
242
+ }
243
+
244
+ Class c = define_class(name, superKlass);
245
+ c.undef_creation_funcs();
246
+ return Data_Type<T>::template bind<Base_T>(c);
241
247
  }
242
- else
248
+
249
+ template<typename T>
250
+ template<typename U, typename Iterator_T>
251
+ inline Data_Type<T>& Data_Type<T>::define_iterator(Iterator_T(U::* begin)(), Iterator_T(U::* end)(), Identifier name)
243
252
  {
244
- return static_cast<T *>(v);
253
+ using Iter_T = detail::Iterator<U, Iterator_T>;
254
+ Iter_T* iterator = new Iter_T(begin, end);
255
+ detail::MethodData::define_method(Data_Type<T>::klass(), name,
256
+ (RUBY_METHOD_FUNC)iterator->call, 0, iterator);
257
+
258
+ return *this;
245
259
  }
246
- }
247
260
 
248
- template<typename T>
249
- inline bool Rice::Data_Type<T>::
250
- is_bound()
251
- {
252
- return klass_ != Qnil;
253
- }
261
+ template <typename T>
262
+ template <typename Attr_T>
263
+ inline Data_Type<T>& Data_Type<T>::define_attr(std::string name, Attr_T attr, AttrAccess access)
264
+ {
265
+ auto* native = detail::Make_Native_Attribute(attr, access);
266
+ using Native_T = typename std::remove_pointer_t<decltype(native)>;
254
267
 
255
- template<typename T>
256
- inline Rice::detail::Abstract_Caster * Rice::Data_Type<T>::
257
- caster() const
258
- {
259
- check_is_bound();
260
- return caster_.get();
261
- }
268
+ detail::verifyType<typename Native_T::Native_Return_T>();
262
269
 
263
- namespace Rice
264
- {
270
+ if (access == AttrAccess::ReadWrite || access == AttrAccess::Read)
271
+ {
272
+ detail::MethodData::define_method( klass_, Identifier(name).id(),
273
+ RUBY_METHOD_FUNC(&Native_T::get), 0, native);
274
+ }
265
275
 
266
- template<>
267
- inline detail::Abstract_Caster * Data_Type<void>::
268
- caster() const
269
- {
270
- return 0;
271
- }
276
+ if (access == AttrAccess::ReadWrite || access == AttrAccess::Write)
277
+ {
278
+ if (std::is_const_v<std::remove_pointer_t<Attr_T>>)
279
+ {
280
+ throw std::runtime_error(name + " is readonly");
281
+ }
272
282
 
273
- template<typename T>
274
- void Data_Type<T>::
275
- check_is_bound()
276
- {
277
- if(!is_bound())
278
- {
279
- std::string s;
280
- s = "Data type ";
281
- s += detail::demangle(typeid(T).name());
282
- s += " is not bound";
283
- throw std::runtime_error(s.c_str());
283
+ detail::MethodData::define_method( klass_, Identifier(name + "=").id(),
284
+ RUBY_METHOD_FUNC(&Native_T::set), 1, native);
285
+ }
286
+
287
+ return *this;
284
288
  }
285
- }
286
289
 
287
- } // Rice
290
+ template <typename T>
291
+ template <typename Attr_T>
292
+ inline Data_Type<T>& Data_Type<T>::define_singleton_attr(std::string name, Attr_T attr, AttrAccess access)
293
+ {
294
+ auto* native = detail::Make_Native_Attribute(attr, access);
295
+ using Native_T = typename std::remove_pointer_t<decltype(native)>;
288
296
 
289
- template<typename T>
290
- inline Rice::Data_Type<T> Rice::
291
- define_class_under(
292
- Object module,
293
- char const * name)
294
- {
295
- Class c(define_class_under(module, name, rb_cObject));
296
- c.undef_creation_funcs();
297
- return Data_Type<T>::template bind<void>(c);
298
- }
297
+ detail::verifyType<typename Native_T::Native_Return_T>();
299
298
 
300
- template<typename T, typename Base_T>
301
- inline Rice::Data_Type<T> Rice::
302
- define_class_under(
303
- Object module,
304
- char const * name)
305
- {
306
- Data_Type<Base_T> base_dt;
307
- Class c(define_class_under(module, name, base_dt));
308
- c.undef_creation_funcs();
309
- return Data_Type<T>::template bind<Base_T>(c);
310
- }
299
+ if (access == AttrAccess::ReadWrite || access == AttrAccess::Read)
300
+ {
301
+ VALUE singleton = detail::protect(rb_singleton_class, this->value());
302
+ detail::MethodData::define_method(singleton, Identifier(name).id(),
303
+ RUBY_METHOD_FUNC(&Native_T::get), 0, native);
304
+ }
311
305
 
312
- template<typename T>
313
- inline Rice::Data_Type<T> Rice::
314
- define_class(
315
- char const * name)
316
- {
317
- Class c(define_class(name, rb_cObject));
318
- c.undef_creation_funcs();
319
- return Data_Type<T>::template bind<void>(c);
320
- }
306
+ if (access == AttrAccess::ReadWrite || access == AttrAccess::Write)
307
+ {
308
+ if (std::is_const_v<std::remove_pointer_t<Attr_T>>)
309
+ {
310
+ throw std::runtime_error(name + " is readonly");
311
+ }
321
312
 
322
- template<typename T, typename Base_T>
323
- inline Rice::Data_Type<T> Rice::
324
- define_class(
325
- char const * name)
326
- {
327
- Data_Type<Base_T> base_dt;
328
- Class c(define_class(name, base_dt));
329
- c.undef_creation_funcs();
330
- return Data_Type<T>::template bind<Base_T>(c);
331
- }
313
+ VALUE singleton = detail::protect(rb_singleton_class, this->value());
314
+ detail::MethodData::define_method(singleton, Identifier(name + "=").id(),
315
+ RUBY_METHOD_FUNC(&Native_T::set), 1, native);
316
+ }
332
317
 
333
- template<typename From_T, typename To_T>
334
- inline void
335
- Rice::define_implicit_cast()
336
- {
337
- // As Rice currently expects only one entry into
338
- // this list for a given klass VALUE, we need to get
339
- // the current caster for From_T and insert in our
340
- // new caster as the head of the caster list
341
-
342
- Class from_class = Data_Type<From_T>::klass().value();
343
- Class to_class = Data_Type<To_T>::klass().value();
344
-
345
- detail::Abstract_Caster* from_caster =
346
- Data_Type<From_T>::caster_.release();
347
-
348
- detail::Abstract_Caster* new_caster =
349
- new detail::Implicit_Caster<To_T, From_T>(from_caster, to_class);
350
-
351
- // Insert our new caster into the list for the from class
352
- Data_Type_Base::casters().erase(from_class);
353
- Data_Type_Base::casters().insert(
354
- std::make_pair(
355
- from_class,
356
- new_caster
357
- )
358
- );
359
-
360
- // And make sure the from_class has direct access to the
361
- // updated caster list
362
- Data_Type<From_T>::caster_.reset(new_caster);
318
+ return *this;
319
+ }
363
320
  }
364
-
365
- #endif // Rice__Data_Type__ipp_
321
+ #endif