mirror of
https://github.com/ruby/ruby.git
synced 2026-01-27 04:24:23 +00:00
Make rb_check_typeddata and rbimpl_check_typeddata identical
This commit is contained in:
parent
72627d85e3
commit
0f64da9672
Notes:
git
2025-12-29 10:47:40 +00:00
53
error.c
53
error.c
@ -1313,6 +1313,20 @@ rb_builtin_class_name(VALUE x)
|
||||
COLDFUNC NORETURN(static void unexpected_type(VALUE, int, int));
|
||||
#define UNDEF_LEAKED "undef leaked to the Ruby space"
|
||||
|
||||
void
|
||||
rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected)
|
||||
{
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
|
||||
actual->wrap_struct_name, expected->wrap_struct_name);
|
||||
}
|
||||
|
||||
void
|
||||
rb_unexpected_object_type(VALUE obj, const char *expected)
|
||||
{
|
||||
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)",
|
||||
displaying_class_of(obj), expected);
|
||||
}
|
||||
|
||||
static void
|
||||
unexpected_type(VALUE x, int xt, int t)
|
||||
{
|
||||
@ -1320,9 +1334,7 @@ unexpected_type(VALUE x, int xt, int t)
|
||||
VALUE mesg, exc = rb_eFatal;
|
||||
|
||||
if (tname) {
|
||||
mesg = rb_sprintf("wrong argument type %"PRIsVALUE" (expected %s)",
|
||||
displaying_class_of(x), tname);
|
||||
exc = rb_eTypeError;
|
||||
rb_unexpected_object_type(x, tname);
|
||||
}
|
||||
else if (xt > T_MASK && xt <= 0x3f) {
|
||||
mesg = rb_sprintf("unknown type 0x%x (0x%x given, probably comes"
|
||||
@ -1367,24 +1379,18 @@ rb_unexpected_type(VALUE x, int t)
|
||||
unexpected_type(x, TYPE(x), t);
|
||||
}
|
||||
|
||||
#undef rb_typeddata_inherited_p
|
||||
int
|
||||
rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent)
|
||||
{
|
||||
while (child) {
|
||||
if (child == parent) return 1;
|
||||
child = child->parent;
|
||||
}
|
||||
return 0;
|
||||
return rb_typeddata_inherited_p_inline(child, parent);
|
||||
}
|
||||
|
||||
#undef rb_typeddata_is_kind_of
|
||||
int
|
||||
rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
|
||||
{
|
||||
if (!RB_TYPE_P(obj, T_DATA) ||
|
||||
!RTYPEDDATA_P(obj) || !rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return rb_typeddata_is_kind_of_inline(obj, data_type);
|
||||
}
|
||||
|
||||
#undef rb_typeddata_is_instance_of
|
||||
@ -1397,26 +1403,7 @@ rb_typeddata_is_instance_of(VALUE obj, const rb_data_type_t *data_type)
|
||||
void *
|
||||
rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
|
||||
{
|
||||
VALUE actual;
|
||||
|
||||
if (!RB_TYPE_P(obj, T_DATA)) {
|
||||
actual = displaying_class_of(obj);
|
||||
}
|
||||
else if (!RTYPEDDATA_P(obj)) {
|
||||
actual = displaying_class_of(obj);
|
||||
}
|
||||
else if (!rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type)) {
|
||||
const char *name = RTYPEDDATA_TYPE(obj)->wrap_struct_name;
|
||||
actual = rb_str_new_cstr(name); /* or rb_fstring_cstr? not sure... */
|
||||
}
|
||||
else {
|
||||
return RTYPEDDATA_GET_DATA(obj);
|
||||
}
|
||||
|
||||
const char *expected = data_type->wrap_struct_name;
|
||||
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected %s)",
|
||||
actual, expected);
|
||||
UNREACHABLE_RETURN(NULL);
|
||||
return rbimpl_check_typeddata(obj, data_type);
|
||||
}
|
||||
|
||||
/* exception classes */
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
return rb_check_typeddata(obj, expected_type);
|
||||
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 RTYPEDDATA_GET_DATA(obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -235,10 +235,11 @@ rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name)
|
||||
rb_exc_raise(exc);
|
||||
}
|
||||
|
||||
RBIMPL_ATTR_NONNULL((2))
|
||||
static inline bool
|
||||
rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type)
|
||||
{
|
||||
return RB_TYPE_P(obj, T_DATA) && RTYPEDDATA_P(obj) && (RTYPEDDATA_TYPE(obj) == data_type);
|
||||
return rbimpl_obj_typeddata_p(obj) && (RTYPEDDATA_TYPE(obj) == data_type);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user