summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2025-12-29 18:14:28 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2025-12-29 18:40:47 +0900
commit0f64da9672d88921439f6fdb306d16fece9b9c90 (patch)
treeb367a0793a11bb2f6e3342389512deba0c30d157 /include
parent72627d85e337e5d8c7fa5738dc4ec7f253f0738e (diff)
Make `rb_check_typeddata` and `rbimpl_check_typeddata` identical
Diffstat (limited to 'include')
-rw-r--r--include/ruby/internal/core/rtypeddata.h96
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);
}