Skip to content

Commit 32f5975

Browse files
dsnopekRepiteo
andcommitted
Add RequiredParam<T> and RequiredValue<T> to mark Object * arguments and return values as required
Co-authored-by: Thaddeus Crews <[email protected]>
1 parent 7864ac8 commit 32f5975

File tree

9 files changed

+377
-1
lines changed

9 files changed

+377
-1
lines changed

core/extension/extension_api_dump.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static String get_property_info_type_name(const PropertyInfo &p_info) {
8888
}
8989

9090
static String get_type_meta_name(const GodotTypeInfo::Metadata metadata) {
91-
static const char *argmeta[13] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double", "char16", "char32" };
91+
static const char *argmeta[14] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double", "char16", "char32", "required" };
9292
return argmeta[metadata];
9393
}
9494

core/extension/gdextension_interface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ typedef enum {
432432
GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE,
433433
GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16,
434434
GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32,
435+
GDEXTENSION_METHOD_ARGUMENT_METADATA_OBJECT_IS_REQUIRED,
435436
} GDExtensionClassMethodArgumentMetadata;
436437

437438
typedef void (*GDExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);

core/object/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "core/templates/hash_set.h"
4040
#include "core/templates/list.h"
4141
#include "core/templates/safe_refcount.h"
42+
#include "core/variant/required_ptr.h"
4243
#include "core/variant/variant.h"
4344

4445
template <typename T>

core/variant/binder_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "core/templates/simple_type.h"
3737
#include "core/typedefs.h"
3838
#include "core/variant/method_ptrcall.h"
39+
#include "core/variant/required_ptr.h"
3940
#include "core/variant/type_info.h"
4041
#include "core/variant/variant.h"
4142
#include "core/variant/variant_internal.h"

core/variant/method_ptrcall.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,42 @@ struct PtrToArg<const T *> {
269269
}
270270
};
271271

272+
// This is for RequiredParam.
273+
274+
template <class T>
275+
struct PtrToArg<RequiredParam<T>> {
276+
typedef typename RequiredParam<T>::ptr_type EncodeT;
277+
278+
_FORCE_INLINE_ static RequiredParam<T> convert(const void *p_ptr) {
279+
if (p_ptr == nullptr) {
280+
return RequiredParam<T>::_err_return_dont_use();
281+
}
282+
return RequiredParam<T>(*reinterpret_cast<T *const *>(p_ptr));
283+
}
284+
285+
_FORCE_INLINE_ static void encode(const RequiredParam<T> &p_var, void *p_ptr) {
286+
*((typename RequiredParam<T>::ptr_type *)p_ptr) = p_var._internal_ptr_dont_use();
287+
}
288+
};
289+
290+
// This is for RequiredResult.
291+
292+
template <class T>
293+
struct PtrToArg<RequiredResult<T>> {
294+
typedef typename RequiredResult<T>::ptr_type EncodeT;
295+
296+
_FORCE_INLINE_ static RequiredResult<T> convert(const void *p_ptr) {
297+
if (p_ptr == nullptr) {
298+
return RequiredResult<T>::_err_return_dont_use();
299+
}
300+
return RequiredResult<T>(*reinterpret_cast<T *const *>(p_ptr));
301+
}
302+
303+
_FORCE_INLINE_ static void encode(const RequiredResult<T> &p_var, void *p_ptr) {
304+
*((typename RequiredResult<T>::ptr_type *)p_ptr) = p_var._internal_ptr_dont_use();
305+
}
306+
};
307+
272308
// This is for ObjectID.
273309

274310
template <>

core/variant/required_ptr.h

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/**************************************************************************/
2+
/* required_ptr.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#pragma once
32+
33+
#include "core/variant/variant.h"
34+
35+
template <typename T>
36+
class RequiredResult {
37+
static_assert(!is_fully_defined_v<T> || std::is_base_of_v<Object, T>, "T must be an Object subtype");
38+
39+
public:
40+
using element_type = T;
41+
using ptr_type = std::conditional_t<std::is_base_of_v<RefCounted, T>, Ref<T>, T *>;
42+
43+
private:
44+
ptr_type _value = ptr_type();
45+
46+
_FORCE_INLINE_ RequiredResult() = default;
47+
48+
public:
49+
RequiredResult(const RequiredResult &p_other) = default;
50+
RequiredResult(RequiredResult &&p_other) = default;
51+
RequiredResult &operator=(const RequiredResult &p_other) = default;
52+
RequiredResult &operator=(RequiredResult &&p_other) = default;
53+
54+
_FORCE_INLINE_ RequiredResult(std::nullptr_t) :
55+
RequiredResult() {}
56+
_FORCE_INLINE_ RequiredResult &operator=(std::nullptr_t) { _value = nullptr; }
57+
58+
// These functions should not be called directly, they are only for internal use.
59+
_FORCE_INLINE_ ptr_type _internal_ptr_dont_use() const { return _value; }
60+
_FORCE_INLINE_ static RequiredResult<T> _err_return_dont_use() { return RequiredResult<T>(); }
61+
62+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
63+
_FORCE_INLINE_ RequiredResult(const RequiredResult<T_Other> &p_other) :
64+
_value(p_other._value) {}
65+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
66+
_FORCE_INLINE_ RequiredResult &operator=(const RequiredResult<T_Other> &p_other) {
67+
_value = p_other._value;
68+
return *this;
69+
}
70+
71+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
72+
_FORCE_INLINE_ RequiredResult(T_Other *p_ptr) :
73+
_value(p_ptr) {}
74+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
75+
_FORCE_INLINE_ RequiredResult &operator=(T_Other *p_ptr) {
76+
_value = p_ptr;
77+
return *this;
78+
}
79+
80+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
81+
_FORCE_INLINE_ RequiredResult(const Ref<T_Other> &p_ref) :
82+
_value(p_ref) {}
83+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
84+
_FORCE_INLINE_ RequiredResult &operator=(const Ref<T_Other> &p_ref) {
85+
_value = p_ref;
86+
return *this;
87+
}
88+
89+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
90+
_FORCE_INLINE_ RequiredResult(Ref<T_Other> &&p_ref) :
91+
_value(std::move(p_ref)) {}
92+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
93+
_FORCE_INLINE_ RequiredResult &operator=(Ref<T_Other> &&p_ref) {
94+
_value = std::move(p_ref);
95+
return &this;
96+
}
97+
98+
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
99+
_FORCE_INLINE_ RequiredResult(const Variant &p_variant) :
100+
_value(static_cast<T *>(p_variant.get_validated_object())) {}
101+
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
102+
_FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) {
103+
_value = static_cast<T *>(p_variant.get_validated_object());
104+
return *this;
105+
}
106+
107+
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
108+
_FORCE_INLINE_ RequiredResult(const Variant &p_variant) :
109+
_value(static_cast<T *>(p_variant.operator Object *())) {}
110+
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
111+
_FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) {
112+
_value = static_cast<T *>(p_variant.operator Object *());
113+
return *this;
114+
}
115+
116+
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
117+
_FORCE_INLINE_ element_type *ptr() const {
118+
return *_value;
119+
}
120+
121+
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
122+
_FORCE_INLINE_ element_type *ptr() const {
123+
return _value;
124+
}
125+
126+
_FORCE_INLINE_ operator ptr_type() {
127+
return _value;
128+
}
129+
130+
_FORCE_INLINE_ operator Variant() const {
131+
return Variant(_value);
132+
}
133+
134+
_FORCE_INLINE_ element_type *operator*() const {
135+
return ptr();
136+
}
137+
138+
_FORCE_INLINE_ element_type *operator->() const {
139+
return ptr();
140+
}
141+
};
142+
143+
template <typename T>
144+
class RequiredParam {
145+
static_assert(!is_fully_defined_v<T> || std::is_base_of_v<Object, T>, "T must be an Object subtype");
146+
147+
public:
148+
using element_type = T;
149+
using ptr_type = std::conditional_t<std::is_base_of_v<RefCounted, T>, Ref<T>, T *>;
150+
151+
private:
152+
ptr_type _value;
153+
154+
_FORCE_INLINE_ RequiredParam() {
155+
if constexpr (!std::is_base_of_v<RefCounted, T>) {
156+
_value = nullptr;
157+
}
158+
}
159+
160+
public:
161+
// These functions should not be called directly, they are only for internal use.
162+
_FORCE_INLINE_ ptr_type _internal_ptr_dont_use() const { return _value; }
163+
_FORCE_INLINE_ bool _is_null_dont_use() const {
164+
if constexpr (std::is_base_of_v<RefCounted, T>) {
165+
return _value.is_null();
166+
} else {
167+
return _value == nullptr;
168+
}
169+
}
170+
_FORCE_INLINE_ static RequiredParam<T> _err_return_dont_use() { return RequiredParam<T>(); }
171+
172+
// Prevent erroneously assigning null values by explicitly removing nullptr constructor/assignment.
173+
RequiredParam(std::nullptr_t) = delete;
174+
RequiredParam &operator=(std::nullptr_t) = delete;
175+
176+
RequiredParam(const RequiredParam &p_other) = default;
177+
RequiredParam(RequiredParam &&p_other) = default;
178+
RequiredParam &operator=(const RequiredParam &p_other) = default;
179+
RequiredParam &operator=(RequiredParam &&p_other) = default;
180+
181+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
182+
_FORCE_INLINE_ RequiredParam(const RequiredParam<T_Other> &p_other) :
183+
_value(p_other._internal_ptr_dont_use()) {}
184+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
185+
_FORCE_INLINE_ RequiredParam &operator=(const RequiredParam<T_Other> &p_other) {
186+
_value = p_other._internal_ptr_dont_use();
187+
return *this;
188+
}
189+
190+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
191+
_FORCE_INLINE_ RequiredParam(T_Other *p_ptr) :
192+
_value(p_ptr) {}
193+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
194+
_FORCE_INLINE_ RequiredParam &operator=(T_Other *p_ptr) {
195+
_value = p_ptr;
196+
return *this;
197+
}
198+
199+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
200+
_FORCE_INLINE_ RequiredParam(const Ref<T_Other> &p_ref) :
201+
_value(p_ref) {}
202+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
203+
_FORCE_INLINE_ RequiredParam &operator=(const Ref<T_Other> &p_ref) {
204+
_value = p_ref;
205+
return *this;
206+
}
207+
208+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
209+
_FORCE_INLINE_ RequiredParam(Ref<T_Other> &&p_ref) :
210+
_value(std::move(p_ref)) {}
211+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
212+
_FORCE_INLINE_ RequiredParam &operator=(Ref<T_Other> &&p_ref) {
213+
_value = std::move(p_ref);
214+
return &this;
215+
}
216+
217+
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
218+
_FORCE_INLINE_ RequiredParam(const Variant &p_variant) :
219+
_value(static_cast<T *>(p_variant.get_validated_object())) {}
220+
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
221+
_FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) {
222+
_value = static_cast<T *>(p_variant.get_validated_object());
223+
return *this;
224+
}
225+
226+
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
227+
_FORCE_INLINE_ RequiredParam(const Variant &p_variant) :
228+
_value(static_cast<T *>(p_variant.operator Object *())) {}
229+
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
230+
_FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) {
231+
_value = static_cast<T *>(p_variant.operator Object *());
232+
return *this;
233+
}
234+
};
235+
236+
#define TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, m_editor) \
237+
if (unlikely(m_param._is_null_dont_use())) { \
238+
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Required object \"" _STR(m_param) "\" is null.", m_msg, m_editor); \
239+
return m_retval; \
240+
} \
241+
typename std::decay_t<decltype(m_param)>::ptr_type m_name = m_param._internal_ptr_dont_use(); \
242+
static_assert(true)
243+
244+
// These macros are equivalent to the ERR_FAIL_NULL*() family of macros, only for RequiredParam<T> instead of raw pointers.
245+
#define EXTRACT_PARAM_OR_FAIL(m_name, m_param) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), "", false)
246+
#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)
247+
#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)
248+
#define EXTRACT_PARAM_OR_FAIL_V(m_name, m_param, m_retval) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, "", false)
249+
#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)
250+
#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)

core/variant/type_info.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum Metadata {
5252
METADATA_REAL_IS_DOUBLE,
5353
METADATA_INT_IS_CHAR16,
5454
METADATA_INT_IS_CHAR32,
55+
METADATA_OBJECT_IS_REQUIRED,
5556
};
5657
}
5758

@@ -182,6 +183,44 @@ struct GetTypeInfo<T *, std::enable_if_t<std::is_base_of_v<Object, T>>> {
182183
}
183184
};
184185

186+
template <class T>
187+
class RequiredParam;
188+
189+
template <class T>
190+
class RequiredResult;
191+
192+
template <typename T>
193+
struct GetTypeInfo<RequiredParam<T>, std::enable_if_t<std::is_base_of_v<Object, T>>> {
194+
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
195+
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_OBJECT_IS_REQUIRED;
196+
197+
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
198+
static inline PropertyInfo get_class_info() {
199+
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
200+
}
201+
202+
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
203+
static inline PropertyInfo get_class_info() {
204+
return PropertyInfo(StringName(T::get_class_static()));
205+
}
206+
};
207+
208+
template <typename T>
209+
struct GetTypeInfo<RequiredResult<T>, std::enable_if_t<std::is_base_of_v<Object, T>>> {
210+
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
211+
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_OBJECT_IS_REQUIRED;
212+
213+
template <typename U = T, std::enable_if_t<std::is_base_of_v<RefCounted, U>, int> = 0>
214+
static inline PropertyInfo get_class_info() {
215+
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
216+
}
217+
218+
template <typename U = T, std::enable_if_t<!std::is_base_of_v<RefCounted, U>, int> = 0>
219+
static inline PropertyInfo get_class_info() {
220+
return PropertyInfo(StringName(T::get_class_static()));
221+
}
222+
};
223+
185224
namespace GodotTypeInfo {
186225
namespace Internal {
187226
inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {

0 commit comments

Comments
 (0)