-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrtypeddata.h
643 lines (586 loc) · 22.8 KB
/
rtypeddata.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
#ifndef RBIMPL_RTYPEDDATA_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_RTYPEDDATA_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines struct ::RTypedData.
*/
#include "ruby/internal/config.h"
#ifdef STDC_HEADERS
# include <stddef.h>
#endif
#include "ruby/internal/assume.h"
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/flag_enum.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/core/rbasic.h"
#include "ruby/internal/core/rdata.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/error.h"
#include "ruby/internal/fl_type.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value_type.h"
/**
* @private
*
* @deprecated This macro once was a thing in the old days, but makes no sense
* any longer today. Exists here for backwards compatibility
* only. You can safely forget about it.
*/
#define HAVE_TYPE_RB_DATA_TYPE_T 1
/**
* @private
*
* @deprecated This macro once was a thing in the old days, but makes no sense
* any longer today. Exists here for backwards compatibility
* only. You can safely forget about it.
*/
#define HAVE_RB_DATA_TYPE_T_FUNCTION 1
/**
* @private
*
* @deprecated This macro once was a thing in the old days, but makes no sense
* any longer today. Exists here for backwards compatibility
* only. You can safely forget about it.
*/
#define HAVE_RB_DATA_TYPE_T_PARENT 1
/**
* This is a value you can set to ::rb_data_type_struct::dfree. Setting this
* means the data was allocated using ::ruby_xmalloc() (or variants), and shall
* be freed using ::ruby_xfree().
*
* @warning Do not use this if you want to use system malloc, because the
* system and Ruby might or might not share the same malloc
* implementation.
*/
#define RUBY_TYPED_DEFAULT_FREE RUBY_DEFAULT_FREE
/**
* This is a value you can set to ::rb_data_type_struct::dfree. Setting this
* means the data is managed by someone else, like, statically allocated. Of
* course you are on your own then.
*/
#define RUBY_TYPED_NEVER_FREE RUBY_NEVER_FREE
/**
* Convenient casting macro.
*
* @param obj An object, which is in fact an ::RTypedData.
* @return The passed object casted to ::RTypedData.
*/
#define RTYPEDDATA(obj) RBIMPL_CAST((struct RTypedData *)(obj))
/**
* Convenient getter macro.
*
* @param v An object, which is in fact an ::RTypedData.
* @return The passed object's ::RTypedData::data field.
*/
#define RTYPEDDATA_DATA(v) (RTYPEDDATA(v)->data)
/** @old{rb_check_typeddata} */
#define Check_TypedStruct(v, t) \
rb_check_typeddata(RBIMPL_CAST((VALUE)(v)), (t))
/** @cond INTERNAL_MACRO */
#define RTYPEDDATA_P RTYPEDDATA_P
#define RTYPEDDATA_TYPE RTYPEDDATA_TYPE
#define RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
#define RUBY_TYPED_WB_PROTECTED RUBY_TYPED_WB_PROTECTED
#define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1
/** @endcond */
#define TYPED_DATA_EMBEDDED 2
/**
* @private
*
* Bits for rb_data_type_struct::flags.
*/
enum
RBIMPL_ATTR_FLAG_ENUM()
rbimpl_typeddata_flags {
/**
* This flag has something to do with Ruby's global interpreter lock. For
* maximum safety, Ruby locks the entire VM during GC. However your
* callback functions could unintentionally unlock it, for instance when
* they try to flush an IO buffer. Such operations are dangerous (threads
* then run alongside of GC). By default, to prevent those scenario,
* callbacks are deferred until the GC engine is 100% sure threads can run.
* This flag skips that; structs with it are deallocated during the sweep
* phase.
*
* Using this flag needs deep understanding of both GC and threads. You
* would better leave it unspecified.
*/
RUBY_TYPED_FREE_IMMEDIATELY = 1,
RUBY_TYPED_EMBEDDABLE = 2,
/**
* This flag has something to do with Ractor. Multiple Ractors run without
* protecting each other. Sharing an object among Ractors is basically
* dangerous, disabled by default. This flag is used to bypass that
* restriction. but setting it is not enough. In addition to do so, an
* object also has to be frozen, and be passed to
* rb_ractor_make_shareable() before being actually shareable. Of course,
* you have to manually prevent race conditions then.
*
* Using this flag needs deep understanding of multithreaded programming.
* You would better leave it unspecified.
*/
RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE,
/**
* This flag has something to do with our garbage collector. These days
* ruby objects are "generational". There are those who are young and
* those who are old. Young objects are prone to die; monitored relatively
* extensively by the garbage collector. OTOH old objects tend to live
* longer. They are relatively rarely considered. This basically works.
* But there is one tweak that has to be exercised. When an elder object
* has reference(s) to younger one(s), that referenced objects must not
* die. In order to detect additions of such references, old generations
* are protected by write barriers. It is a very difficult hack to
* appropriately insert write barriers everywhere. This mechanism is
* disabled by default for 3rd party extensions (they never get aged). By
* specifying this flag you can enable the generational feature to your
* data structure. Of course, you have to manually insert write barriers
* then.
*
* Using this flag needs deep understanding of GC internals, often at the
* level of source code. You would better leave it unspecified.
*/
RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
/**
* This flag no longer in use
*/
RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6,
/**
* This flag determines whether marking and compaction should be carried out
* using the dmark/dcompact callback functions or whether we should mark
* declaratively using a list of references defined inside the data struct we're wrapping
*/
RUBY_TYPED_DECL_MARKING = RUBY_FL_USER2
};
/**
* This is the struct that holds necessary info for a struct. It roughly
* resembles a Ruby level class; multiple objects can share a ::rb_data_type_t
* instance.
*/
typedef struct rb_data_type_struct rb_data_type_t;
/** @copydoc rb_data_type_t */
struct rb_data_type_struct {
/**
* Name of structs of this kind. This is used for diagnostic purposes.
* This has to be unique in the process, but doesn't has to be a valid
* C/Ruby identifier.
*/
const char *wrap_struct_name;
/** Function pointers. Resembles C++ `vtbl`.*/
struct {
/**
* This function is called when the object is experiencing GC marks.
* If it contains references to other Ruby objects, you need to mark
* them also. Otherwise GC will smash your data.
*
* @see rb_gc_mark()
* @warning This is called during GC runs. Object allocations are
* impossible at that moment (that is why GC runs).
*/
RUBY_DATA_FUNC dmark;
/**
* This function is called when the object is no longer used. You need
* to do whatever necessary to avoid memory leaks.
*
* @warning This is called during GC runs. Object allocations are
* impossible at that moment (that is why GC runs).
*/
RUBY_DATA_FUNC dfree;
/**
* This function is to query the size of the underlying memory regions.
*
* @internal
*
* This function has only one usage, which is form inside of
* `ext/objspace`.
*/
size_t (*dsize)(const void *);
/**
* This function is called when the object is relocated. Like
* ::rb_data_type_struct::dmark, you need to update references to Ruby
* objects inside of your structs.
*
* @see rb_gc_location()
* @warning This is called during GC runs. Object allocations are
* impossible at that moment (that is why GC runs).
*/
RUBY_DATA_FUNC dcompact;
/**
* This field is reserved for future extension. For now, it must be
* filled with zeros.
*/
void *reserved[1]; /* For future extension.
This array *must* be filled with ZERO. */
} function;
/**
* Parent of this class. Sometimes C structs have inheritance-like
* relationships. An example is `struct sockaddr` and its family. If you
* design such things, make ::rb_data_type_t for each of them and connect
* using this field. Ruby can then transparently cast your data back and
* forth when you call #TypedData_Get_Struct().
*
* ```CXX
* struct parent { };
* static inline const rb_data_type_t parent_type = {
* .wrap_struct_name = "parent",
* };
*
* struct child: public parent { };
* static inline const rb_data_type_t child_type = {
* .wrap_struct_name = "child",
* .parent = &parent_type,
* };
*
* // This function can take both parent_class and child_class.
* static inline struct parent *
* get_parent(VALUE v)
* {
* struct parent *p;
* TypedData_Get_Struct(v, parent_type, struct parent, p);
* return p;
* }
* ```
*/
const rb_data_type_t *parent;
/**
* Type-specific static data. This area can be used for any purpose by a
* programmer who define the type. Ruby does not manage this at all.
*/
void *data; /* This area can be used for any purpose
by a programmer who define the type. */
/**
* Type-specific behavioural characteristics. This is a bitfield. It is
* an EXTREMELY WISE IDEA to leave this field blank. It is designed so
* that setting zero is the safest thing to do. If you risk to set any
* bits on, you have to know exactly what you are doing.
*
* @internal
*
* Why it has to be a ::VALUE? @shyouhei doesn't understand the design.
*/
VALUE flags; /* RUBY_FL_WB_PROTECTED */
};
/**
* "Typed" user data. By using this, extension libraries can wrap a C struct
* to make it visible from Ruby. For instance if you have a `struct timeval`,
* and you want users to use it,
*
* ```CXX
* static inline const rb_data_type_t timeval_type = {
* // Note that unspecified fields are 0-filled by default.
* .wrap_struct_name = "timeval",
* .function = {
* .dmark = nullptr, // no need to mark
* .dfree = RUBY_TYPED_DEFAULT_FREE, // use ruby_xfree()
* .dsize = [](auto) {
* return sizeof(struct timeval);
* },
* },
* };
*
* extern "C" void
* Init_timeval(void)
* {
* auto klass = rb_define_class("YourName", rb_cObject);
*
* rb_define_alloc_func(klass, [](auto klass) {
* struct timeval *t;
* auto ret = TypedData_Make_Struct(
* klass, struct timeval, &timeval_type, t);
*
* if (auto i = gettimeofday(t, nullptr); i == -1) {
* rb_sys_fail("gettimeofday(3)");
* }
* else {
* return ret;
* }
* });
* }
* ```
*/
struct RTypedData {
/** The part that all ruby objects have in common. */
struct RBasic basic;
/**
* This field stores various information about how Ruby should handle a
* data. This roughly resembles a Ruby level class (apart from method
* definition etc.)
*/
const rb_data_type_t *const type;
/**
* This has to be always 1.
*
* @internal
*/
const VALUE typed_flag;
/** Pointer to the actual C level struct that you want to wrap. */
void *data;
};
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NONNULL((3))
/**
* This is the primitive way to wrap an existing C struct into ::RTypedData.
*
* @param[in] klass Ruby level class of the returning object.
* @param[in] datap Pointer to the target C struct.
* @param[in] type The characteristics of the passed data.
* @exception rb_eTypeError `klass` is not a class.
* @exception rb_eNoMemError Out of memory.
* @return An allocated object that wraps `datap`.
*/
VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type);
/**
* Identical to rb_data_typed_object_wrap(), except it allocates a new data
* region internally instead of taking an existing one. The allocation is done
* using ruby_calloc(). Hence it makes no sense for `type->function.dfree` to
* be anything other than ::RUBY_TYPED_DEFAULT_FREE.
*
* @param[in] klass Ruby level class of the returning object.
* @param[in] size Requested size of memory to allocate.
* @param[in] type The characteristics of the passed data.
* @exception rb_eTypeError `klass` is not a class.
* @exception rb_eNoMemError Out of memory.
* @return An allocated object that wraps a new `size` byte region.
*/
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type);
/**
* Checks for the domestic relationship between the two.
*
* @param[in] child A data type supposed to be a child of `parent`.
* @param[in] parent A data type supposed to be a parent of `child`.
* @retval true `child` is a descendent of `parent`.
* @retval false Otherwise.
*
* @internal
*
* You can path NULL to both arguments, don't know what that means though.
*/
int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent);
/**
* Checks if the given object is of given kind.
*
* @param[in] obj An instance of ::RTypedData.
* @param[in] data_type Expected data type of `obj`.
* @retval true `obj` is of `data_type`.
* @retval false Otherwise.
*/
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
/**
* Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead
* of returning false.
*
* @param[in] obj An instance of ::RTypedData.
* @param[in] data_type Expected data type of `obj`.
* @exception rb_eTypeError obj is not of `data_type`.
* @return Unwrapped C struct that `obj` holds.
* @post Upon successful return `obj`'s type is guaranteed `data_type`.
*/
void *rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type);
RBIMPL_SYMBOL_EXPORT_END()
/**
* Converts sval, a pointer to your struct, into a Ruby object.
*
* @param klass A ruby level class.
* @param data_type The type of `sval`.
* @param sval A pointer to your struct.
* @exception rb_eTypeError `klass` is not a class.
* @exception rb_eNoMemError Out of memory.
* @return A created Ruby object.
*/
#define TypedData_Wrap_Struct(klass,data_type,sval)\
rb_data_typed_object_wrap((klass),(sval),(data_type))
/**
* @private
*
* This is an implementation detail of #TypedData_Make_Struct. People don't
* use it directly.
*
* @param result Variable name of created Ruby object.
* @param klass Ruby level class of the object.
* @param type Type name of the C struct.
* @param size Size of the C struct.
* @param data_type The data type describing `type`.
* @param sval Variable name of created C struct.
*/
#define TypedData_Make_Struct0(result, klass, type, size, data_type, sval) \
VALUE result = rb_data_typed_object_zalloc(klass, size, data_type); \
(sval) = (type *)RTYPEDDATA_GET_DATA(result); \
RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
/**
* Identical to #TypedData_Wrap_Struct, except it allocates a new data region
* internally instead of taking an existing one. The allocation is done using
* ruby_calloc(). Hence it makes no sense for `data_type->function.dfree` to
* be anything other than ::RUBY_TYPED_DEFAULT_FREE.
*
* @param klass Ruby level class of the object.
* @param type Type name of the C struct.
* @param data_type The data type describing `type`.
* @param sval Variable name of created C struct.
* @exception rb_eTypeError `klass` is not a class.
* @exception rb_eNoMemError Out of memory.
* @return A created Ruby object.
*/
#ifdef HAVE_STMT_AND_DECL_IN_EXPR
#define TypedData_Make_Struct(klass, type, data_type, sval) \
RB_GNUC_EXTENSION({ \
TypedData_Make_Struct0( \
data_struct_obj, \
klass, \
type, \
sizeof(type), \
data_type, \
sval); \
data_struct_obj; \
})
#else
#define TypedData_Make_Struct(klass, type, data_type, sval) \
rb_data_typed_object_make( \
(klass), \
(data_type), \
RBIMPL_CAST((void **)&(sval)), \
sizeof(type))
#endif
/**
* Obtains a C struct from inside of a wrapper Ruby object.
*
* @param obj An instance of ::RTypedData.
* @param type Type name of the C struct.
* @param data_type The data type describing `type`.
* @param sval Variable name of obtained C struct.
* @exception rb_eTypeError `obj` is not a kind of `data_type`.
* @return Unwrapped C struct that `obj` holds.
*/
#define TypedData_Get_Struct(obj,type,data_type,sval) \
((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type))))
static inline bool
RTYPEDDATA_EMBEDDED_P(VALUE obj)
{
#if RUBY_DEBUG
if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) {
Check_Type(obj, RUBY_T_DATA);
RBIMPL_UNREACHABLE_RETURN(false);
}
#endif
return RTYPEDDATA(obj)->typed_flag & TYPED_DATA_EMBEDDED;
}
static inline void *
RTYPEDDATA_GET_DATA(VALUE obj)
{
#if RUBY_DEBUG
if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) {
Check_Type(obj, RUBY_T_DATA);
RBIMPL_UNREACHABLE_RETURN(false);
}
#endif
/* We reuse the data pointer in embedded TypedData. We can't use offsetof
* since RTypedData a non-POD type in C++. */
const size_t embedded_typed_data_size = sizeof(struct RTypedData) - sizeof(void *);
return RTYPEDDATA_EMBEDDED_P(obj) ? (char *)obj + embedded_typed_data_size : RTYPEDDATA(obj)->data;
}
RBIMPL_ATTR_PURE()
RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
* This is an implementation detail of Check_Type(). People don't use it
* directly.
*
* @param[in] obj Object in question
* @retval true `obj` is an instance of ::RTypedData.
* @retval false `obj` is an instance of ::RData.
* @pre `obj` must be a Ruby object of ::RUBY_T_DATA.
*/
static inline bool
rbimpl_rtypeddata_p(VALUE obj)
{
VALUE typed_flag = RTYPEDDATA(obj)->typed_flag;
return typed_flag != 0 && typed_flag <= 3;
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
* Checks whether the passed object is ::RTypedData or ::RData.
*
* @param[in] obj Object in question
* @retval true `obj` is an instance of ::RTypedData.
* @retval false `obj` is an instance of ::RData.
* @pre `obj` must be a Ruby object of ::RUBY_T_DATA.
*/
static inline bool
RTYPEDDATA_P(VALUE obj)
{
#if RUBY_DEBUG
if (RB_UNLIKELY(! RB_TYPE_P(obj, RUBY_T_DATA))) {
Check_Type(obj, RUBY_T_DATA);
RBIMPL_UNREACHABLE_RETURN(false);
}
#endif
return rbimpl_rtypeddata_p(obj);
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */
/**
* Queries for the type of given object.
*
* @param[in] obj Object in question
* @return Data type struct that corresponds to `obj`.
* @pre `obj` must be an instance of ::RTypedData.
*/
static inline const struct rb_data_type_struct *
RTYPEDDATA_TYPE(VALUE obj)
{
#if RUBY_DEBUG
if (RB_UNLIKELY(! RTYPEDDATA_P(obj))) {
rb_unexpected_type(obj, RUBY_T_DATA);
RBIMPL_UNREACHABLE_RETURN(NULL);
}
#endif
return RTYPEDDATA(obj)->type;
}
/**
* While we don't stop you from using this function, it seems to be an
* implementation detail of #TypedData_Make_Struct, which is preferred over
* this one.
*
* @param[in] klass Ruby level class of the returning object.
* @param[in] type The data type
* @param[out] datap Return pointer.
* @param[in] size Size of the C struct.
* @exception rb_eTypeError `klass` is not a class.
* @exception rb_eNoMemError Out of memory.
* @return A created Ruby object.
* @post `*datap` points to the C struct wrapped by the returned object.
*/
static inline VALUE
rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap, size_t size)
{
TypedData_Make_Struct0(result, klass, void, size, type, *datap);
return result;
}
RBIMPL_ATTR_DEPRECATED(("by: rb_data_typed_object_wrap"))
/** @deprecated This function was renamed to rb_data_typed_object_wrap(). */
static inline VALUE
rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
{
return rb_data_typed_object_wrap(klass, datap, type);
}
#endif /* RBIMPL_RTYPEDDATA_H */