#ifndef RBIMPL_RTYPEDDATA_H /*-*-C++-*-vi:se ft=cpp:*/ #define RBIMPL_RTYPEDDATA_H /** * @file * @author Ruby developers * @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 #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 */