diff options
| author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2025-12-29 18:14:28 +0900 |
|---|---|---|
| committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2025-12-29 18:40:47 +0900 |
| commit | 0f64da9672d88921439f6fdb306d16fece9b9c90 (patch) | |
| tree | b367a0793a11bb2f6e3342389512deba0c30d157 /include | |
| parent | 72627d85e337e5d8c7fa5738dc4ec7f253f0738e (diff) | |
Make `rb_check_typeddata` and `rbimpl_check_typeddata` identical
Diffstat (limited to 'include')
| -rw-r--r-- | include/ruby/internal/core/rtypeddata.h | 96 |
1 files changed, 82 insertions, 14 deletions
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index 0f430f0c6a..8952ba9181 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -450,6 +450,36 @@ RBIMPL_ATTR_NONNULL((2)) * @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_ATTR_NORETURN() +RBIMPL_ATTR_NONNULL((2)) +/** + * @private + * + * Fails with the given object's type incompatibility to the type. + * + * This is an implementation detail of Check_Type. People don't use it + * directly. + * + * @param[in] obj The object in question. + * @param[in] expected Name of expected data type of `obj`. + */ +void rb_unexpected_object_type(VALUE obj, const char *expected); + +RBIMPL_ATTR_NORETURN() +RBIMPL_ATTR_NONNULL(()) +/** + * @private + * + * Fails with the given object's type incompatibility to the type. + * + * This is an implementation detail of #TypedData_Make_Struct. People don't + * use it directly. + * + * @param[in] actual Actual data type. + * @param[in] expected Expected data type. + */ +void rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected); RBIMPL_SYMBOL_EXPORT_END() /** @@ -565,6 +595,27 @@ rbimpl_rtypeddata_p(VALUE obj) return FL_TEST_RAW(obj, RUBY_TYPED_FL_IS_TYPED_DATA); } +RBIMPL_ATTR_PURE() +RBIMPL_ATTR_ARTIFICIAL() +/** + * @private + * + * Identical to rbimpl_rtypeddata_p(), except it is allowed to call on non-data + * objects. + * + * This is an implementation detail of inline functions defined in this file. + * People don't use it directly. + * + * @param[in] obj Object in question + * @retval true `obj` is an instance of ::RTypedData. + * @retval false `obj` is not an instance of ::RTypedData + */ +static inline bool +rbimpl_obj_typeddata_p(VALUE obj) +{ + return RB_TYPE_P(obj, RUBY_T_DATA) && rbimpl_rtypeddata_p(obj); +} + RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() /** @@ -615,6 +666,29 @@ RTYPEDDATA_TYPE(VALUE obj) } RBIMPL_ATTR_ARTIFICIAL() +RBIMPL_ATTR_NONNULL(()) +static inline bool +rb_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent) +{ + do { + if (RB_LIKELY(child == parent)) return true; + } while ((child = child->parent) != NULL); + return false; +} +#define rb_typeddata_inherited_p rb_typeddata_inherited_p_inline + +RBIMPL_ATTR_ARTIFICIAL() +RBIMPL_ATTR_NONNULL((2)) +static inline bool +rb_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type) +{ + if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) return false; + return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type); +} +#define rb_typeddata_is_kind_of rb_typeddata_is_kind_of_inline + +RBIMPL_ATTR_ARTIFICIAL() +RBIMPL_ATTR_NONNULL((2)) /** * @private * @@ -624,22 +698,16 @@ RBIMPL_ATTR_ARTIFICIAL() static inline void * rbimpl_check_typeddata(VALUE obj, const rb_data_type_t *expected_type) { - if (RB_LIKELY(RB_TYPE_P(obj, T_DATA) && RTYPEDDATA_P(obj))) { - const rb_data_type_t *actual_type = RTYPEDDATA_TYPE(obj); - void *data = RTYPEDDATA_GET_DATA(obj); - if (RB_LIKELY(actual_type == expected_type)) { - return data; - } - - while (actual_type) { - actual_type = actual_type->parent; - if (actual_type == expected_type) { - return data; - } - } + if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) { + rb_unexpected_object_type(obj, expected_type->wrap_struct_name); + } + + const rb_data_type_t *actual_type = RTYPEDDATA_TYPE(obj); + if (RB_UNLIKELY(!rb_typeddata_inherited_p(actual_type, expected_type))){ + rb_unexpected_typeddata(actual_type, expected_type); } - return rb_check_typeddata(obj, expected_type); + return RTYPEDDATA_GET_DATA(obj); } |
