text: /*************************************************************************/
  /*  type_info.h                                                          */
  /*************************************************************************/
  /*                       This file is part of:                           */
  /*                           GODOT ENGINE                                */
  /*                      https://godotengine.org                          */
  /*************************************************************************/
  /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
  /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
  /*                                                                       */
  /* 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.                */
  /*************************************************************************/
  
  #ifndef GET_TYPE_INFO_H
  #define GET_TYPE_INFO_H
  
  #ifdef DEBUG_METHODS_ENABLED
  
  template <bool C, typename T = void>
  struct EnableIf {
  
  	typedef T type;
  };
  
  template <typename T>
  struct EnableIf<false, T> {
  };
  
  template <typename, typename>
  struct TypesAreSame {
  
  	static bool const value = false;
  };
  
  template <typename A>
  struct TypesAreSame<A, A> {
  
  	static bool const value = true;
  };
  
  template <typename B, typename D>
  struct TypeInherits {
  
  	static D *get_d();
  
  	static char (&test(B *))[1];
  	static char (&test(...))[2];
  
  	static bool const value = sizeof(test(get_d())) == sizeof(char) &&
  							  !TypesAreSame<B volatile const, void volatile const>::value;
  };
  
  namespace GodotTypeInfo {
  enum Metadata {
  	METADATA_NONE,
  	METADATA_INT_IS_INT8,
  	METADATA_INT_IS_INT16,
  	METADATA_INT_IS_INT32,
  	METADATA_INT_IS_INT64,
  	METADATA_INT_IS_UINT8,
  	METADATA_INT_IS_UINT16,
  	METADATA_INT_IS_UINT32,
  	METADATA_INT_IS_UINT64,
  	METADATA_REAL_IS_FLOAT,
  	METADATA_REAL_IS_DOUBLE
  };
  }
  
  // If the compiler fails because it's trying to instantiate the primary 'GetTypeInfo' template
  // instead of one of the specializations, it's most likely because the type 'T' is not supported.
  // If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration
  // instead of a forward declaration. You can always forward declare 'T' in a header file, and then
  // include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated.
  template <class T, typename = void>
  struct GetTypeInfo;
  
  #define MAKE_TYPE_INFO(m_type, m_var_type)                                            \
  	template <>                                                                       \
  	struct GetTypeInfo<m_type> {                                                      \
  		static const Variant::Type VARIANT_TYPE = m_var_type;                         \
  		static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
  		static inline PropertyInfo get_class_info() {                                 \
  			return PropertyInfo(VARIANT_TYPE, String());                              \
  		}                                                                             \
  	};                                                                                \
  	template <>                                                                       \
  	struct GetTypeInfo<const m_type &> {                                              \
  		static const Variant::Type VARIANT_TYPE = m_var_type;                         \
  		static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
  		static inline PropertyInfo get_class_info() {                                 \
  			return PropertyInfo(VARIANT_TYPE, String());                              \
  		}                                                                             \
  	};
  
  #define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata)    \
  	template <>                                                     \
  	struct GetTypeInfo<m_type> {                                    \
  		static const Variant::Type VARIANT_TYPE = m_var_type;       \
  		static const GodotTypeInfo::Metadata METADATA = m_metadata; \
  		static inline PropertyInfo get_class_info() {               \
  			return PropertyInfo(VARIANT_TYPE, String());            \
  		}                                                           \
  	};                                                              \
  	template <>                                                     \
  	struct GetTypeInfo<const m_type &> {                            \
  		static const Variant::Type VARIANT_TYPE = m_var_type;       \
  		static const GodotTypeInfo::Metadata METADATA = m_metadata; \
  		static inline PropertyInfo get_class_info() {               \
  			return PropertyInfo(VARIANT_TYPE, String());            \
  		}                                                           \
  	};
  
  MAKE_TYPE_INFO(bool, Variant::BOOL)
  MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT8)
  MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8)
  MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16)
  MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16)
  MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32)
  MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
  MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
  MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
  MAKE_TYPE_INFO(wchar_t, Variant::INT)
  MAKE_TYPE_INFO_WITH_META(float, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
  MAKE_TYPE_INFO_WITH_META(double, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
  
  MAKE_TYPE_INFO(String, Variant::STRING)
  MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
  MAKE_TYPE_INFO(Rect2, Variant::RECT2)
  MAKE_TYPE_INFO(Vector3, Variant::VECTOR3)
  MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D)
  MAKE_TYPE_INFO(Plane, Variant::PLANE)
  MAKE_TYPE_INFO(Quat, Variant::QUAT)
  MAKE_TYPE_INFO(AABB, Variant::AABB)
  MAKE_TYPE_INFO(Basis, Variant::BASIS)
  MAKE_TYPE_INFO(Transform, Variant::TRANSFORM)
  MAKE_TYPE_INFO(Color, Variant::COLOR)
  MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH)
  MAKE_TYPE_INFO(RID, Variant::_RID)
  MAKE_TYPE_INFO(Dictionary, Variant::DICTIONARY)
  MAKE_TYPE_INFO(Array, Variant::ARRAY)
  MAKE_TYPE_INFO(PoolByteArray, Variant::POOL_BYTE_ARRAY)
  MAKE_TYPE_INFO(PoolIntArray, Variant::POOL_INT_ARRAY)
  MAKE_TYPE_INFO(PoolRealArray, Variant::POOL_REAL_ARRAY)
  MAKE_TYPE_INFO(PoolStringArray, Variant::POOL_STRING_ARRAY)
  MAKE_TYPE_INFO(PoolVector2Array, Variant::POOL_VECTOR2_ARRAY)
  MAKE_TYPE_INFO(PoolVector3Array, Variant::POOL_VECTOR3_ARRAY)
  MAKE_TYPE_INFO(PoolColorArray, Variant::POOL_COLOR_ARRAY)
  
  MAKE_TYPE_INFO(StringName, Variant::STRING)
  MAKE_TYPE_INFO(IP_Address, Variant::STRING)
  
  class BSP_Tree;
  MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY)
  
  //for RefPtr
  template <>
  struct GetTypeInfo<RefPtr> {
  	static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
  	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
  	static inline PropertyInfo get_class_info() {
  		return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
  	}
  };
  template <>
  struct GetTypeInfo<const RefPtr &> {
  	static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
  	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
  	static inline PropertyInfo get_class_info() {
  		return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
  	}
  };
  
  //for variant
  template <>
  struct GetTypeInfo<Variant> {
  	static const Variant::Type VARIANT_TYPE = Variant::NIL;
  	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
  	static inline PropertyInfo get_class_info() {
  		return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
  	}
  };
  
  template <>
  struct GetTypeInfo<const Variant &> {
  	static const Variant::Type VARIANT_TYPE = Variant::NIL;
  	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
  	static inline PropertyInfo get_class_info() {
  		return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
  	}
  };
  
  #define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type)                       \
  	template <>                                                                       \
  	struct GetTypeInfo<m_template<m_type> > {                                         \
  		static const Variant::Type VARIANT_TYPE = m_var_type;                         \
  		static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
  		static inline PropertyInfo get_class_info() {                                 \
  			return PropertyInfo(VARIANT_TYPE, String());                              \
  		}                                                                             \
  	};                                                                                \
  	template <>                                                                       \
  	struct GetTypeInfo<const m_template<m_type> &> {                                  \
  		static const Variant::Type VARIANT_TYPE = m_var_type;                         \
  		static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
  		static inline PropertyInfo get_class_info() {                                 \
  			return PropertyInfo(VARIANT_TYPE, String());                              \
  		}                                                                             \
  	};
  
  MAKE_TEMPLATE_TYPE_INFO(std::vector, uint8_t, Variant::POOL_BYTE_ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, int, Variant::POOL_INT_ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, float, Variant::POOL_REAL_ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, String, Variant::POOL_STRING_ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, Vector2, Variant::POOL_VECTOR2_ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, Vector3, Variant::POOL_VECTOR3_ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, Color, Variant::POOL_COLOR_ARRAY)
  
  MAKE_TEMPLATE_TYPE_INFO(std::vector, Variant, Variant::ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, RID, Variant::ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, Plane, Variant::ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(std::vector, StringName, Variant::POOL_STRING_ARRAY)
  
  MAKE_TEMPLATE_TYPE_INFO(PoolVector, Plane, Variant::ARRAY)
  MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY)
  
  template <typename T>
  struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
  	static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
  	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
  	static inline PropertyInfo get_class_info() {
  		return PropertyInfo(StringName(T::get_class_static()));
  	}
  };
  
  template <typename T>
  struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
  	static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
  	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
  	static inline PropertyInfo get_class_info() {
  		return PropertyInfo(StringName(T::get_class_static()));
  	}
  };
  
  #define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl)                                                                                                                                 \
  	template <>                                                                                                                                                                   \
  	struct GetTypeInfo<m_impl> {                                                                                                                                                  \
  		static const Variant::Type VARIANT_TYPE = Variant::INT;                                                                                                                   \
  		static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;                                                                                             \
  		static inline PropertyInfo get_class_info() {                                                                                                                             \
  			return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \
  		}                                                                                                                                                                         \
  	};
  
  #define MAKE_ENUM_TYPE_INFO(m_enum)                 \
  	TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum)       \
  	TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \
  	TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &)     \
  	TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
  
  template <typename T>
  inline StringName __constant_get_enum_name(T param, const String &p_constant) {
  	if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL)
  		ERR_PRINTS("Missing VARIANT_ENUM_CAST for constant's enum: " + p_constant);
  	return GetTypeInfo<T>::get_class_info().class_name;
  }
  
  #define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
  
  #else
  
  #define MAKE_ENUM_TYPE_INFO(m_enum)
  #define CLASS_INFO(m_type)
  
  #endif // DEBUG_METHODS_ENABLED
  
  #endif // GET_TYPE_INFO_H
  