rice 4.3.2 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -25
  3. data/README.md +7 -2
  4. data/Rakefile +7 -1
  5. data/include/rice/rice.hpp +7321 -4470
  6. data/include/rice/stl.hpp +769 -222
  7. data/lib/mkmf-rice.rb +37 -95
  8. data/rice/Address_Registration_Guard.hpp +72 -3
  9. data/rice/Arg.hpp +19 -5
  10. data/rice/Arg.ipp +24 -0
  11. data/rice/Callback.hpp +21 -0
  12. data/rice/Callback.ipp +13 -0
  13. data/rice/Constructor.hpp +4 -27
  14. data/rice/Constructor.ipp +79 -0
  15. data/rice/Data_Object.hpp +74 -3
  16. data/rice/Data_Object.ipp +324 -32
  17. data/rice/Data_Type.hpp +215 -3
  18. data/rice/Data_Type.ipp +125 -64
  19. data/rice/Director.hpp +0 -2
  20. data/rice/Enum.hpp +4 -6
  21. data/rice/Enum.ipp +101 -57
  22. data/rice/Exception.hpp +62 -2
  23. data/rice/Exception.ipp +7 -12
  24. data/rice/JumpException.hpp +44 -0
  25. data/rice/JumpException.ipp +48 -0
  26. data/rice/MemoryView.hpp +11 -0
  27. data/rice/MemoryView.ipp +43 -0
  28. data/rice/Return.hpp +6 -26
  29. data/rice/Return.ipp +10 -16
  30. data/rice/detail/DefaultHandler.hpp +12 -0
  31. data/rice/detail/DefaultHandler.ipp +8 -0
  32. data/rice/detail/HandlerRegistry.hpp +5 -35
  33. data/rice/detail/HandlerRegistry.ipp +7 -11
  34. data/rice/detail/InstanceRegistry.hpp +1 -4
  35. data/rice/detail/MethodInfo.hpp +15 -5
  36. data/rice/detail/MethodInfo.ipp +78 -6
  37. data/rice/detail/Native.hpp +32 -0
  38. data/rice/detail/Native.ipp +129 -0
  39. data/rice/detail/NativeAttributeGet.hpp +51 -0
  40. data/rice/detail/NativeAttributeGet.ipp +51 -0
  41. data/rice/detail/NativeAttributeSet.hpp +43 -0
  42. data/rice/detail/NativeAttributeSet.ipp +82 -0
  43. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  44. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  45. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  46. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  47. data/rice/detail/NativeFunction.hpp +20 -21
  48. data/rice/detail/NativeFunction.ipp +199 -64
  49. data/rice/detail/NativeIterator.hpp +8 -11
  50. data/rice/detail/NativeIterator.ipp +27 -31
  51. data/rice/detail/NativeRegistry.hpp +24 -17
  52. data/rice/detail/NativeRegistry.ipp +23 -56
  53. data/rice/detail/Proc.hpp +4 -0
  54. data/rice/detail/Proc.ipp +85 -0
  55. data/rice/detail/Registries.hpp +0 -7
  56. data/rice/detail/Registries.ipp +0 -18
  57. data/rice/detail/RubyFunction.hpp +0 -3
  58. data/rice/detail/RubyFunction.ipp +4 -8
  59. data/rice/detail/RubyType.hpp +19 -0
  60. data/rice/detail/RubyType.ipp +187 -0
  61. data/rice/detail/TupleIterator.hpp +14 -0
  62. data/rice/detail/Type.hpp +5 -6
  63. data/rice/detail/Type.ipp +150 -33
  64. data/rice/detail/TypeRegistry.hpp +15 -7
  65. data/rice/detail/TypeRegistry.ipp +105 -12
  66. data/rice/detail/Wrapper.hpp +6 -5
  67. data/rice/detail/Wrapper.ipp +45 -23
  68. data/rice/detail/cpp_protect.hpp +5 -6
  69. data/rice/detail/default_allocation_func.ipp +0 -2
  70. data/rice/detail/from_ruby.hpp +37 -3
  71. data/rice/detail/from_ruby.ipp +911 -454
  72. data/rice/detail/ruby.hpp +18 -0
  73. data/rice/detail/to_ruby.hpp +41 -3
  74. data/rice/detail/to_ruby.ipp +437 -113
  75. data/rice/global_function.hpp +0 -4
  76. data/rice/global_function.ipp +1 -2
  77. data/rice/rice.hpp +105 -22
  78. data/rice/ruby_mark.hpp +4 -3
  79. data/rice/stl.hpp +4 -0
  80. data/test/embed_ruby.cpp +4 -1
  81. data/test/extconf.rb +2 -0
  82. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  83. data/test/test_Address_Registration_Guard.cpp +5 -0
  84. data/test/test_Array.cpp +12 -1
  85. data/test/test_Attribute.cpp +103 -21
  86. data/test/test_Builtin_Object.cpp +5 -0
  87. data/test/test_Callback.cpp +231 -0
  88. data/test/test_Class.cpp +5 -31
  89. data/test/test_Constructor.cpp +69 -6
  90. data/test/test_Data_Object.cpp +9 -4
  91. data/test/test_Data_Type.cpp +428 -64
  92. data/test/test_Director.cpp +10 -5
  93. data/test/test_Enum.cpp +152 -40
  94. data/test/test_Exception.cpp +235 -0
  95. data/test/test_File.cpp +70 -0
  96. data/test/test_From_Ruby.cpp +542 -0
  97. data/test/test_Hash.cpp +5 -0
  98. data/test/test_Identifier.cpp +5 -0
  99. data/test/test_Inheritance.cpp +6 -1
  100. data/test/test_Iterator.cpp +5 -0
  101. data/test/test_JumpException.cpp +22 -0
  102. data/test/test_Keep_Alive.cpp +6 -1
  103. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
  104. data/test/test_Memory_Management.cpp +5 -0
  105. data/test/test_Module.cpp +118 -64
  106. data/test/test_Native_Registry.cpp +2 -33
  107. data/test/test_Object.cpp +5 -0
  108. data/test/test_Overloads.cpp +631 -0
  109. data/test/test_Ownership.cpp +67 -4
  110. data/test/test_Proc.cpp +45 -0
  111. data/test/test_Self.cpp +5 -0
  112. data/test/test_Stl_Exception.cpp +109 -0
  113. data/test/test_Stl_Map.cpp +22 -8
  114. data/test/test_Stl_Optional.cpp +5 -0
  115. data/test/test_Stl_Pair.cpp +7 -2
  116. data/test/test_Stl_Reference_Wrapper.cpp +5 -0
  117. data/test/test_Stl_SmartPointer.cpp +210 -5
  118. data/test/test_Stl_String.cpp +5 -0
  119. data/test/test_Stl_String_View.cpp +5 -0
  120. data/test/test_Stl_Type.cpp +147 -0
  121. data/test/test_Stl_Unordered_Map.cpp +18 -7
  122. data/test/test_Stl_Variant.cpp +5 -0
  123. data/test/test_Stl_Vector.cpp +130 -8
  124. data/test/test_String.cpp +5 -0
  125. data/test/test_Struct.cpp +5 -0
  126. data/test/test_Symbol.cpp +5 -0
  127. data/test/test_Template.cpp +192 -0
  128. data/test/test_To_Ruby.cpp +152 -0
  129. data/test/test_Tracking.cpp +1 -0
  130. data/test/test_Type.cpp +100 -0
  131. data/test/test_global_functions.cpp +53 -6
  132. data/test/unittest.cpp +8 -0
  133. metadata +37 -20
  134. data/lib/version.rb +0 -3
  135. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  136. data/rice/Data_Object_defn.hpp +0 -84
  137. data/rice/Data_Type_defn.hpp +0 -190
  138. data/rice/Exception_defn.hpp +0 -68
  139. data/rice/HandlerRegistration.hpp +0 -15
  140. data/rice/Identifier.hpp +0 -50
  141. data/rice/Identifier.ipp +0 -29
  142. data/rice/detail/ExceptionHandler.hpp +0 -8
  143. data/rice/detail/ExceptionHandler.ipp +0 -28
  144. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  145. data/rice/detail/Jump_Tag.hpp +0 -21
  146. data/rice/detail/NativeAttribute.hpp +0 -64
  147. data/rice/detail/NativeAttribute.ipp +0 -112
  148. data/rice/detail/from_ruby_defn.hpp +0 -38
  149. data/rice/detail/to_ruby_defn.hpp +0 -48
  150. data/test/test_Jump_Tag.cpp +0 -17
  151. data/test/test_To_From_Ruby.cpp +0 -399
data/rice/Data_Object.ipp CHANGED
@@ -1,7 +1,3 @@
1
- #ifndef Rice__Data_Object__ipp_
2
- #define Rice__Data_Object__ipp_
3
-
4
- #include "Data_Type_defn.hpp"
5
1
 
6
2
  #include <algorithm>
7
3
 
@@ -22,6 +18,13 @@ namespace Rice
22
18
  this->set_value(value);
23
19
  }
24
20
 
21
+ template<typename T>
22
+ inline Data_Object<T>::Data_Object(const T& data, bool isOwner, Class klass)
23
+ {
24
+ VALUE value = detail::wrap(klass, Data_Type<T>::ruby_data_type(), data, isOwner);
25
+ this->set_value(value);
26
+ }
27
+
25
28
  template<typename T>
26
29
  inline Data_Object<T>::Data_Object(T* data, bool isOwner, Class klass)
27
30
  {
@@ -65,16 +68,16 @@ namespace Rice
65
68
  }
66
69
  else
67
70
  {
68
- return detail::unwrap<T>(this->value(), Data_Type<T>::ruby_data_type());
71
+ return detail::unwrap<T>(this->value(), Data_Type<T>::ruby_data_type(), false);
69
72
  }
70
73
  }
71
74
 
72
75
  template<typename T>
73
- inline T* Data_Object<T>::from_ruby(VALUE value)
76
+ inline T* Data_Object<T>::from_ruby(VALUE value, bool takeOwnership)
74
77
  {
75
78
  if (Data_Type<T>::is_descendant(value))
76
79
  {
77
- return detail::unwrap<T>(value, Data_Type<T>::ruby_data_type());
80
+ return detail::unwrap<T>(value, Data_Type<T>::ruby_data_type(), takeOwnership);
78
81
  }
79
82
  else
80
83
  {
@@ -102,7 +105,7 @@ namespace Rice::detail
102
105
  VALUE convert(const T& data)
103
106
  {
104
107
  // Get the ruby typeinfo
105
- std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(data);
108
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(data);
106
109
 
107
110
  // We always take ownership of data passed by value (yes the parameter is T& but the template
108
111
  // matched <typename T> thus we have to tell wrap to copy the reference we are sending to it
@@ -236,6 +239,52 @@ namespace Rice::detail
236
239
  Return* returnInfo_ = nullptr;
237
240
  };
238
241
 
242
+ template <typename T>
243
+ class To_Ruby<T**>
244
+ {
245
+ public:
246
+ To_Ruby() = default;
247
+
248
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
249
+ {
250
+ }
251
+
252
+ VALUE convert(T** data)
253
+ {
254
+ if (data)
255
+ {
256
+ // Note that T could be a pointer or reference to a base class while data is in fact a
257
+ // child class. Lookup the correct type so we return an instance of the correct Ruby class
258
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(**data);
259
+ bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
260
+ return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
261
+ }
262
+ else
263
+ {
264
+ return Qnil;
265
+ }
266
+ }
267
+
268
+ VALUE convert(const T** data)
269
+ {
270
+ if (data)
271
+ {
272
+ // Note that T could be a pointer or reference to a base class while data is in fact a
273
+ // child class. Lookup the correct type so we return an instance of the correct Ruby class
274
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType(*data);
275
+ bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
276
+ return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner);
277
+ }
278
+ else
279
+ {
280
+ return Qnil;
281
+ }
282
+ }
283
+
284
+ private:
285
+ Return* returnInfo_ = nullptr;
286
+ };
287
+
239
288
  template<typename T>
240
289
  class To_Ruby<Data_Object<T>>
241
290
  {
@@ -258,23 +307,48 @@ namespace Rice::detail
258
307
  {
259
308
  }
260
309
 
261
- bool is_convertible(VALUE value)
310
+ Convertible is_convertible(VALUE value)
262
311
  {
263
- return rb_type(value) == RUBY_T_DATA &&
264
- Data_Type<T>::is_descendant(value);
312
+ switch (rb_type(value))
313
+ {
314
+ case RUBY_T_DATA:
315
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
316
+ break;
317
+ default:
318
+ return Convertible::None;
319
+ }
265
320
  }
266
321
 
267
322
  T convert(VALUE value)
268
323
  {
269
- using Intrinsic_T = intrinsic_type<T>;
270
-
324
+ // This expression checks to see if T has an explicit copy constructor
325
+ // If it does then we have to call it directly. Not sure if this end ups
326
+ // with an extra copy or not?
327
+ //
328
+ // std::is_constructible_v<T, T> && !std::is_convertible_v<T, T>
271
329
  if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
272
330
  {
273
- return this->arg_->template defaultValue<Intrinsic_T>();
331
+ if constexpr (std::is_constructible_v<T, T> && !std::is_convertible_v<T, T>)
332
+ {
333
+ return T(this->arg_->template defaultValue<T>());
334
+ }
335
+ else
336
+ {
337
+ return this->arg_->template defaultValue<T>();
338
+ }
274
339
  }
275
340
  else
276
341
  {
277
- return *Data_Object<Intrinsic_T>::from_ruby(value);
342
+ if constexpr (std::is_constructible_v<T, T> && !std::is_convertible_v<T, T>)
343
+ {
344
+ using Intrinsic_T = intrinsic_type<T>;
345
+ return T(*Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner()));
346
+ }
347
+ else
348
+ {
349
+ using Intrinsic_T = intrinsic_type<T>;
350
+ return *Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
351
+ }
278
352
  }
279
353
  }
280
354
 
@@ -294,10 +368,16 @@ namespace Rice::detail
294
368
  {
295
369
  }
296
370
 
297
- bool is_convertible(VALUE value)
371
+ Convertible is_convertible(VALUE value)
298
372
  {
299
- return rb_type(value) == RUBY_T_DATA &&
300
- Data_Type<T>::is_descendant(value);
373
+ switch (rb_type(value))
374
+ {
375
+ case RUBY_T_DATA:
376
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
377
+ break;
378
+ default:
379
+ return Convertible::None;
380
+ }
301
381
  }
302
382
 
303
383
  T& convert(VALUE value)
@@ -310,7 +390,7 @@ namespace Rice::detail
310
390
  }
311
391
  else
312
392
  {
313
- return *Data_Object<Intrinsic_T>::from_ruby(value);
393
+ return *Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
314
394
  }
315
395
  }
316
396
 
@@ -319,30 +399,154 @@ namespace Rice::detail
319
399
  };
320
400
 
321
401
  template<typename T>
322
- class From_Ruby<T*>
402
+ class From_Ruby<T&&>
323
403
  {
324
404
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
325
405
  "Data_Object cannot be used with fundamental types");
326
406
  public:
327
- bool is_convertible(VALUE value)
407
+ From_Ruby() = default;
408
+
409
+ explicit From_Ruby(Arg * arg) : arg_(arg)
328
410
  {
329
- return rb_type(value) == RUBY_T_DATA &&
330
- Data_Type<T>::is_descendant(value);
331
411
  }
332
412
 
333
- T* convert(VALUE value)
413
+ Convertible is_convertible(VALUE value)
414
+ {
415
+ switch (rb_type(value))
416
+ {
417
+ case RUBY_T_DATA:
418
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
419
+ break;
420
+ default:
421
+ return Convertible::None;
422
+ }
423
+ }
424
+
425
+ T&& convert(VALUE value)
334
426
  {
335
427
  using Intrinsic_T = intrinsic_type<T>;
336
428
 
337
- if (value == Qnil)
429
+ if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue())
338
430
  {
339
- return nullptr;
431
+ return std::move(this->arg_->template defaultValue<Intrinsic_T>());
340
432
  }
341
433
  else
342
434
  {
343
- return Data_Object<Intrinsic_T>::from_ruby(value);
435
+ return std::move(*Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner()));
436
+ }
437
+ }
438
+
439
+ private:
440
+ Arg* arg_ = nullptr;
441
+ };
442
+
443
+ // Helper class to convert a Ruby array of T to a C++ array of T (this happens when an API take T* as parameter
444
+ // along with a second size parameter)
445
+ template<typename T>
446
+ class ArrayHelper
447
+ {
448
+ public:
449
+ using Intrinsic_T = intrinsic_type<T>;
450
+
451
+ T* convert(VALUE value)
452
+ {
453
+ this->vector_ = Array(value).to_vector<T>();
454
+ return this->vector_.data();
455
+ }
456
+
457
+ private:
458
+ std::vector<Intrinsic_T> vector_;
459
+ };
460
+
461
+ // 99% of the time a T* represents a wrapped C++ object that we want to call methods on. However, T*
462
+ // could also be a pointer to an array of T objects, so T[]. OpenCV for example has API calls like this.
463
+ //
464
+ // Therefore this From_Ruby implementation supports both uses cases which complicates the code. The problem
465
+ // is for T[] to compile, a class needs to be constructible, destructible and not abstract. A further wrinkle
466
+ // is if T has an explicit copy-constructor then that requires additional special handling in the code
467
+ // (see From_Ruby<T>). Whether this extra complication is worth it is debatable, but it does mean that
468
+ // a Ruby array can be passed to any C++ API that takes a * including fundamental types (unsigned char)
469
+ // and class types (T).
470
+ //
471
+ // Note that the From_Ruby<T[]> specialization never matches a parameter defined in function as T[] - the C++
472
+ // compiler always picks T* instead. Not sure why...
473
+ template<typename T>
474
+ class From_Ruby<T*>
475
+ {
476
+ static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
477
+ "Data_Object cannot be used with fundamental types");
478
+ using Intrinsic_T = intrinsic_type<T>;
479
+
480
+ public:
481
+ From_Ruby() = default;
482
+
483
+ explicit From_Ruby(Arg* arg) : arg_(arg)
484
+ {
485
+ }
486
+
487
+ ~From_Ruby()
488
+ {
489
+ if constexpr (std::is_destructible_v<Intrinsic_T>)
490
+ {
491
+ delete this->arrayHelper_;
492
+ }
493
+ }
494
+
495
+ Convertible is_convertible(VALUE value)
496
+ {
497
+ switch (rb_type(value))
498
+ {
499
+ case RUBY_T_DATA:
500
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
501
+ break;
502
+ case RUBY_T_NIL:
503
+ return Convertible::Exact;
504
+ break;
505
+ case RUBY_T_ARRAY:
506
+ return Convertible::Exact;
507
+ break;
508
+ default:
509
+ return Convertible::None;
344
510
  }
345
511
  }
512
+
513
+ T* convert(VALUE value)
514
+ {
515
+ switch (rb_type(value))
516
+ {
517
+ case RUBY_T_DATA:
518
+ {
519
+ return Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
520
+ break;
521
+ }
522
+ case RUBY_T_NIL:
523
+ {
524
+ return nullptr;
525
+ break;
526
+ }
527
+ case RUBY_T_ARRAY:
528
+ {
529
+ if constexpr (std::is_copy_constructible_v<Intrinsic_T> && std::is_destructible_v<Intrinsic_T> && !std::is_abstract_v<Intrinsic_T>)
530
+ {
531
+ if (this->arrayHelper_ == nullptr)
532
+ {
533
+ this->arrayHelper_ = new ArrayHelper<T>();
534
+ }
535
+ return this->arrayHelper_->convert(value);
536
+ break;
537
+ }
538
+ // Will fall through to the type exception if we get here
539
+ }
540
+ default:
541
+ {
542
+ throw create_type_exception<Intrinsic_T>(value);
543
+ }
544
+ }
545
+ }
546
+
547
+ private:
548
+ Arg* arg_ = nullptr;
549
+ ArrayHelper<T>* arrayHelper_ = nullptr;
346
550
  };
347
551
 
348
552
  template<typename T>
@@ -351,10 +555,22 @@ namespace Rice::detail
351
555
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
352
556
  "Data_Object cannot be used with fundamental types");
353
557
  public:
354
- bool is_convertible(VALUE value)
558
+ From_Ruby() = default;
559
+
560
+ explicit From_Ruby(Arg* arg) : arg_(arg)
561
+ {
562
+ }
563
+
564
+ Convertible is_convertible(VALUE value)
355
565
  {
356
- return rb_type(value) == RUBY_T_DATA &&
357
- Data_Type<T>::is_descendant(value);
566
+ switch (rb_type(value))
567
+ {
568
+ case RUBY_T_DATA:
569
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
570
+ break;
571
+ default:
572
+ return Convertible::None;
573
+ }
358
574
  }
359
575
 
360
576
  T* convert(VALUE value)
@@ -367,9 +583,74 @@ namespace Rice::detail
367
583
  }
368
584
  else
369
585
  {
370
- return Data_Object<Intrinsic_T>::from_ruby(value);
586
+ return Data_Object<Intrinsic_T>::from_ruby(value, this->arg_ && this->arg_->isOwner());
587
+ }
588
+ }
589
+
590
+ private:
591
+ Arg* arg_ = nullptr;
592
+ };
593
+
594
+ template<typename T>
595
+ class From_Ruby<T**>
596
+ {
597
+ static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
598
+ "Data_Object cannot be used with fundamental types");
599
+ using Intrinsic_T = intrinsic_type<T>;
600
+ public:
601
+ From_Ruby() = default;
602
+
603
+ explicit From_Ruby(Arg* arg) : arg_(arg)
604
+ {
605
+ }
606
+
607
+ Convertible is_convertible(VALUE value)
608
+ {
609
+ switch (rb_type(value))
610
+ {
611
+ case RUBY_T_DATA:
612
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
613
+ break;
614
+ case RUBY_T_NIL:
615
+ return Convertible::Exact;
616
+ break;
617
+ case RUBY_T_ARRAY:
618
+ return Convertible::Exact;
619
+ break;
620
+ default:
621
+ return Convertible::None;
371
622
  }
372
623
  }
624
+
625
+ T** convert(VALUE value)
626
+ {
627
+ switch (rb_type(value))
628
+ {
629
+ case RUBY_T_DATA:
630
+ {
631
+ return detail::unwrap<Intrinsic_T*>(value, Data_Type<T>::ruby_data_type(), false);
632
+ break;
633
+ }
634
+ case RUBY_T_NIL:
635
+ {
636
+ return nullptr;
637
+ break;
638
+ }
639
+ case RUBY_T_ARRAY:
640
+ {
641
+ this->vector_ = Array(value).to_vector<Intrinsic_T*>();
642
+ return this->vector_.data();
643
+ }
644
+ default:
645
+ {
646
+ throw create_type_exception<Intrinsic_T>(value);
647
+ }
648
+ }
649
+ }
650
+
651
+ private:
652
+ Arg* arg_ = nullptr;
653
+ std::vector<Intrinsic_T*> vector_;
373
654
  };
374
655
 
375
656
  template<typename T>
@@ -378,10 +659,21 @@ namespace Rice::detail
378
659
  static_assert(!std::is_fundamental_v<intrinsic_type<T>>,
379
660
  "Data_Object cannot be used with fundamental types");
380
661
  public:
662
+ Convertible is_convertible(VALUE value)
663
+ {
664
+ switch (rb_type(value))
665
+ {
666
+ case RUBY_T_DATA:
667
+ return Data_Type<T>::is_descendant(value) ? Convertible::Exact : Convertible::None;
668
+ break;
669
+ default:
670
+ return Convertible::None;
671
+ }
672
+ }
673
+
381
674
  static Data_Object<T> convert(VALUE value)
382
675
  {
383
676
  return Data_Object<T>(value);
384
677
  }
385
678
  };
386
679
  }
387
- #endif // Rice__Data_Object__ipp_
data/rice/Data_Type.hpp CHANGED
@@ -1,7 +1,219 @@
1
1
  #ifndef Rice__Data_Type__hpp_
2
2
  #define Rice__Data_Type__hpp_
3
3
 
4
- #include "Data_Type_defn.hpp"
5
- #include "Data_Type.ipp"
4
+ #include <set>
6
5
 
7
- #endif // Rice__Data_Type__hpp_
6
+ namespace Rice
7
+ {
8
+ //! A mechanism for binding ruby types to C++ types.
9
+ /*! This class binds run-time types (Ruby VALUEs) to compile-time types
10
+ * (C++ types). The binding can occur only once.
11
+ */
12
+ template<typename T>
13
+ class Data_Type : public Class
14
+ {
15
+ static_assert(std::is_same_v<detail::intrinsic_type<T>, T>);
16
+
17
+ public:
18
+ using type = T;
19
+
20
+ //! Default constructor which does not bind.
21
+ /*! No member functions must be called on this Data_Type except bind,
22
+ * until the type is bound.
23
+ */
24
+ Data_Type();
25
+
26
+ //! Constructor which takes a Module.
27
+ /*! Binds the type to the given VALUE according to the rules given
28
+ * above.
29
+ * \param klass the module to which to bind.
30
+ */
31
+ Data_Type(Module const & v);
32
+
33
+ //! Return the Ruby class.
34
+ /*! \return the ruby class to which the type is bound.
35
+ */
36
+ static Class klass();
37
+
38
+ //! Return the Ruby data type.
39
+ static rb_data_type_t* ruby_data_type();
40
+
41
+ //! Assignment operator which takes a Module
42
+ /*! \param klass must be the class to which this data type is already
43
+ * bound.
44
+ * \return *this
45
+ */
46
+ virtual Data_Type & operator=(Module const & klass);
47
+
48
+ /*! Creates a singleton method allocate and an instance method called
49
+ * initialize which together create a new instance of the class. The
50
+ * allocate method allocates memory for the object reference and the
51
+ * initialize method constructs the object.
52
+ * \param constructor an object that has a static member function
53
+ * construct() that constructs a new instance of T and sets the object's data
54
+ * member to point to the new instance. A helper class Constructor
55
+ * is provided that does precisely this.
56
+ * \param args a list of Arg instance used to define default parameters (optional)
57
+ *
58
+ * For example:
59
+ * \code
60
+ * define_class<Foo>("Foo")
61
+ * .define_constructor(Constructor<Foo>());
62
+ * \endcode
63
+ */
64
+ template<typename Constructor_T, typename...Rice_Arg_Ts>
65
+ Data_Type<T>& define_constructor(Constructor_T constructor, Rice_Arg_Ts const& ...args);
66
+
67
+ /*! Runs a function that should define this Data_Types methods and attributes.
68
+ * This is useful when creating classes from a C++ class template.
69
+ *
70
+ * \param builder A function that addes methods/attributes to this class
71
+ *
72
+ * For example:
73
+ * \code
74
+ * void builder(Data_Type<Matrix<T, R, C>>& klass)
75
+ * {
76
+ * klass.define_method...
77
+ * return klass;
78
+ * }
79
+ *
80
+ * define_class<<Matrix<T, R, C>>>("Matrix")
81
+ * .build(&builder);
82
+ *
83
+ * \endcode
84
+ */
85
+ template<typename Func_T>
86
+ Data_Type<T>& define(Func_T func);
87
+
88
+ //! Register a Director class for this class.
89
+ /*! For any class that uses Rice::Director to enable polymorphism
90
+ * across the languages, you need to register that director proxy
91
+ * class with this method. Not doing so will cause the resulting
92
+ * library to die at run time when it tries to convert the base
93
+ * type into the Director proxy type.
94
+ *
95
+ * This method takes no methodInfo, just needs the type of the
96
+ * Director proxy class.
97
+ *
98
+ * For example:
99
+ * \code
100
+ * class FooDirector : public Foo, public Rice::Director {
101
+ * ...
102
+ * };
103
+ *
104
+ * define_class<Foo>("Foo")
105
+ * .define_director<FooDirector>()
106
+ * .define_constructor(Constructor<FooDirector, Rice::Object>());
107
+ * \endcode
108
+ */
109
+ template<typename Director_T>
110
+ Data_Type<T>& define_director();
111
+
112
+ //! Determine if the type is bound.
113
+ /*! \return true if the object is bound, false otherwise.
114
+ */
115
+ static bool is_bound();
116
+ static void check_is_bound();
117
+ static bool is_defined(Object parent, const std::string& name);
118
+
119
+ // This is only for testing - DO NOT USE!!!
120
+ static void unbind();
121
+
122
+ static bool is_descendant(VALUE value);
123
+
124
+ //! Define an iterator.
125
+ /*! Essentially this is a conversion from a C++-style begin/end
126
+ * iterator to a Ruby-style \#each iterator.
127
+ * \param begin a member function pointer to a function that returns
128
+ * an iterator to the beginning of the sequence.
129
+ * \param end a member function pointer to a function that returns an
130
+ * iterator to the end of the sequence.
131
+ * \param name the name of the iterator.
132
+ * \return *this
133
+ */
134
+
135
+ template<typename Iterator_Func_T>
136
+ Data_Type<T>& define_iterator(Iterator_Func_T begin, Iterator_Func_T end, std::string name = "each");
137
+
138
+ template <typename Attribute_T>
139
+ Data_Type<T>& define_attr(std::string name, Attribute_T attribute, AttrAccess access = AttrAccess::ReadWrite);
140
+
141
+ template <typename Attribute_T>
142
+ Data_Type<T>& define_singleton_attr(std::string name, Attribute_T attribute, AttrAccess access = AttrAccess::ReadWrite);
143
+
144
+ #include "cpp_api/shared_methods.hpp"
145
+ protected:
146
+ //! Bind a Data_Type to a VALUE.
147
+ /*! Throws an exception if the Data_Type is already bound to a
148
+ * different class. Any existing instances of the Data_Type will be
149
+ * bound after this function returns.
150
+ * \param klass the ruby type to which to bind.
151
+ * \return *this
152
+ */
153
+ template <typename Base_T = void>
154
+ static Data_Type<T> bind(const Module& klass);
155
+
156
+ template<typename T_, typename Base_T>
157
+ friend Rice::Data_Type<T_> define_class_under(Object parent, Identifier id, Class superKlass);
158
+
159
+ template<typename T_, typename Base_T>
160
+ friend Rice::Data_Type<T_> define_class_under(Object parent, char const * name);
161
+
162
+ template<typename T_, typename Base_T>
163
+ friend Rice::Data_Type<T_> define_class(char const * name);
164
+
165
+ template<bool IsMethod, typename Function_T>
166
+ void wrap_native_call(VALUE klass, std::string name, Function_T&& function, MethodInfo* methodInfo);
167
+
168
+ private:
169
+ template<typename T_>
170
+ friend class Data_Type;
171
+
172
+ static inline VALUE klass_ = Qnil;
173
+
174
+ // Typed Data support
175
+ static inline rb_data_type_t* rb_data_type_ = nullptr;
176
+
177
+ // Track unbound instances (ie, declared variables of type Data_Type<T>
178
+ // before define_class is called)
179
+ static inline std::set<Data_Type<T>*>unbound_instances_;
180
+ };
181
+
182
+ //! Define a new data class in the namespace given by module.
183
+ /*! This override allows you to specify a Ruby class as the base class versus a
184
+ * wrapped C++ class. This functionality is rarely needed - but is essential for
185
+ * creating new custom Exception classes where the Ruby superclass should be
186
+ * rb_eStandard
187
+ * \param T the C++ type of the wrapped class.
188
+ * \param module the Module in which to define the class.
189
+ * \param name the name of the new class.
190
+ * \param superKlass the Ruby super class.
191
+ * \return the new class.
192
+ */
193
+ template<typename T, typename Base_T = void>
194
+ Data_Type<T> define_class_under(Object parent, Identifier id, Class superKlass = rb_cObject);
195
+
196
+ //! Define a new data class in the namespace given by module.
197
+ /*! By default the class will inherit from Ruby's rb_cObject. This
198
+ * can be overriden via the Base_T template parameter. Note that
199
+ * Base_T must already have been registered.
200
+ * \param T the C++ type of the wrapped class.
201
+ * \param module the the Module in which to define the class.
202
+ * \return the new class.
203
+ */
204
+ template<typename T, typename Base_T = void>
205
+ Data_Type<T> define_class_under(Object parent, char const* name);
206
+
207
+ //! Define a new data class in the default namespace.
208
+ /*! By default the class will inherit from Ruby's rb_cObject. This
209
+ * can be overriden via the Base_T template parameter. Note that
210
+ * Base_T must already have been registered.
211
+ * \param T the C++ type of the wrapped class.
212
+ * \param module the the Module in which to define the class.
213
+ * \return the new class.
214
+ */
215
+ template<typename T, typename Base_T = void>
216
+ Data_Type<T> define_class(char const* name);
217
+ }
218
+
219
+ #endif // Rice__Data_Type__hpp_