rice 4.3.3 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -26
  3. data/README.md +7 -2
  4. data/Rakefile +7 -1
  5. data/include/rice/rice.hpp +7291 -4430
  6. data/include/rice/stl.hpp +769 -222
  7. data/lib/mkmf-rice.rb +37 -95
  8. data/rice/Address_Registration_Guard.hpp +72 -3
  9. data/rice/Arg.hpp +19 -5
  10. data/rice/Arg.ipp +24 -0
  11. data/rice/Callback.hpp +21 -0
  12. data/rice/Callback.ipp +13 -0
  13. data/rice/Constructor.hpp +4 -27
  14. data/rice/Constructor.ipp +79 -0
  15. data/rice/Data_Object.hpp +74 -3
  16. data/rice/Data_Object.ipp +324 -32
  17. data/rice/Data_Type.hpp +215 -3
  18. data/rice/Data_Type.ipp +125 -64
  19. data/rice/Director.hpp +0 -2
  20. data/rice/Enum.hpp +4 -6
  21. data/rice/Enum.ipp +101 -57
  22. data/rice/Exception.hpp +62 -2
  23. data/rice/Exception.ipp +7 -12
  24. data/rice/JumpException.hpp +44 -0
  25. data/rice/JumpException.ipp +48 -0
  26. data/rice/MemoryView.hpp +11 -0
  27. data/rice/MemoryView.ipp +43 -0
  28. data/rice/Return.hpp +6 -26
  29. data/rice/Return.ipp +10 -16
  30. data/rice/detail/DefaultHandler.hpp +12 -0
  31. data/rice/detail/DefaultHandler.ipp +8 -0
  32. data/rice/detail/HandlerRegistry.hpp +5 -35
  33. data/rice/detail/HandlerRegistry.ipp +7 -11
  34. data/rice/detail/InstanceRegistry.hpp +1 -4
  35. data/rice/detail/MethodInfo.hpp +15 -5
  36. data/rice/detail/MethodInfo.ipp +78 -6
  37. data/rice/detail/Native.hpp +32 -0
  38. data/rice/detail/Native.ipp +129 -0
  39. data/rice/detail/NativeAttributeGet.hpp +51 -0
  40. data/rice/detail/NativeAttributeGet.ipp +51 -0
  41. data/rice/detail/NativeAttributeSet.hpp +43 -0
  42. data/rice/detail/NativeAttributeSet.ipp +82 -0
  43. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  44. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  45. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  46. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  47. data/rice/detail/NativeFunction.hpp +20 -21
  48. data/rice/detail/NativeFunction.ipp +199 -64
  49. data/rice/detail/NativeIterator.hpp +8 -11
  50. data/rice/detail/NativeIterator.ipp +27 -31
  51. data/rice/detail/NativeRegistry.hpp +24 -15
  52. data/rice/detail/NativeRegistry.ipp +23 -48
  53. data/rice/detail/Proc.hpp +4 -0
  54. data/rice/detail/Proc.ipp +85 -0
  55. data/rice/detail/Registries.hpp +0 -7
  56. data/rice/detail/Registries.ipp +0 -18
  57. data/rice/detail/RubyFunction.hpp +0 -3
  58. data/rice/detail/RubyFunction.ipp +4 -8
  59. data/rice/detail/RubyType.hpp +19 -0
  60. data/rice/detail/RubyType.ipp +187 -0
  61. data/rice/detail/TupleIterator.hpp +14 -0
  62. data/rice/detail/Type.hpp +5 -6
  63. data/rice/detail/Type.ipp +150 -33
  64. data/rice/detail/TypeRegistry.hpp +15 -7
  65. data/rice/detail/TypeRegistry.ipp +105 -12
  66. data/rice/detail/Wrapper.hpp +6 -5
  67. data/rice/detail/Wrapper.ipp +45 -23
  68. data/rice/detail/cpp_protect.hpp +5 -6
  69. data/rice/detail/default_allocation_func.ipp +0 -2
  70. data/rice/detail/from_ruby.hpp +37 -3
  71. data/rice/detail/from_ruby.ipp +911 -454
  72. data/rice/detail/ruby.hpp +18 -0
  73. data/rice/detail/to_ruby.hpp +41 -3
  74. data/rice/detail/to_ruby.ipp +437 -113
  75. data/rice/global_function.hpp +0 -4
  76. data/rice/global_function.ipp +1 -2
  77. data/rice/rice.hpp +105 -22
  78. data/rice/ruby_mark.hpp +4 -3
  79. data/rice/stl.hpp +4 -0
  80. data/test/embed_ruby.cpp +4 -1
  81. data/test/extconf.rb +2 -0
  82. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  83. data/test/test_Address_Registration_Guard.cpp +5 -0
  84. data/test/test_Array.cpp +12 -1
  85. data/test/test_Attribute.cpp +103 -21
  86. data/test/test_Builtin_Object.cpp +5 -0
  87. data/test/test_Callback.cpp +231 -0
  88. data/test/test_Class.cpp +5 -31
  89. data/test/test_Constructor.cpp +69 -6
  90. data/test/test_Data_Object.cpp +9 -4
  91. data/test/test_Data_Type.cpp +428 -64
  92. data/test/test_Director.cpp +10 -5
  93. data/test/test_Enum.cpp +152 -40
  94. data/test/test_Exception.cpp +235 -0
  95. data/test/test_File.cpp +70 -0
  96. data/test/test_From_Ruby.cpp +542 -0
  97. data/test/test_Hash.cpp +5 -0
  98. data/test/test_Identifier.cpp +5 -0
  99. data/test/test_Inheritance.cpp +6 -1
  100. data/test/test_Iterator.cpp +5 -0
  101. data/test/test_JumpException.cpp +22 -0
  102. data/test/test_Keep_Alive.cpp +6 -1
  103. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
  104. data/test/test_Memory_Management.cpp +5 -0
  105. data/test/test_Module.cpp +118 -64
  106. data/test/test_Native_Registry.cpp +2 -33
  107. data/test/test_Object.cpp +5 -0
  108. data/test/test_Overloads.cpp +631 -0
  109. data/test/test_Ownership.cpp +67 -4
  110. data/test/test_Proc.cpp +45 -0
  111. data/test/test_Self.cpp +5 -0
  112. data/test/test_Stl_Exception.cpp +109 -0
  113. data/test/test_Stl_Map.cpp +22 -8
  114. data/test/test_Stl_Optional.cpp +5 -0
  115. data/test/test_Stl_Pair.cpp +7 -2
  116. data/test/test_Stl_Reference_Wrapper.cpp +5 -0
  117. data/test/test_Stl_SmartPointer.cpp +210 -5
  118. data/test/test_Stl_String.cpp +5 -0
  119. data/test/test_Stl_String_View.cpp +5 -0
  120. data/test/test_Stl_Type.cpp +147 -0
  121. data/test/test_Stl_Unordered_Map.cpp +18 -7
  122. data/test/test_Stl_Variant.cpp +5 -0
  123. data/test/test_Stl_Vector.cpp +130 -8
  124. data/test/test_String.cpp +5 -0
  125. data/test/test_Struct.cpp +5 -0
  126. data/test/test_Symbol.cpp +5 -0
  127. data/test/test_Template.cpp +192 -0
  128. data/test/test_To_Ruby.cpp +152 -0
  129. data/test/test_Tracking.cpp +1 -0
  130. data/test/test_Type.cpp +100 -0
  131. data/test/test_global_functions.cpp +53 -6
  132. data/test/unittest.cpp +8 -0
  133. metadata +37 -20
  134. data/lib/version.rb +0 -3
  135. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  136. data/rice/Data_Object_defn.hpp +0 -84
  137. data/rice/Data_Type_defn.hpp +0 -190
  138. data/rice/Exception_defn.hpp +0 -68
  139. data/rice/HandlerRegistration.hpp +0 -15
  140. data/rice/Identifier.hpp +0 -50
  141. data/rice/Identifier.ipp +0 -29
  142. data/rice/detail/ExceptionHandler.hpp +0 -8
  143. data/rice/detail/ExceptionHandler.ipp +0 -28
  144. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  145. data/rice/detail/Jump_Tag.hpp +0 -21
  146. data/rice/detail/NativeAttribute.hpp +0 -64
  147. data/rice/detail/NativeAttribute.ipp +0 -112
  148. data/rice/detail/from_ruby_defn.hpp +0 -38
  149. data/rice/detail/to_ruby_defn.hpp +0 -48
  150. data/test/test_Jump_Tag.cpp +0 -17
  151. data/test/test_To_From_Ruby.cpp +0 -399
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_