You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-01 16:38:31 +00:00
Add RequiredParam<T> and RequiredValue<T> to mark Object * arguments and return values as required
Co-authored-by: Thaddeus Crews <repiteo@outlook.com>
This commit is contained in:
@@ -88,7 +88,7 @@ static String get_property_info_type_name(const PropertyInfo &p_info) {
|
||||
}
|
||||
|
||||
static String get_type_meta_name(const GodotTypeInfo::Metadata metadata) {
|
||||
static const char *argmeta[13] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double", "char16", "char32" };
|
||||
static const char *argmeta[14] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double", "char16", "char32", "required" };
|
||||
return argmeta[metadata];
|
||||
}
|
||||
|
||||
|
||||
@@ -1942,6 +1942,10 @@
|
||||
{
|
||||
"name": "GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32",
|
||||
"value": 12
|
||||
},
|
||||
{
|
||||
"name": "GDEXTENSION_METHOD_ARGUMENT_METADATA_OBJECT_IS_REQUIRED",
|
||||
"value": 13
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "core/templates/hash_set.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/variant/required_ptr.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "core/templates/simple_type.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/method_ptrcall.h"
|
||||
#include "core/variant/required_ptr.h"
|
||||
#include "core/variant/type_info.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "core/variant/variant_internal.h"
|
||||
|
||||
@@ -269,6 +269,42 @@ struct PtrToArg<const T *> {
|
||||
}
|
||||
};
|
||||
|
||||
// This is for RequiredParam.
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<RequiredParam<T>> {
|
||||
typedef typename RequiredParam<T>::ptr_type EncodeT;
|
||||
|
||||
_FORCE_INLINE_ static RequiredParam<T> convert(const void *p_ptr) {
|
||||
if (p_ptr == nullptr) {
|
||||
return RequiredParam<T>::_err_return_dont_use();
|
||||
}
|
||||
return RequiredParam<T>(*reinterpret_cast<T *const *>(p_ptr));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static void encode(const RequiredParam<T> &p_var, void *p_ptr) {
|
||||
*((typename RequiredParam<T>::ptr_type *)p_ptr) = p_var._internal_ptr_dont_use();
|
||||
}
|
||||
};
|
||||
|
||||
// This is for RequiredResult.
|
||||
|
||||
template <class T>
|
||||
struct PtrToArg<RequiredResult<T>> {
|
||||
typedef typename RequiredResult<T>::ptr_type EncodeT;
|
||||
|
||||
_FORCE_INLINE_ static RequiredResult<T> convert(const void *p_ptr) {
|
||||
if (p_ptr == nullptr) {
|
||||
return RequiredResult<T>::_err_return_dont_use();
|
||||
}
|
||||
return RequiredResult<T>(*reinterpret_cast<T *const *>(p_ptr));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static void encode(const RequiredResult<T> &p_var, void *p_ptr) {
|
||||
*((typename RequiredResult<T>::ptr_type *)p_ptr) = p_var._internal_ptr_dont_use();
|
||||
}
|
||||
};
|
||||
|
||||
// This is for ObjectID.
|
||||
|
||||
template <>
|
||||
|
||||
246
core/variant/required_ptr.h
Normal file
246
core/variant/required_ptr.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/**************************************************************************/
|
||||
/* required_ptr.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
template <typename T>
|
||||
class RequiredResult {
|
||||
static_assert(!is_fully_defined_v<T> || std::is_base_of_v<Object, T>, "T must be an Object subtype");
|
||||
|
||||
public:
|
||||
using element_type = T;
|
||||
using ptr_type = std::conditional_t<std::is_base_of_v<RefCounted, T>, Ref<T>, T *>;
|
||||
|
||||
private:
|
||||
ptr_type _value = ptr_type();
|
||||
|
||||
_FORCE_INLINE_ RequiredResult() = default;
|
||||
|
||||
public:
|
||||
RequiredResult(const RequiredResult &p_other) = default;
|
||||
RequiredResult(RequiredResult &&p_other) = default;
|
||||
RequiredResult &operator=(const RequiredResult &p_other) = default;
|
||||
RequiredResult &operator=(RequiredResult &&p_other) = default;
|
||||
|
||||
_FORCE_INLINE_ RequiredResult(std::nullptr_t) :
|
||||
RequiredResult() {}
|
||||
_FORCE_INLINE_ RequiredResult &operator=(std::nullptr_t) { _value = nullptr; }
|
||||
|
||||
// These functions should not be called directly, they are only for internal use.
|
||||
_FORCE_INLINE_ ptr_type _internal_ptr_dont_use() const { return _value; }
|
||||
_FORCE_INLINE_ static RequiredResult<T> _err_return_dont_use() { return RequiredResult<T>(); }
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult(const RequiredResult<T_Other> &p_other) :
|
||||
_value(p_other._value) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult &operator=(const RequiredResult<T_Other> &p_other) {
|
||||
_value = p_other._value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult(T_Other *p_ptr) :
|
||||
_value(p_ptr) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult &operator=(T_Other *p_ptr) {
|
||||
_value = p_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult(const Ref<T_Other> &p_ref) :
|
||||
_value(p_ref) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult &operator=(const Ref<T_Other> &p_ref) {
|
||||
_value = p_ref;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult(Ref<T_Other> &&p_ref) :
|
||||
_value(std::move(p_ref)) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult &operator=(Ref<T_Other> &&p_ref) {
|
||||
_value = std::move(p_ref);
|
||||
return &this;
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult(const Variant &p_variant) :
|
||||
_value(static_cast<T *>(p_variant.get_validated_object())) {}
|
||||
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) {
|
||||
_value = static_cast<T *>(p_variant.get_validated_object());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult(const Variant &p_variant) :
|
||||
_value(static_cast<T *>(p_variant.operator Object *())) {}
|
||||
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) {
|
||||
_value = static_cast<T *>(p_variant.operator Object *());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ element_type *ptr() const {
|
||||
return *_value;
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ element_type *ptr() const {
|
||||
return _value;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ operator ptr_type() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ operator Variant() const {
|
||||
return Variant(_value);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ element_type *operator*() const {
|
||||
return ptr();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ element_type *operator->() const {
|
||||
return ptr();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RequiredParam {
|
||||
static_assert(!is_fully_defined_v<T> || std::is_base_of_v<Object, T>, "T must be an Object subtype");
|
||||
|
||||
public:
|
||||
using element_type = T;
|
||||
using ptr_type = std::conditional_t<std::is_base_of_v<RefCounted, T>, Ref<T>, T *>;
|
||||
|
||||
private:
|
||||
ptr_type _value = ptr_type();
|
||||
|
||||
_FORCE_INLINE_ RequiredParam() = default;
|
||||
|
||||
public:
|
||||
// These functions should not be called directly, they are only for internal use.
|
||||
_FORCE_INLINE_ ptr_type _internal_ptr_dont_use() const { return _value; }
|
||||
_FORCE_INLINE_ bool _is_null_dont_use() const {
|
||||
if constexpr (std::is_base_of_v<RefCounted, T>) {
|
||||
return _value.is_null();
|
||||
} else {
|
||||
return _value == nullptr;
|
||||
}
|
||||
}
|
||||
_FORCE_INLINE_ static RequiredParam<T> _err_return_dont_use() { return RequiredParam<T>(); }
|
||||
|
||||
// Prevent erroneously assigning null values by explicitly removing nullptr constructor/assignment.
|
||||
RequiredParam(std::nullptr_t) = delete;
|
||||
RequiredParam &operator=(std::nullptr_t) = delete;
|
||||
|
||||
RequiredParam(const RequiredParam &p_other) = default;
|
||||
RequiredParam(RequiredParam &&p_other) = default;
|
||||
RequiredParam &operator=(const RequiredParam &p_other) = default;
|
||||
RequiredParam &operator=(RequiredParam &&p_other) = default;
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam(const RequiredParam<T_Other> &p_other) :
|
||||
_value(p_other._internal_ptr_dont_use()) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam &operator=(const RequiredParam<T_Other> &p_other) {
|
||||
_value = p_other._internal_ptr_dont_use();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam(T_Other *p_ptr) :
|
||||
_value(p_ptr) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam &operator=(T_Other *p_ptr) {
|
||||
_value = p_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam(const Ref<T_Other> &p_ref) :
|
||||
_value(p_ref) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam &operator=(const Ref<T_Other> &p_ref) {
|
||||
_value = p_ref;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam(Ref<T_Other> &&p_ref) :
|
||||
_value(std::move(p_ref)) {}
|
||||
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam &operator=(Ref<T_Other> &&p_ref) {
|
||||
_value = std::move(p_ref);
|
||||
return &this;
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam(const Variant &p_variant) :
|
||||
_value(static_cast<T *>(p_variant.get_validated_object())) {}
|
||||
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) {
|
||||
_value = static_cast<T *>(p_variant.get_validated_object());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam(const Variant &p_variant) :
|
||||
_value(static_cast<T *>(p_variant.operator Object *())) {}
|
||||
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
_FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) {
|
||||
_value = static_cast<T *>(p_variant.operator Object *());
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#define TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, m_editor) \
|
||||
if (unlikely(m_param._is_null_dont_use())) { \
|
||||
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Required object \"" _STR(m_param) "\" is null.", m_msg, m_editor); \
|
||||
return m_retval; \
|
||||
} \
|
||||
typename std::decay_t<decltype(m_param)>::ptr_type m_name = m_param._internal_ptr_dont_use(); \
|
||||
static_assert(true)
|
||||
|
||||
// These macros are equivalent to the ERR_FAIL_NULL*() family of macros, only for RequiredParam<T> instead of raw pointers.
|
||||
#define EXTRACT_PARAM_OR_FAIL(m_name, m_param) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), "", false)
|
||||
#define EXTRACT_PARAM_OR_FAIL_MSG(m_name, m_param, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), m_msg, false)
|
||||
#define EXTRACT_PARAM_OR_FAIL_EDMSG(m_name, m_param, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), m_msg, true)
|
||||
#define EXTRACT_PARAM_OR_FAIL_V(m_name, m_param, m_retval) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, "", false)
|
||||
#define EXTRACT_PARAM_OR_FAIL_V_MSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, false)
|
||||
#define EXTRACT_PARAM_OR_FAIL_V_EDMSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, true)
|
||||
@@ -52,6 +52,7 @@ enum Metadata {
|
||||
METADATA_REAL_IS_DOUBLE,
|
||||
METADATA_INT_IS_CHAR16,
|
||||
METADATA_INT_IS_CHAR32,
|
||||
METADATA_OBJECT_IS_REQUIRED,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -182,6 +183,44 @@ struct GetTypeInfo<T *, std::enable_if_t<std::is_base_of_v<Object, T>>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class RequiredParam;
|
||||
|
||||
template <class T>
|
||||
class RequiredResult;
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<RequiredParam<T>, std::enable_if_t<std::is_base_of_v<Object, T>>> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_OBJECT_IS_REQUIRED;
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(StringName(T::get_class_static()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetTypeInfo<RequiredResult<T>, std::enable_if_t<std::is_base_of_v<Object, T>>> {
|
||||
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_OBJECT_IS_REQUIRED;
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
|
||||
static inline PropertyInfo get_class_info() {
|
||||
return PropertyInfo(StringName(T::get_class_static()));
|
||||
}
|
||||
};
|
||||
|
||||
namespace GodotTypeInfo {
|
||||
namespace Internal {
|
||||
inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {
|
||||
|
||||
@@ -608,6 +608,30 @@ struct VariantInternalAccessor<Object *> {
|
||||
static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { VariantInternal::object_assign(v, p_value); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantInternalAccessor<RequiredParam<T>> {
|
||||
static _FORCE_INLINE_ RequiredParam<T> get(const Variant *v) { return RequiredParam<T>(Object::cast_to<T>(const_cast<Object *>(*VariantInternal::get_object(v)))); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const RequiredParam<T> &p_value) { VariantInternal::object_assign(v, p_value.ptr()); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantInternalAccessor<const RequiredParam<T> &> {
|
||||
static _FORCE_INLINE_ RequiredParam<T> get(const Variant *v) { return RequiredParam<T>(Object::cast_to<T>(*VariantInternal::get_object(v))); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const RequiredParam<T> &p_value) { VariantInternal::object_assign(v, p_value.ptr()); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantInternalAccessor<RequiredResult<T>> {
|
||||
static _FORCE_INLINE_ RequiredResult<T> get(const Variant *v) { return RequiredResult<T>(Object::cast_to<T>(const_cast<Object *>(*VariantInternal::get_object(v)))); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const RequiredResult<T> &p_value) { VariantInternal::object_assign(v, p_value.ptr()); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VariantInternalAccessor<const RequiredResult<T> &> {
|
||||
static _FORCE_INLINE_ RequiredResult<T> get(const Variant *v) { return RequiredResult<T>(Object::cast_to<T>(*VariantInternal::get_object(v))); }
|
||||
static _FORCE_INLINE_ void set(Variant *v, const RequiredResult<T> &p_value) { VariantInternal::object_assign(v, p_value.ptr()); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantInternalAccessor<Variant> {
|
||||
static _FORCE_INLINE_ Variant &get(Variant *v) { return *v; }
|
||||
|
||||
@@ -596,4 +596,28 @@ TEST_CASE("[Object] Destruction at the end of the call chain is safe") {
|
||||
"Object was tail-deleted without crashes.");
|
||||
}
|
||||
|
||||
int required_param_compare(const Ref<RefCounted> &p_ref, const RequiredParam<RefCounted> &p_required) {
|
||||
EXTRACT_PARAM_OR_FAIL_V(extract, p_required, false);
|
||||
ERR_FAIL_COND_V(p_ref->get_reference_count() != extract->get_reference_count(), -1);
|
||||
return p_ref->get_reference_count();
|
||||
}
|
||||
|
||||
TEST_CASE("[Object] RequiredParam Ref<T>") {
|
||||
Ref<RefCounted> ref;
|
||||
ref.instantiate();
|
||||
|
||||
RequiredParam<RefCounted> required = ref;
|
||||
EXTRACT_PARAM_OR_FAIL(extract, required);
|
||||
|
||||
static_assert(std::is_same_v<decltype(ref), decltype(extract)>);
|
||||
|
||||
CHECK_EQ(ref->get_reference_count(), extract->get_reference_count());
|
||||
|
||||
const int count = required_param_compare(ref, ref);
|
||||
CHECK_NE(count, -1);
|
||||
CHECK_NE(count, ref->get_reference_count());
|
||||
|
||||
CHECK_EQ(ref->get_reference_count(), extract->get_reference_count());
|
||||
}
|
||||
|
||||
} // namespace TestObject
|
||||
|
||||
Reference in New Issue
Block a user