Files
GacUI/Import/VlppReflection.h
2024-09-29 00:14:53 -07:00

8058 lines
269 KiB
C++

/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppOS.h"
#include "Vlpp.h"
#include "VlppRegex.h"
/***********************************************************************
.\DESCRIPTABLEOBJECT.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_DESCRIPTABLEOBJECT
#define VCZH_REFLECTION_DESCRIPTABLEOBJECT
#if (defined VCZH_DEBUG_NO_REFLECTION) && (defined VCZH_DEBUG_METAONLY_REFLECTION)
static_assert(false, "Preprocessor VCZH_DEBUG_NO_REFLECTION and VCZH_DEBUG_METAONLY_REFLECTION could not be defined at the same time.")
#endif
#if !(defined VCZH_DEBUG_NO_REFLECTION) && !(defined VCZH_DEBUG_METAONLY_REFLECTION)
#define VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
#endif
namespace vl
{
namespace reflection
{
namespace description
{
class ITypeDescriptor;
}
/***********************************************************************
DescriptableObject
***********************************************************************/
/// <summary>
/// <p>
/// Base class of all reflectable value types (class).
/// If you want to create a reflectable class, you should inherit from [T:vl.reflection.Description`1].
/// </p>
/// <p>
/// Inheriting from [T:vl.reflection.Description`1] is necessary even if you turned on "VCZH_DEBUG_NO_REFLECTION" preprocessor definition.
/// In this case, some members will be removed from this class to reduce the object size.
/// </p>
/// <p>
/// <b>Ptr&lt;DescriptableObject&gt;</b> is recommended to replace <b>Ptr&lt;Object&gt;</b> for holding a reflectable object.
/// When a class <b>T</b> inherits from [T:vl.reflection.Description`1], including <b>DescriptableObject</b> itself,
/// <b>Ptr&lt;T&gt;</b> is safe to be created directly from a <b>T*</b> hold by another <b>Ptr&lt;T&gt;</b>.
/// This is not allowed for all classes that do not inherit from [T:vl.reflection.Description`1].
/// </p>
/// </summary>
/// <remarks>
/// <p>
/// When a class in Workflow script inherits from a class in C++,
/// since it is not possible to actually create a class in runtime,
/// so the created object from this Workflow class is multiple <b>DescriptableObject</b> grouping together.
/// </p>
/// <p>
/// This is called <b>aggregation</b>.
/// </p>
/// <p>
/// In this case, <see cref="SafeAggregationCast`1"/> is required to do pointer casting to a C++ class.
/// </p>
/// <p>
/// To allow a C++ class to be aggregated,
/// use [T:vl.reflection.AggregatableDescription`1] instead of [T:vl.reflection.Description`1],
/// and call <see cref="FinalizeAggregation"/> in the destructor.
/// If A inherits B and they are all aggregatable, do it in both destructors.
/// </p>
/// </remarks>
/// <example><![CDATA[
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// WString data;
/// };
///
/// int main()
/// {
/// auto myClass = Ptr(new MyClass);
/// myClass->data = L"Hello, world!";
///
/// Ptr<DescriptableObject> obj = myClass;
/// Console::WriteLine(obj.Cast<MyClass>()->data);
///
/// // usually you cannot do this directly
/// // because obj and myClass share the same reference counter, but myClass2 doesn't
/// // this will cause the destructor delete MyClass twice and crash
/// // but it is different when MyClass inherits from Description<MyClass> or AggregatableDescription<MyClass>
/// auto myClass2 = Ptr<MyClass>(dynamic_cast<MyClass*>(obj.Obj()));
/// Console::WriteLine(myClass2->data);
/// }
/// ]]></example>
class DescriptableObject
{
template<typename T, typename Enabled>
friend struct vl::ReferenceCounterOperator;
template<typename T>
friend class Description;
typedef collections::Dictionary<WString, Ptr<Object>> InternalPropertyMap;
typedef bool(*DestructorProc)(DescriptableObject* obj, bool forceDisposing);
private:
atomic_vint referenceCounter;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
size_t objectSize;
description::ITypeDescriptor** typeDescriptor;
#endif
Ptr<InternalPropertyMap> internalProperties;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
bool destructing;
DescriptableObject** aggregationInfo;
vint aggregationSize;
#endif
protected:
DestructorProc sharedPtrDestructorProc;
protected:
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
// Returns true if this object inherits other objects by aggregation.</returns>
bool IsAggregated();
// Returnd the number of aggregated base objects.</returns>
vint GetAggregationSize();
// Return the object that inherit this object.</returns>
DescriptableObject* GetAggregationRoot();
// Notice that an object inherit this object, it is called by SetAggregationParent
void SetAggregationRoot(DescriptableObject* value);
// Return the specified aggregated base object
DescriptableObject* GetAggregationParent(vint index);
// Set an aggregated base class
void SetAggregationParent(vint index, DescriptableObject* value);
// Set an aggregated base class
void SetAggregationParent(vint index, Ptr<DescriptableObject>& value);
// Must be called in Workflow generated classes that inherit from aggregatable C++ classes.
void InitializeAggregation(vint size);
#endif
/// <summary>A function that must be called in destructors of all classes inheriting from [T:vl.reflection.AggregatableDescription`1].</summary>
void FinalizeAggregation();
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
template<typename T>
void SafeAggregationCast(T*& result)
{
auto expected = dynamic_cast<T*>(this);
if (expected)
{
CHECK_ERROR(result == nullptr, L"vl::reflection::DescriptableObject::SafeAggregationCast<T>()#Found multiple ways to do aggregation cast.");
result = expected;
}
if (IsAggregated())
{
for (vint i = 0; i < aggregationSize; i++)
{
if (auto parent = GetAggregationParent(i))
{
parent->SafeAggregationCast<T>(result);
}
}
}
}
#endif
public:
DescriptableObject();
virtual ~DescriptableObject();
// all fields are describing the object, it would be incorrect if they are copied from one to another.
DescriptableObject(const DescriptableObject&) : DescriptableObject() {}
DescriptableObject(DescriptableObject&&) : DescriptableObject() {}
DescriptableObject& operator=(const DescriptableObject&) { return *this; }
DescriptableObject& operator=(DescriptableObject&&) { return *this; }
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
/// <summary>
/// <p>Get the type descriptor that describe the real type of this object.</p>
/// </summary>
/// <returns>The real type.</returns>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
description::ITypeDescriptor* GetTypeDescriptor();
#endif
/// <summary>
/// Get an internal property of this object.
/// Internal properties are totally for customization,
/// they do not affect the object in anyway.
/// </summary>
/// <returns>Value of the internal property of this object.</returns>
/// <param name="name">Name of the property.</param>
Ptr<Object> GetInternalProperty(const WString& name);
/// <summary>
/// Set an internal property of this object.
/// Internal properties are totally for customization,
/// they do not affect the object in anyway.
/// </summary>
/// <param name="name">Name of the property.</param>
/// <param name="value">Value of the internal property of this object.</param>
void SetInternalProperty(const WString& name, Ptr<Object> value);
/// <summary>Try to delete this object.</summary>
/// <returns>Returns true if this operation succeeded. Returns false if the object refuces to be dispose.</returns>
/// <param name="forceDisposing">Set to true to force disposing this object. If the reference counter is not 0 if you force disposing it, it will raise a [T:vl.reflection.description.ValueNotDisposableException].</param>
bool Dispose(bool forceDisposing);
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
/// <summary>
/// <p>Get the aggregation root object, which is the object that inherits this object by aggregation.</p>
/// </summary>
/// <returns>The aggregation root object. If this object is not aggregated, or it is the root object of others, than this function return itself.</returns>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
DescriptableObject* SafeGetAggregationRoot();
#endif
/// <summary>Cast the object to another type, this is required when the object is involved in aggregation.</summary>
/// <returns>The object with the expected type in all involved aggregated objects. It will crash when multiple objects are found to be qualified.</returns>
/// <typeparam name="T">The expected type to cast.</typeparam>
/// <remarks>
/// <p>
/// A workflow class could inherit from multiple aggregatable C++ classes.
/// </p>
/// <p>
/// In order to do pointer casting correctly,
/// this function allow you to cast from one aggregated C++ base object to another aggregated C++ base object,
/// even when these two objects are not involved in inheriting in C++.
/// </p>
/// <p>
/// When <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>on</b>, it performs dynamic_cast.
/// </p>
/// </remarks>
template<typename T>
T* SafeAggregationCast()
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
T* result = nullptr;
SafeGetAggregationRoot()->SafeAggregationCast<T>(result);
return result;
#else
return dynamic_cast<T*>(this);
#endif
}
};
/// <summary>
/// <p>
/// Inherit from this class when you want to create a reflectable class.
/// It should be used like this:
/// <program><code><![CDATA[
/// class YourClass : public Description<YourClass>
/// {
/// ..
/// };
/// ]]></code></program>
/// </p>
/// <p>
/// If you want YourClass to be inheritable in scripts,
/// instead of using Description,
/// you should use <see cref="AggregatableDescription`1"/>, like this:
/// <program><code><![CDATA[
/// class YourClass : public AggregatableDescription<YourClass>
/// {
/// ~YourClass()
/// {
/// FinalizeAggregation();
/// }
/// };
/// ]]></code></program>
/// </p>
/// <p>
/// After you complete your type,
/// use the following macros and functions to register your class into the global type table.
/// </p>
/// <p>
/// Some of the predefined type has already been registered.
/// If your types depend on these types, you should load those types by calling some or all of them:
/// <ul>
/// <li>[F:vl.reflection.description.LoadPredefinedTypes]</li>
/// <li>[F:vl.reflection.description.LoadParsingTypes]</li>
/// <li>[F:vl.reflection.description.JsonLoadTypes]</li>
/// <li>[F:vl.reflection.description.XmlLoadTypes]</li>
/// </ul>
/// But if you link <b>GacUIReflection.cpp</b> in your project and set <b>VCZH_DEBUG_NO_REFLECTION</b> to off,
/// all types will be automatically loaded before <b>GuiMain</b> is called.
/// </p>
/// <p>
/// The order does not matter, because content of types are lazily loaded.
/// </p>
/// <p>
/// Everything below should be put in <b>vl::reflection::description</b> namespaces.
/// <ol>
/// <li>
/// <b>(in header files)</b> Create a macro that contains all types that you want to register.
/// Content in the list will become full names for registered type,
/// so it is strongly recommended to use the full name.
/// <program><code><![CDATA[
/// #define MY_TYPELIST(F)\
/// F(mynamespaces::MyClass1)\
/// F(mynamespaces::MyClass2)\
/// ]]></code></program>
/// </li>
/// <li>
/// <b>in header files)</b> Connect type names and types:
/// <program><code><![CDATA[
/// MY_TYPELIST(DECL_TYPE_INFO)
/// ]]></code></program>
/// </li>
/// <li>
/// <b>(in cpp files)</b> Connect type names and types:
/// <program><code><![CDATA[
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
/// ]]></code></program>
/// </li>
/// <li>
/// <b>(in cpp files)</b> Register all members:
/// <ul>
/// <li>
/// You will need to define a macro for commas, Whatever name is fine.
/// <program><code><![CDATA[
/// #define _ ,
/// ]]></code></program>
/// </li>
/// <li>
/// <b>enum</b>:
/// use <b>BEGIN_ENUM_ITEM_MERGABLE</b> instead of <b>BEGIN_ENUM_ITEM</b> if enum items are flags instead of concrete items.
/// <program><code><![CDATA[
/// BEGIN_ENUM_ITEM(Season)
/// ENUM_ITEM(Spring)
/// ENUM_ITEM(Summer)
/// ENUM_ITEM(Autumn)
/// ENUM_ITEM(Winter)
/// END_ENUM_ITEM(Season)
/// ]]></code></program>
/// </li>
/// <li>
/// <b>enum class:</b>
/// use <b>BEGIN_ENUM_ITEM_MERGABLE</b> instead of <b>BEGIN_ENUM_ITEM</b> if enum items are flags instead of concrete items.
/// <program><code><![CDATA[
/// BEGIN_ENUM_ITEM(Season)
/// ENUM_CLASS_ITEM(Spring)
/// ENUM_CLASS_ITEM(Summer)
/// ENUM_CLASS_ITEM(Autumn)
/// ENUM_CLASS_ITEM(Winter)
/// END_ENUM_ITEM(Season)
/// ]]></code></program>
/// </li>
/// <li>
/// <b>struct</b>:
/// It doesn't necessary mean a struct in C++.
/// Structs in reflection and Workflow script mean value types that carry only data, without methods and inheritance.
/// <program><code><![CDATA[
/// BEGIN_STRUCT_MEMBER(Point)
/// STRUCT_MEMBER(x)
/// STRUCT_MEMBER(y)
/// END_STRUCT_MEMBER(Point)
/// ]]></code></program>
/// </li>
/// <li>
/// <p>
/// <b>class</b>:
/// It doesn't necessary mean a class in C++.
/// Classes in reflection and Workflow script mean reference types.
/// </p>
/// <p>
/// Here are all macros that register content of classes
/// <ul>
/// <li>CLASS_MEMBER_BASE</li>
/// <li>CLASS_MEMBER_FIELD</li>
/// <li>CLASS_MEMBER_CONSTRUCTOR</li>
/// <li>CLASS_MEMBER_EXTERNALCTOR(_TEMPLATE)?</li>
/// <li>CLASS_MEMBER_METHOD(_OVERLOAD)?_RENAME</li>
/// <li>CLASS_MEMBER_(STATIC_)?METHOD(_OVERLOAD)?</li>
/// <li>CLASS_MEMBER_(STATIC_)?EXTERNALMETHOD(_TEMPLATE)?</li>
/// <li>CLASS_MEMBER_PROPERTY(_EVENT)?(_READONLY)?(_FAST)?</li>
/// <li>CLASS_MEMBER_PROPERTY_REFERENCETEMPLATE</li>
/// <li>CLASS_MEMBER_EVENT</li>
/// </ul>
/// </p>
/// <p>
/// <program><code><![CDATA[
/// BEGIN_CLASS_MEMBER(MyClass)
///
/// // 01) Declare a base class (can have multiple base classes).
/// CLASS_MEMBER_BASE(MyBaseClass)
///
/// // 02) Declare a field.
/// CLASS_MEMBER_FIELD(myField)
///
/// // 03) Default constructor that results in a raw pointer.
/// CLASS_MEMBER_CONSTRUCTIOR(MyClass*(), NO_PARAMETER)
///
/// // 04) Default constructor that results in a shared pointer.
/// CLASS_MEMBER_CONSTRUCTIOR(Ptr<MyClass>(), NO_PARAMETER)
///
/// // 05) Constructor with arguments.
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(int, const WString&), {L"numberParameter" _ L"stringParameter"})
///
/// // 06) Inject a global function as a constructor.
/// CLASS_MEMBER_EXTERNALCTOR(Ptr<MyClass>(int, const WString&), {L"numberParameter" _ L"stringParameter"}, mynamespace::CreateMyClass)
///
/// // 07) Inject a consturctor and specify how to generate C++ code, "*" means not able to generate.
/// CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(Ptr<MyClass>(int, const WString&), {L"numberParameter" _ L"stringParameter"}, CreateMyClass, L"mynamespace::GetMyClass($Arguments)", L"::vl::Func<$Func>(&mynamespace::GetMyClass)")
/// CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(Ptr<MyClass>(), NO_PARAMETER, []()->Ptr<MyClass>{return nullptr;}, L"*", L"*")
///
/// // 08) Add unoverloaded functions.
/// CLASS_MEMBER_METHOD(MyFunction1, NO_PARAMETER)
/// CLASS_MEMBER_METHOD(MyFunction2, {L"parameter1" _ L"parameter2"})
///
/// // 09) Add unoverloaded functions but give different names. Unoverloaded only means in C++, not in renamed functions.
/// CLASS_MEMBER_METHOD_RENAME(MyNewName1, MyFunction1, NO_PARAMETER)
/// CLASS_MEMBER_METHOD_RENAME(MyNewName2, MyFunction2, {L"parameter1" _ L"parameter2"})
///
/// // 10) Add overloaded functions, with function type specified in method pointers
/// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, NO_PARAMETER, int(MyClass::*)())
/// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, {L"parameter"}, int(MyClass::*)(int))
/// CLASS_MEMBER_METHOD_OVERLOAD(MyFunction3, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&))
///
/// // 11) Add overloaded functions but give different names.
/// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName3, MyFunction3, NO_PARAMETER, int(MyClass::*)())
/// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName4, MyFunction3, {L"parameter"}, int(MyClass::*)(int))
/// CLASS_MEMBER_METHOD_OVERLOAD_RENAME(MyNewName4, MyFunction3, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&))
///
/// // 12) Inject global functions as methods:
/// CLASS_MEMBER_EXTERNALMETHOD(MyNewName5, {L"parameter"}, int(MyClass::*)(int), mynamespace::AGlobalFunction)
///
/// // 13) Inject a method and specify how to generate C++ code, "*" means not able to generate.
/// CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(MyNewName5, {L"parameter1" _ L"parameter2"}, int(MyClass::*)(int, const WString&), [](MyClass* a, int b, const WString& c){return 0;}, L"*", L"*")
///
/// // 14) Add unoverloaded static functions
/// CLASS_MEMBER_STATIC_METHOD(MyFunction4, NO_PARAMETER)
/// CLASS_MEMBER_STATIC_METHOD(MyFunction5, {L"parameter1" _ L"parameter2"})
///
/// // 15) Add overloaded static functions
/// CLASS_MEMBER_STATIC_METHOD_OVERLOAD(MyFunction6, NO_PARAMETER, int(*)())
/// CLASS_MEMBER_STATIC_METHOD_OVERLOAD(MyFunction6, {L"parameter"}, int(*)(int))
/// CLASS_MEMBER_STATIC_METHOD_OVERLOAD(MyFunction6, {L"parameter1" _ L"parameter2"}, int(*)(int, const WString&))
///
/// // 16) Inject global functions as static methods:
/// CLASS_MEMBER_STATIC_EXTERNALMETHOD(MyNewName6, {L"parameter"}, int(*)(int), mynamespace::AGlobalFunction2)
///
/// // 17) Inject a static method and specify how to generate C++ code, "*" means not able to generate.
/// CLASS_MEMBER_STATIC_EXTERNALMETHOD_TEMPLATE(MyNewName6, {L"parameter1" _ L"parameter2"}, int(*)(int, const WString&), [](int b, const WString& c){return 0;}, L"*")
///
/// // 18) Add a getter function as a property
/// CLASS_MEMBER_PROPERTY_READONLY_FAST(X)
/// // which is short for
/// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
/// CLASS_MEMBER_PROPERTY_READONLY(X, GetX)
///
/// // 19) Add a pair of getter and setter functions as a property
/// CLASS_MEMBER_PROPERTY_FAST(X)
/// // which is short for
/// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
/// CLASS_MEMBER_METHOD(SetX, {L"value"})
/// CLASS_MEMBER_PROPERTY(X, GetX, SetX)
///
/// // 20) Add a getter function as a property with a property changed event
/// CLASS_MEMBER_EVENT(XChanged)
/// CLASS_MEMBER_PROPERTY_EVENT_READONLY_FAST(X, XChanged)
/// // which is short for
/// CLASS_MEMBER_EVENT(XChanged)
/// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
/// CLASS_MEMBER_PROPERTY_EVENT_READONLY(X, GetX, XChanged)
///
/// // 21) Add a pair of getter and setter functions as a property with a property changed event
/// CLASS_MEMBER_EVENT(XChanged)
/// CLASS_MEMBER_PROPERTY_EVENT_FAST(X, XChanged)
/// // which is short for
/// CLASS_MEMBER_EVENT(XChanged)
/// CLASS_MEMBER_METHOD(GetX, NO_PARAMETER)
/// CLASS_MEMBER_METHOD(SetX, {L"value"})
/// CLASS_MEMBER_PROPERTY_EVENT(X, GetX, SetX, XChanged)
///
/// END_CLASS_MEMBER(MyClass)
/// ]]></code></program>
/// </p>
/// <p>
/// If the code compiles, the class should look like this:
/// <program><code><![CDATA[
/// class MyClass : public Description<MyClass>
/// {
/// public:
/// MyClass();
/// MyClass(int numberParameter, const WString& stringParameter);
///
/// int MyFunction1();
/// int MyFunction2(int parameter1, const WString& parameter2);
/// int MyFunction3();
/// int MyFunction3(int parameter);
/// int MyFunction3(int parameter1, const WString& parameter2);
///
/// static int MyFunction4();
/// static int MyFunction5(int parameter1, const WString& parameter2);
/// static int MyFunction6();
/// static int MyFunction6(int parameter);
/// static int MyFunction6(int parameter1, const WString& parameter2);
///
/// Event<void()> XChanged;
/// int GetX();
/// void SetX(int value);
/// };
///
/// Ptr<MyClass> CreateMyClass(int numberParameter, const WString7 stringParameter);
/// int GlobalFunction(MyClass* self, int parameter);
/// ]]></code></program>
/// </p>
/// </li>
/// <li>
/// <p>
/// <b>interface</b>:
/// A C++ class can be registered as a reflectable interface if:
/// <ul>
/// <li>Directly or indirectly inherits [T:vl.reflection.IDescriptable]</li>
/// <li>The only registered constructor (if exists) should use Ptr&lt;[T:vl.reflection.description.IValueInterfaceProxy]&gt; as a parameter, so that a Workflow script class could implement this interface.</li>
/// </ul>
/// </p>
/// <p>
/// Suppose you have an interface like this:
/// <program><code><![CDATA[
/// class IMyInterface : public virtual IDescriptable, public Description<IMyInterface>
/// {
/// public:
/// int GetX();
/// void SetX(int value);
/// };
/// ]]></code></program>
/// </p>
/// <p>
/// If you want to allow a Workflow script class implement this interface, you should first add a proxy like this:
/// <program><code><![CDATA[
/// #pragma warning(push)
/// #pragma warning(disable:4250)
/// BEGIN_INTERFACE_PROXY_NOPARENT_RAWPTR(IMyInterface)
/// // or BEGIN_INTERFACE_PROXY_RAWPTR(IMyInterface, baseInterfaces...)
/// // or BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(IMyInterface)
/// // or BEGIN_INTERFACE_PROXY_SHAREDPTR(IMyInterface, baseInterfaces...)
/// int GetX()override
/// {
/// INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetX)
/// }
///
/// void SetX(int value)override
/// {
/// INVOKE_INTERFACE_PROXY(SetX, value)
/// }
/// END_INTERFACE_PROXY(IMyInterface)
/// #pragma warning(pop)
/// ]]></code></program>
/// </p>
/// <p>
/// And then use this code to register the interface:
/// <program><code><![CDATA[
/// BEGIN_INTERFACE_MEMBER(IMyInterface)
/// ...
/// END_INTERFACE_MEMBER(IMyInterface)
/// ]]></code></program>
/// </p>
/// <p>
/// Everything else is the same as registering classes.
/// Use <b>BEGIN_INTERFACE_MEMBER_NOPROXY</b> to register an interface without a proxy,
/// which means a Workflow script class cannot implement this interface.
/// </p>
/// </li>
/// <li>
/// Undefine the macro for comma:
/// <program><code><![CDATA[
/// #undef _
/// ]]></code></program>
/// </li>
/// </ul>
/// </li>
/// <li>
/// <b>(in cpp files)</b> Create a type loader:
/// <program><code><![CDATA[
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
/// ]]></code></program>
/// </li>
/// <li>
/// Before using reflection on registered types, you need to register the type loader:
/// <program><code><![CDATA[
/// vl::reflection::description::GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// ]]></code></program>
/// </li>
/// </ol>
/// </p>
/// </summary>
/// <typeparam name="T">Type that inherit this class.</typeparam>
template<typename T>
class Description : public virtual DescriptableObject
{
protected:
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
static description::ITypeDescriptor* associatedTypeDescriptor;
#endif
public:
Description()
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if(objectSize<sizeof(T))
{
objectSize=sizeof(T);
if(!typeDescriptor || !*typeDescriptor || associatedTypeDescriptor)
{
typeDescriptor=&associatedTypeDescriptor;
}
}
#endif
}
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
static description::ITypeDescriptor* GetAssociatedTypeDescriptor()
{
return associatedTypeDescriptor;
}
static void SetAssociatedTypeDescriptor(description::ITypeDescriptor* typeDescroptor)
{
associatedTypeDescriptor=typeDescroptor;
}
#endif
};
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
template<typename T>
description::ITypeDescriptor* Description<T>::associatedTypeDescriptor = 0;
#endif
/***********************************************************************
AggregatableDescription
***********************************************************************/
/// <summary>
/// Inherit from this class when you want to create a reflectable class that can be inherited by Workflow script classes.
/// </summary>
/// <typeparam name="T">Type that inherit this class.</typeparam>
template<typename T>
class AggregatableDescription : public Description<T>
{
};
/***********************************************************************
IDescriptable
***********************************************************************/
/// <summary>Base type of all reflectable interfaces. All reflectable interface types should be virtual inherited.</summary>
class IDescriptable : public virtual Interface, public Description<IDescriptable>
{
public:
~IDescriptable(){}
};
/***********************************************************************
ReferenceCounterOperator
***********************************************************************/
}
template<typename T>
struct ReferenceCounterOperator<T, std::enable_if_t<std::is_convertible_v<T*, reflection::DescriptableObject*>>>
{
static __forceinline atomic_vint* CreateCounter(T* reference)
{
reflection::DescriptableObject* obj=reference;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if (obj->IsAggregated())
{
if (auto root = obj->GetAggregationRoot())
{
return &root->referenceCounter;
}
}
#endif
return &obj->referenceCounter;
}
static __forceinline void DeleteReference(atomic_vint* counter, void* reference)
{
reflection::DescriptableObject* obj=(T*)reference;
obj->Dispose(false);
}
};
namespace reflection
{
namespace description
{
/***********************************************************************
Exceptions
***********************************************************************/
class TypeDescriptorException abstract : public Exception
{
public:
TypeDescriptorException(const WString& message)
:Exception(message)
{
}
};
class ObjectDisposedException : public TypeDescriptorException
{
public:
ObjectDisposedException()
:TypeDescriptorException(L"The referenced native object has been disposed.")
{
}
};
class ValueNotDisposableException : public TypeDescriptorException
{
public:
ValueNotDisposableException()
:TypeDescriptorException(L"Cannot dispose an object whose reference counter is not 0.")
{
}
};
}
}
}
#endif
/***********************************************************************
.\DESCRIPTABLEVALUE.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_DESCRIPTABLEVALUE
#define VCZH_REFLECTION_DESCRIPTABLEVALUE
namespace vl
{
namespace reflection
{
namespace description
{
class ITypeInfo;
class IMethodGroupInfo;
class IMethodInfo;
class IPropertyInfo;
class IEventInfo;
class IEventHandler;
class IValueFunctionProxy;
}
namespace description
{
/***********************************************************************
Value
***********************************************************************/
enum class PredefinedBoxableType : vint
{
PBT_Unknown = -1,
PBT_S8, PBT_S16, PBT_S32, PBT_S64,
PBT_U8, PBT_U16, PBT_U32, PBT_U64,
PBT_F32, PBT_F64,
PBT_BOOL,
PBT_WCHAR,
PBT_STRING,
PBT_LOCALE,
PBT_DATETIME,
};
class IBoxedValue : public virtual IDescriptable, public Description<IBoxedValue>
{
public:
enum CompareResult
{
Smaller,
Greater,
Equal,
NotComparable,
};
virtual PredefinedBoxableType GetBoxableType() = 0;
virtual Ptr<IBoxedValue> Copy() = 0;
virtual CompareResult ComparePrimitive(Ptr<IBoxedValue> boxedValue) = 0;
};
/// <summary>A type to store all values of reflectable types.</summary>
/// <remarks>
/// To convert between <b>Value</b> and its real C++ type, the following functions are recommended:
/// <ul>
/// <li>[F:vl.reflection.description.BoxValue`1]</li>
/// <li>[F:vl.reflection.description.UnboxValue`1]</li>
/// <li>[F:vl.reflection.description.BoxParameter`1]</li>
/// <li>[F:vl.reflection.description.UnboxParameter`1]</li>
/// </ul>
/// </remarks>
class Value : public Object
{
public:
/// <summary>How the value is stored.</summary>
enum ValueType
{
/// <summary>The value is null.</summary>
Null,
/// <summary>The reference value is stored using a raw pointer.</summary>
RawPtr,
/// <summary>The reference value is stored using a shared pointer.</summary>
SharedPtr,
/// <summary>The value is stored by boxing.</summary>
BoxedValue,
};
protected:
ValueType valueType;
DescriptableObject* rawPtr;
Ptr<DescriptableObject> sharedPtr;
Ptr<IBoxedValue> boxedValue;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
ITypeDescriptor* typeDescriptor;
#endif
Value(DescriptableObject* value);
Value(Ptr<DescriptableObject> value);
Value(Ptr<IBoxedValue> value, ITypeDescriptor* associatedTypeDescriptor);
public:
/// <summary>Create a null value.</summary>
Value();
Value(const Value& value);
Value& operator=(const Value& value);
friend std::partial_ordering operator<=>(const Value& a, const Value& b);
friend bool operator==(const Value& a, const Value& b) { return (a <=> b) == 0; }
/// <summary>Find out how the value is stored.</summary>
/// <returns>Returns How the value is stored.</returns>
ValueType GetValueType()const;
/// <summary>Get the stored raw pointer if <b>GetValueType()</b> returns <b>RawPtr</b> or <b>SharedPtr</b>.</summary>
/// <returns>The stored raw pointer. Returns null if failed.</returns>
DescriptableObject* GetRawPtr()const;
/// <summary>Get the stored shared pointer if <b>GetValueType()</b> returns <b>SharedPtr</b>.</summary>
/// <returns>The stored shared pointer. Returns null if failed.</returns>
Ptr<DescriptableObject> GetSharedPtr()const;
/// <summary>Get the stored value if <b>GetValueType()</b> returns <b>BoxedValue</b>.</summary>
/// <returns>The stored text. Returns empty if failed.</returns>
Ptr<IBoxedValue> GetBoxedValue()const;
/// <summary>Test if this value isnull.</summary>
/// <returns>Returns true if this value is null.</returns>
bool IsNull()const;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
/// <summary>Get the real type of the stored object.</summary>
/// <returns>The real type. Returns null if the value is null.</returns>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
ITypeDescriptor* GetTypeDescriptor()const;
WString GetTypeFriendlyName()const;
bool CanConvertTo(ITypeDescriptor* targetType, ValueType targetValueType)const;
bool CanConvertTo(ITypeInfo* targetType)const;
#endif
/// <summary>Create a value from a raw pointer.</summary>
/// <returns>The created value.</returns>
/// <param name="value">The raw pointer to store.</param>
static Value From(DescriptableObject* value);
/// <summary>Create a value from a shared pointer.</summary>
/// <returns>The created value.</returns>
/// <param name="value">The shared pointer to store.</param>
static Value From(Ptr<DescriptableObject> value);
/// <summary>Create a boxed value.</summary>
/// <returns>The created value.</returns>
/// <param name="value">The boxed value to store.</param>
/// <param name="type">The type of the boxed value.</param>
static Value From(Ptr<IBoxedValue> value, ITypeDescriptor* type);
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
static IMethodInfo* SelectMethod(IMethodGroupInfo* methodGroup, collections::Array<Value>& arguments);
/// <summary>Call the default constructor of the specified type to create a value.</summary>
/// <returns>The created value.</returns>
/// <param name="type">The type to create the value.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
static Value Create(ITypeDescriptor* type);
/// <summary>Call the constructor of the specified type to create a value.</summary>
/// <returns>The created value.</returns>
/// <param name="type">The type to create the value.</param>
/// <param name="arguments">Arguments for the constructor.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// MyClass()
/// :data(L"Hello, world!")
/// {
/// }
///
/// MyClass(const WString& _data)
/// :data(_data)
/// {
/// }
///
/// WString data;
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(const WString&), { L"data" })
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto myClass = Value::Create(GetTypeDescriptor(L"mynamespace::MyClass"), (Value_xs(), WString(L"Hello, world!!!")));
///
/// auto ptrMyClass1 = UnboxValue<Ptr<MyClass>>(myClass);
/// Console::WriteLine(ptrMyClass1->data);
///
/// Ptr<MyClass> ptrMyClass2;
/// UnboxParameter(myClass, ptrMyClass2);
/// Console::WriteLine(ptrMyClass2->data);
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
static Value Create(ITypeDescriptor* type, collections::Array<Value>& arguments);
/// <summary>Call the default constructor of the specified type to create a value.</summary>
/// <returns>The created value.</returns>
/// <param name="typeName">The registered full name for the type to create the value.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
static Value Create(const WString& typeName);
/// <summary>Call the constructor of the specified type to create a value.</summary>
/// <returns>The created value.</returns>
/// <param name="typeName">The registered full name for the type to create the value.</param>
/// <param name="arguments">Arguments for the constructor.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// MyClass()
/// :data(L"Hello, world!")
/// {
/// }
///
/// MyClass(const WString& _data)
/// :data(_data)
/// {
/// }
///
/// WString data;
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(const WString&), { L"data" })
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto myClass = Value::Create(L"mynamespace::MyClass", (Value_xs(), WString(L"Hello, world!!!")));
///
/// auto ptrMyClass1 = UnboxValue<Ptr<MyClass>>(myClass);
/// Console::WriteLine(ptrMyClass1->data);
///
/// Ptr<MyClass> ptrMyClass2;
/// UnboxParameter(myClass, ptrMyClass2);
/// Console::WriteLine(ptrMyClass2->data);
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
static Value Create(const WString& typeName, collections::Array<Value>& arguments);
/// <summary>Call a static method of the specified type.</summary>
/// <returns>The return value from that method.</returns>
/// <param name="typeName">The registered full name for the type.</param>
/// <param name="name">The registered name for the method.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
static Value InvokeStatic(const WString& typeName, const WString& name);
/// <summary>Call a static method of the specified type.</summary>
/// <returns>The return value from that method.</returns>
/// <param name="typeName">The registered full name for the type.</param>
/// <param name="name">The registered name for the method.</param>
/// <param name="arguments">Arguments for the method.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// static void PrintHelloWorld(const WString& name)
/// {
/// Console::WriteLine(L"Hello, " + name + L"!");
/// }
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_STATIC_METHOD(PrintHelloWorld, { L"name" })
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// Value::InvokeStatic(L"mynamespace::MyClass", L"PrintHelloWorld", (Value_xs(), WString(L"Gaclib")));
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
static Value InvokeStatic(const WString& typeName, const WString& name, collections::Array<Value>& arguments);
/// <summary>Call the getter function for a property.</summary>
/// <returns>The value of the property.</returns>
/// <param name="name">The registered name for the property.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// private:
/// WString prop;
/// public:
/// WString field;
///
/// WString GetProp() { return prop; };
/// void SetProp(const WString& value) { prop = value; }
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_FIELD(field)
/// CLASS_MEMBER_PROPERTY_FAST(Prop)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
/// auto myClass = Value::Create(td);
///
/// myClass.SetProperty(L"field", BoxValue<WString>(L"Hello, world!"));
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Hello, Gaclib!"));
///
/// Console::WriteLine(UnboxValue<WString>(myClass.GetProperty(L"field")));
/// Console::WriteLine(UnboxValue<WString>(myClass.GetProperty(L"Prop")));
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
Value GetProperty(const WString& name)const;
/// <summary>Call the setter function for a property.</summary>
/// <param name="name">The registered name for the property.</param>
/// <param name="newValue">The value to set the property.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// private:
/// WString prop;
/// public:
/// WString field;
///
/// WString GetProp() { return prop; };
/// void SetProp(const WString& value) { prop = value; }
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_FIELD(field)
/// CLASS_MEMBER_PROPERTY_FAST(Prop)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
/// auto myClass = Value::Create(td);
///
/// myClass.SetProperty(L"field", BoxValue<WString>(L"Hello, world!"));
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Hello, Gaclib!"));
///
/// Console::WriteLine(UnboxValue<WString>(myClass.GetProperty(L"field")));
/// Console::WriteLine(UnboxValue<WString>(myClass.GetProperty(L"Prop")));
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
void SetProperty(const WString& name, const Value& newValue);
/// <summary>Call a non-static method.</summary>
/// <returns>The return value from that method.</returns>
/// <param name="name">The registered name for the method.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
Value Invoke(const WString& name)const;
/// <summary>Call a non-static method.</summary>
/// <returns>The return value from that method.</returns>
/// <param name="name">The registered name for the method.</param>
/// <param name="arguments">Arguments for the method.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// void PrintHelloWorld(const WString& name)
/// {
/// Console::WriteLine(L"Hello, " + name + L"!");
/// }
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_METHOD(PrintHelloWorld, { L"name" })
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
/// auto myClass = Value::Create(td);
/// myClass.Invoke(L"PrintHelloWorld", (Value_xs(), WString(L"Gaclib")));
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
Value Invoke(const WString& name, collections::Array<Value>& arguments)const;
/// <summary>Attach a callback function for the event.</summary>
/// <returns>The event handler for this attachment. You need to keep it to detach the callback function.</returns>
/// <param name="name">The registered name for the event.</param>
/// <param name="function">The callback function.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// private:
/// WString prop;
/// public:
/// Event<void(const WString&, const WString&)> PropChanged;
///
/// WString GetProp()
/// {
/// return prop;
/// }
///
/// void SetProp(const WString& value)
/// {
/// if (prop != value)
/// {
/// auto old = prop;
/// prop = value;
/// PropChanged(old, prop);
/// }
/// }
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_EVENT(PropChanged)
/// CLASS_MEMBER_PROPERTY_EVENT_FAST(Prop, PropChanged)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
/// auto myClass = Value::Create(td);
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Zero"));
///
/// using CallbackType = Func<void(const WString&, const WString&)>;
/// CallbackType callbackFunction = [](const WString& oldProp, const WString& newProp)
/// {
/// Console::WriteLine(L"myClass.Prop changed: " + oldProp + L" -> " + newProp);
/// };
/// auto handler = myClass.AttachEvent(L"PropChanged", BoxParameter(callbackFunction));
///
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"One"));
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Two"));
/// myClass.DetachEvent(L"PropChanged", handler);
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Three"));
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
Ptr<IEventHandler> AttachEvent(const WString& name, const Value& function)const;
/// <summary>Detach a callback function from the event.</summary>
/// <returns>Returns true if this operation succeeded.</returns>
/// <param name="name">The registered name for the event.</param>
/// <param name="handler">The event handler returned from <see cref="AttachEvent"/>.</param>
/// <remarks>
/// <p>Only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is <b>off</b>.</p>
/// </remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// private:
/// WString prop;
/// public:
/// Event<void(const WString&, const WString&)> PropChanged;
///
/// WString GetProp()
/// {
/// return prop;
/// }
///
/// void SetProp(const WString& value)
/// {
/// if (prop != value)
/// {
/// auto old = prop;
/// prop = value;
/// PropChanged(old, prop);
/// }
/// }
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_EVENT(PropChanged)
/// CLASS_MEMBER_PROPERTY_EVENT_FAST(Prop, PropChanged)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto td = GetTypeDescriptor(L"mynamespace::MyClass");
/// auto myClass = Value::Create(td);
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Zero"));
///
/// using CallbackType = Func<void(const WString&, const WString&)>;
/// CallbackType callbackFunction = [](const WString& oldProp, const WString& newProp)
/// {
/// Console::WriteLine(L"myClass.Prop changed: " + oldProp + L" -> " + newProp);
/// };
/// auto handler = myClass.AttachEvent(L"PropChanged", BoxParameter(callbackFunction));
///
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"One"));
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Two"));
/// myClass.DetachEvent(L"PropChanged", handler);
/// myClass.SetProperty(L"Prop", BoxValue<WString>(L"Three"));
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
bool DetachEvent(const WString& name, Ptr<IEventHandler> handler)const;
#endif
/// <summary>Dispose the object if <b>GetValueType()</b> returns <b>RawPtr</b>.</summary>
/// <returns>
/// Returns true if the object is disposed.
/// Returns false if the object cannot be disposed.
/// An exception will be thrown if the reference counter is not 0.
///</returns>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class SharedClass : public Object, public Description<SharedClass>
/// {
/// public:
/// SharedClass()
/// {
/// Console::WriteLine(L"SharedClass::SharedClass()");
/// }
///
/// ~SharedClass()
/// {
/// Console::WriteLine(L"SharedClass::~SharedClass()");
/// }
/// };
///
/// class RawClass : public Object, public Description<RawClass>
/// {
/// public:
/// RawClass()
/// {
/// Console::WriteLine(L"RawClass::RawClass()");
/// }
///
/// ~RawClass()
/// {
/// Console::WriteLine(L"RawClass::~RawClass()");
/// }
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::SharedClass)\
/// F(mynamespace::RawClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(SharedClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<SharedClass>(), NO_PARAMETER)
/// END_CLASS_MEMBER(SharedClass)
///
/// BEGIN_CLASS_MEMBER(RawClass)
/// CLASS_MEMBER_CONSTRUCTOR(RawClass*(), NO_PARAMETER)
/// END_CLASS_MEMBER(RawClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// auto sharedClass = Value::Create(L"mynamespace::SharedClass");
/// auto rawClass = Value::Create(L"mynamespace::RawClass");
///
/// Console::WriteLine(L"sharedClass is " + WString(sharedClass.GetValueType() == Value::SharedPtr ? L"SharedPtr" : L"RawPtr"));
/// Console::WriteLine(L"rawClass is " + WString(rawClass.GetValueType() == Value::SharedPtr ? L"SharedPtr" : L"RawPtr"));
///
/// rawClass.DeleteRawPtr();
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
bool DeleteRawPtr();
};
}
}
}
#endif
/***********************************************************************
.\DESCRIPTABLEINTERFACES.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_DESCRIPTABLEINTERFACES
#define VCZH_REFLECTION_DESCRIPTABLEINTERFACES
namespace vl
{
namespace reflection
{
namespace description
{
class IValueReadonlyList;
template<typename T>
struct TypedValueSerializerProvider;
}
namespace description
{
/***********************************************************************
ValueType
***********************************************************************/
namespace pbt_selector
{
template<PredefinedBoxableType _Value>
struct SelectorBase { static constexpr PredefinedBoxableType Value = _Value; };
template<typename T> struct Selector : SelectorBase<PredefinedBoxableType::PBT_Unknown> {};
template<> struct Selector<vint8_t> : SelectorBase<PredefinedBoxableType::PBT_S8> {};
template<> struct Selector<vint16_t> : SelectorBase<PredefinedBoxableType::PBT_S16> {};
template<> struct Selector<vint32_t> : SelectorBase<PredefinedBoxableType::PBT_S32> {};
template<> struct Selector<vint64_t> : SelectorBase<PredefinedBoxableType::PBT_S64> {};
template<> struct Selector<vuint8_t> : SelectorBase<PredefinedBoxableType::PBT_U8> {};
template<> struct Selector<vuint16_t> : SelectorBase<PredefinedBoxableType::PBT_U16> {};
template<> struct Selector<vuint32_t> : SelectorBase<PredefinedBoxableType::PBT_U32> {};
template<> struct Selector<vuint64_t> : SelectorBase<PredefinedBoxableType::PBT_U64> {};
template<> struct Selector<float> : SelectorBase<PredefinedBoxableType::PBT_F32> {};
template<> struct Selector<double> : SelectorBase<PredefinedBoxableType::PBT_F64> {};
template<> struct Selector<bool> : SelectorBase<PredefinedBoxableType::PBT_BOOL> {};
template<> struct Selector<wchar_t> : SelectorBase<PredefinedBoxableType::PBT_WCHAR> {};
template<> struct Selector<WString> : SelectorBase<PredefinedBoxableType::PBT_STRING> {};
template<> struct Selector<Locale> : SelectorBase<PredefinedBoxableType::PBT_LOCALE> {};
template<> struct Selector<DateTime> : SelectorBase<PredefinedBoxableType::PBT_DATETIME> {};
}
class IValueType : public virtual IDescriptable, public Description<IValueType>
{
public:
template<typename T>
class TypedBox : public IBoxedValue
{
public:
T value;
TypedBox()
:value{}
{
}
TypedBox(const T& _value)
:value(_value)
{
}
PredefinedBoxableType GetBoxableType()override
{
return pbt_selector::Selector<T>::Value;
}
Ptr<IBoxedValue> Copy()override
{
return Ptr(new TypedBox<T>(value));
}
CompareResult ComparePrimitive(Ptr<IBoxedValue> boxedValue)override
{
if (auto typedBox = boxedValue.Cast<TypedBox<T>>())
{
auto r = value <=> typedBox->value;
if constexpr (std::is_same_v<decltype(r), std::partial_ordering>)
{
if (r == std::partial_ordering::unordered) return IBoxedValue::NotComparable;
}
if (r < 0) return IBoxedValue::Smaller;
if (r > 0) return IBoxedValue::Greater;
return IBoxedValue::Equal;
}
return IBoxedValue::NotComparable;
}
};
virtual Value CreateDefault() = 0;
};
class IEnumType : public virtual IDescriptable, public Description<IEnumType>
{
public:
virtual bool IsFlagEnum() = 0;
virtual vint GetItemCount() = 0;
virtual WString GetItemName(vint index) = 0;
virtual vuint64_t GetItemValue(vint index) = 0;
virtual vint IndexOfItem(WString name) = 0;
virtual Value ToEnum(vuint64_t value) = 0;
virtual vuint64_t FromEnum(const Value& value) = 0;
};
class ISerializableType : public virtual IDescriptable, public Description<ISerializableType>
{
public:
virtual bool Serialize(const Value& input, WString& output) = 0;
virtual bool Deserialize(const WString& input, Value& output) = 0;
};
/***********************************************************************
ITypeDescriptor (type)
***********************************************************************/
enum class TypeInfoHint
{
Normal,
LazyList,
Array,
List,
SortedList,
ObservableList,
Dictionary,
NativeCollectionReference,
};
class ITypeInfo : public virtual IDescriptable, public Description<ITypeInfo>
{
public:
enum Decorator
{
RawPtr,
SharedPtr,
Nullable,
TypeDescriptor,
Generic,
};
virtual Decorator GetDecorator() = 0;
virtual TypeInfoHint GetHint() = 0;
virtual ITypeInfo* GetElementType() = 0;
virtual ITypeDescriptor* GetTypeDescriptor() = 0;
virtual vint GetGenericArgumentCount() = 0;
virtual ITypeInfo* GetGenericArgument(vint index) = 0;
virtual WString GetTypeFriendlyName() = 0;
};
/***********************************************************************
ITypeDescriptor (basic)
***********************************************************************/
class IMemberInfo : public virtual IDescriptable, public Description<IMemberInfo>
{
public:
virtual ITypeDescriptor* GetOwnerTypeDescriptor()=0;
virtual const WString& GetName()=0;
};
/***********************************************************************
ITypeDescriptor (event)
***********************************************************************/
class IEventHandler : public virtual IDescriptable, public Description<IEventHandler>
{
public:
virtual bool IsAttached()=0;
};
class IEventInfo : public virtual IMemberInfo, public Description<IEventInfo>
{
public:
class ICpp : public virtual IDescriptable, public Description<ICpp>
{
public:
/*
Arguments:
$Name: Event name
$This: Expression for the "this" argument
$Handler: Event handler function / Event handler object
$Arguments: Expressions for arguments separated by ", "
Default (for Vlpp Event):
Attach: ::vl::__vwsn::EventAttach($This->$Name, $Handler)
Detach: ::vl::__vwsn::EventDetach($This->$Name, $Handler)
Invoke: ::vl::__vwsn::EventInvoke($This->$Name)($Arguments)
GetInvokeTemplate() == L"*":
This event does not exist in C++
*/
virtual const WString& GetAttachTemplate() = 0;
virtual const WString& GetDetachTemplate() = 0;
virtual const WString& GetInvokeTemplate() = 0;
};
/*
Priority:
1. Use ICpp
2. Use Default
*/
virtual ICpp* GetCpp() = 0;
virtual ITypeInfo* GetHandlerType()=0;
virtual vint GetObservingPropertyCount()=0;
virtual IPropertyInfo* GetObservingProperty(vint index)=0;
virtual Ptr<IEventHandler> Attach(const Value& thisObject, Ptr<IValueFunctionProxy> handler)=0;
virtual bool Detach(const Value& thisObject, Ptr<IEventHandler> handler)=0;
virtual void Invoke(const Value& thisObject, Ptr<IValueReadonlyList> arguments)=0;
};
/***********************************************************************
ITypeDescriptor (property)
***********************************************************************/
class IPropertyInfo : public virtual IMemberInfo, public Description<IPropertyInfo>
{
public:
class ICpp : public virtual IDescriptable, public Description<ICpp>
{
public:
/*
Arguments:
$Type: C++ full type name
$Name: Property name
$This: Expression for the "this" argument
Default:
Struct: $This.$Name
Class: $This->$Name
Example:
Token in syntax tree: $This->$Name.value
GetReferenceTemplate() == L"*":
This property does not exist in C++
*/
virtual const WString& GetReferenceTemplate() = 0;
};
/*
Priority:
1. Use ICpp
2. Use ICpp from getter and setter
3. Use default
*/
virtual ICpp* GetCpp() = 0;
virtual bool IsReadable()=0;
virtual bool IsWritable()=0;
virtual ITypeInfo* GetReturn()=0;
virtual IMethodInfo* GetGetter()=0;
virtual IMethodInfo* GetSetter()=0;
virtual IEventInfo* GetValueChangedEvent()=0;
virtual Value GetValue(const Value& thisObject)=0;
virtual void SetValue(Value& thisObject, const Value& newValue)=0;
};
/***********************************************************************
ITypeDescriptor (method)
***********************************************************************/
class IParameterInfo : public virtual IMemberInfo, public Description<IParameterInfo>
{
public:
virtual ITypeInfo* GetType()=0;
virtual IMethodInfo* GetOwnerMethod()=0;
};
class IMethodInfo : public virtual IMemberInfo, public Description<IMethodInfo>
{
public:
class ICpp : public virtual IDescriptable, public Description<ICpp>
{
public:
/*
Arguments:
$Type: C++ full type name
$Func: C++ function type (e.g. void(int)), object type not included for method
$Name: Method name
$This: Expression for the "this" argument;
$Arguments: Expressions for arguments separated by ", "
Default:
Constructor: new $Type($Arguments)
Static: $Type::$Name($Arguments)
Normal: $This->$Name($Arguments)
Example:
External constructor: <full-function-name>($Arguments)
External method: <full-function-name>($This, $Arguments)
Renamed method: $This-><function-name>($Arguments)
GetInvokeTemplate() == L"*":
This method does not exist in C++
*/
virtual const WString& GetInvokeTemplate() = 0;
virtual const WString& GetClosureTemplate() = 0;
};
/*
Priority:
1. Use ICpp
2. Use default
*/
virtual ICpp* GetCpp() = 0;
virtual IMethodGroupInfo* GetOwnerMethodGroup()=0;
virtual IPropertyInfo* GetOwnerProperty()=0;
virtual vint GetParameterCount()=0;
virtual IParameterInfo* GetParameter(vint index)=0;
virtual ITypeInfo* GetReturn()=0;
virtual bool IsStatic()=0;
virtual void CheckArguments(collections::Array<Value>& arguments)=0;
virtual Value Invoke(const Value& thisObject, collections::Array<Value>& arguments)=0;
virtual Value CreateFunctionProxy(const Value& thisObject) = 0;
};
class IMethodGroupInfo : public virtual IMemberInfo, public Description<IMethodGroupInfo>
{
public:
virtual vint GetMethodCount()=0;
virtual IMethodInfo* GetMethod(vint index)=0;
};
/***********************************************************************
ITypeDescriptor
***********************************************************************/
enum class TypeDescriptorFlags : vint
{
Undefined = 0,
Object = 1<<0,
IDescriptable = 1<<1,
Class = 1<<2,
Interface = 1<<3,
Primitive = 1<<4,
Struct = 1<<5,
FlagEnum = 1<<6,
NormalEnum = 1<<7,
ClassType = Object | Class,
InterfaceType = IDescriptable | Interface,
ReferenceType = ClassType | InterfaceType,
EnumType = FlagEnum | NormalEnum,
StructType = Primitive | Struct,
};
inline TypeDescriptorFlags operator&(TypeDescriptorFlags a, TypeDescriptorFlags b)
{
return (TypeDescriptorFlags)((vint)a & (vint)b);
}
inline TypeDescriptorFlags operator|(TypeDescriptorFlags a, TypeDescriptorFlags b)
{
return (TypeDescriptorFlags)((vint)a | (vint)b);
}
/// <summary>Metadata class for reflectable types.</summary>
class ITypeDescriptor : public virtual IDescriptable, public Description<ITypeDescriptor>
{
public:
class ICpp : public virtual IDescriptable, public Description<ICpp>
{
public:
/*
Default: refer to TypeInfoContent::VlppType
GetFullName() == L"*":
This type does not exist in C++
*/
virtual const WString& GetFullName() = 0;
};
/*
Priority:
1. Use ICpp
2. Use default
*/
virtual ICpp* GetCpp() = 0;
virtual TypeDescriptorFlags GetTypeDescriptorFlags() = 0;
virtual bool IsAggregatable() = 0;
virtual const WString& GetTypeName() = 0;
virtual IValueType* GetValueType() = 0;
virtual IEnumType* GetEnumType() = 0;
virtual ISerializableType* GetSerializableType() = 0;
virtual vint GetBaseTypeDescriptorCount() = 0;
virtual ITypeDescriptor* GetBaseTypeDescriptor(vint index) = 0;
virtual bool CanConvertTo(ITypeDescriptor* targetType) = 0;
virtual vint GetPropertyCount() = 0;
virtual IPropertyInfo* GetProperty(vint index) = 0;
virtual bool IsPropertyExists(const WString& name, bool inheritable) = 0;
virtual IPropertyInfo* GetPropertyByName(const WString& name, bool inheritable) = 0;
virtual vint GetEventCount() = 0;
virtual IEventInfo* GetEvent(vint index) = 0;
virtual bool IsEventExists(const WString& name, bool inheritable) = 0;
virtual IEventInfo* GetEventByName(const WString& name, bool inheritable) = 0;
virtual vint GetMethodGroupCount() = 0;
virtual IMethodGroupInfo* GetMethodGroup(vint index) = 0;
virtual bool IsMethodGroupExists(const WString& name, bool inheritable) = 0;
virtual IMethodGroupInfo* GetMethodGroupByName(const WString& name, bool inheritable) = 0;
virtual IMethodGroupInfo* GetConstructorGroup() = 0;
};
#ifndef VCZH_DEBUG_NO_REFLECTION
/***********************************************************************
ITypeManager
***********************************************************************/
class ITypeManager;
/// <summary>Delay loading for registering reflectable types.</summary>
class ITypeLoader : public virtual Interface
{
public:
/// <summary>Called when it is time to register types.</summary>
/// <param name="manager">The type manager.</param>
virtual void Load(ITypeManager* manager)=0;
/// <summary>Called when it is time to unregister types.</summary>
/// <param name="manager">The type manager.</param>
/// <remarks>
/// Types cannot be unregistered one by one,
/// they are removed at the same time by calling
/// [F:vl.reflection.description.DestroyGlobalTypeManager] or
/// [F:vl.reflection.description.ResetGlobalTypeManager].
/// Here is just a chance for reverse extra steps, when these steps are taken in <see cref="Load"/>.
/// </remarks>
virtual void Unload(ITypeManager* manager)=0;
};
/// <summary>A type manager to access all reflectable types.</summary>
class ITypeManager : public virtual Interface
{
public:
/// <summary>Get the number of all registered types.</summary>
/// <returns>The number of all registered types.</returns>
virtual vint GetTypeDescriptorCount()=0;
/// <summary>Get one registered type.</summary>
/// <returns>A registered type specified by the index.</returns>
/// <param name="index">The index for retriving the registered type.</param>
/// <remarks>
/// The index itself does not has any specific meaning.
/// And it is no guarantee that an index will always return the same type for each execution of the same process.
/// </remarks>
virtual ITypeDescriptor* GetTypeDescriptor(vint index)=0;
virtual ITypeDescriptor* GetTypeDescriptor(const WString& name)=0;
virtual bool SetTypeDescriptor(const WString& name, Ptr<ITypeDescriptor> typeDescriptor)=0;
/// <summary>Delay register some types.</summary>
/// <returns>Returns true if this operation succeeded.</returns>
/// <param name="typeLoader">A type loader for delay registering.</param>
/// <remarks>
/// You can still call this function after <see cref="Load"/> is called.
/// In this case, there is no delay registering, all types in this loader will be registered immediately.
/// </remarks>
virtual bool AddTypeLoader(Ptr<ITypeLoader> typeLoader)=0;
virtual bool RemoveTypeLoader(Ptr<ITypeLoader> typeLoader)=0;
/// <summary>Load all added type loaders.</summary>
/// <returns>Returns true if this operation succeeded.</returns>
virtual bool Load()=0;
virtual bool Unload()=0;
virtual bool Reload()=0;
virtual bool IsLoaded()=0;
virtual ITypeDescriptor* GetRootType()=0;
virtual vint GetTypeVersion()=0;
};
/// <summary>Get the type manager.</summary>
/// <returns>Returns the type manager.</returns>
extern ITypeManager* GetGlobalTypeManager();
/// <summary>Unload all types and free the type manager.</summary>
/// <returns>Returns true if this operation succeeded.</returns>
/// <remarks>
/// After calling this function, you can no longer register new types,
/// and calling <see cref="GetGlobalTypeManager"/> will always get null.
/// </remarks>
extern bool DestroyGlobalTypeManager();
/// <summary>Unload all types and reset the type manager.</summary>
/// <returns>Returns true if this operation succeeded.</returns>
/// <remarks>
/// <p>
/// This function is similar to <see cref="DestroyGlobalTypeManager"/>,
/// but calling this function allows types to be registsred again.
/// </p>
/// <p>
/// This function is very useful for unit testing.
/// In each test case, you can first register all types,
/// and after the test case is finished, call this function to reset all types.
/// You can do this again and again in the other test cases,
/// so that these test cases don't affect each other.
/// </p>
/// </remarks>
extern bool ResetGlobalTypeManager();
/// <summary>Get a registered type given the registered name.</summary>
/// <returns>Returns the metadata class for this registered type.</returns>
/// <param name="name">
/// The registered name.
/// Note that this is not the full name of the C++ type,
/// it is the name what is used to registere this type.</param>
/// <remarks>
/// Returning null means the type registration is declared but the type manager has not started.
/// </remarks>
extern ITypeDescriptor* GetTypeDescriptor(const WString& name);
extern bool IsInterfaceType(ITypeDescriptor* typeDescriptor, bool& acceptProxy);
extern void LogTypeManager(stream::TextWriter& writer);
extern void GenerateMetaonlyTypes(stream::IStream& outputStream);
extern Ptr<ITypeLoader> LoadMetaonlyTypes(stream::IStream& inputStream, const collections::Dictionary<WString, Ptr<ISerializableType>>& serializableTypes);
/***********************************************************************
Cpp Helper Functions
***********************************************************************/
extern WString CppGetFullName(ITypeDescriptor* type);
extern WString CppGetReferenceTemplate(IPropertyInfo* prop);
extern WString CppGetClosureTemplate(IMethodInfo* method);
extern WString CppGetInvokeTemplate(IMethodInfo* method);
extern WString CppGetAttachTemplate(IEventInfo* ev);
extern WString CppGetDetachTemplate(IEventInfo* ev);
extern WString CppGetInvokeTemplate(IEventInfo* ev);
extern bool CppExists(ITypeDescriptor* type);
extern bool CppExists(IPropertyInfo* prop);
extern bool CppExists(IMethodInfo* method);
extern bool CppExists(IEventInfo* ev);
#endif
/***********************************************************************
Exceptions
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
class TypeNotExistsException : public TypeDescriptorException
{
public:
TypeNotExistsException(const WString& name)
:TypeDescriptorException(L"Cannot find the type \""+name+L"\".")
{
}
};
class ConstructorNotExistsException : public TypeDescriptorException
{
public:
ConstructorNotExistsException(ITypeDescriptor* type)
:TypeDescriptorException(L"Cannot find any constructor in type \"" + type->GetTypeName() + L"\".")
{
}
};
class MemberNotExistsException : public TypeDescriptorException
{
public:
MemberNotExistsException(const WString& name, ITypeDescriptor* type)
:TypeDescriptorException(L"Cannot find the member \"" + name + L"\" in type \"" + type->GetTypeName() + L"\".")
{
}
};
class PropertyIsNotReadableException : public TypeDescriptorException
{
public:
PropertyIsNotReadableException(IPropertyInfo* propertyInfo)
:TypeDescriptorException(L"Cannot read value from a property \"" + propertyInfo->GetName() + L"\" that is not readable in type \"" + propertyInfo->GetOwnerTypeDescriptor()->GetTypeName() + L"\".")
{
}
};
class PropertyIsNotWritableException : public TypeDescriptorException
{
public:
PropertyIsNotWritableException(IPropertyInfo* propertyInfo)
:TypeDescriptorException(L"Cannot write value to a property \"" + propertyInfo->GetName() + L"\" that is not writable in type \"" + propertyInfo->GetOwnerTypeDescriptor()->GetTypeName() + L"\".")
{
}
};
class ArgumentNullException : public TypeDescriptorException
{
public:
ArgumentNullException(const WString& name, const WString& member)
:TypeDescriptorException(L"Argument \"" + name + L"\" cannot be null when accessing its member \"" + member + L"\".")
{
}
ArgumentNullException(const WString& name, IMethodInfo* target)
:TypeDescriptorException(L"Argument \"" + name + L"\" cannot be null when invoking method \"" + target->GetName() + L"\" in type \"" + target->GetOwnerTypeDescriptor()->GetTypeName() + L"\".")
{
}
ArgumentNullException(const WString& name, IEventInfo* target)
:TypeDescriptorException(L"Argument \"" + name + L"\" cannot be null when accessing event \"" + target->GetName() + L"\" in type \"" + target->GetOwnerTypeDescriptor()->GetTypeName() + L"\".")
{
}
ArgumentNullException(const WString& name, IPropertyInfo* target)
:TypeDescriptorException(L"Argument \"" + name + L"\" cannot be null when invoking property \"" + target->GetName() + L"\" in type \"" + target->GetOwnerTypeDescriptor()->GetTypeName() + L"\".")
{
}
};
class ArgumentTypeMismtatchException : public TypeDescriptorException
{
public:
ArgumentTypeMismtatchException(const WString& name, ITypeDescriptor* expected, ITypeDescriptor* actual)
:TypeDescriptorException(L"Argument \"" + name + L"\" cannot convert from \"" + actual->GetTypeName() + L"\" to \"" + expected->GetTypeName() + L"\".")
{
}
ArgumentTypeMismtatchException(const WString& name, ITypeInfo* expected, const Value& actual)
:TypeDescriptorException(L"Argument \"" + name + L"\" cannot convert from \"" + actual.GetTypeFriendlyName() + L"\" to \"" + expected->GetTypeFriendlyName() + L"\".")
{
}
ArgumentTypeMismtatchException(const WString& name, ITypeDescriptor* type, Value::ValueType valueType, const Value& actual)
:TypeDescriptorException(L"Argument \"" + name + L"\" cannot convert from \"" + actual.GetTypeFriendlyName() + L"\" to \"" +
(valueType == Value::SharedPtr ? L"Ptr<" : L"") + type->GetTypeName() + (valueType == Value::SharedPtr ? L">" : valueType == Value::RawPtr ? L"*" : L"")
+ L"\".")
{
}
};
class ArgumentCountMismtatchException : public TypeDescriptorException
{
public:
ArgumentCountMismtatchException()
:TypeDescriptorException(L"Argument count does not match the definition.")
{
}
ArgumentCountMismtatchException(IMethodGroupInfo* target)
:TypeDescriptorException(L"Argument count does not match the definition when invoking method \"" + target->GetName() + L"\" in type \"" + target->GetOwnerTypeDescriptor()->GetTypeName() + L"\".")
{
}
};
#endif
}
}
}
#endif
/***********************************************************************
.\PREDEFINED\OBSERVABLELIST.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_TYPES_OBSERVABLELIST
#define VCZH_REFLECTION_TYPES_OBSERVABLELIST
namespace vl
{
namespace collections
{
/// <summary>Base type of observable container which triggers callbacks whenever items are changed.</summary>
/// <typeparam name="T">Type of elements.</typeparam>
/// <remarks>
/// <p>Methods are the same to <see cref="List`2"/>, except that operator[] is readonly.</p>
/// <p>
/// When an item is being inserted to the list,
/// <b>QueryInsert</b> will be called to determine if this item can be inserted,
/// <b>BeforeInsert</b> will be called before inserting,
/// <b>AfterInsert</b> will be called after inserting.
/// </p>
/// <p>
/// When an item is being removed from the list,
/// <b>QueryRemove</b> will be called to determine if this item can be removed,
/// <b>BeforeRemove</b> will be called before removing,
/// <b>AfterRemove</b> will be called after removing.
/// </p>
/// <p>
/// When an item is being replaced, it is considered as removing the original item and inserting the new item.
/// </p>
/// <p>
/// After any changing happens, <b>NotifyUpdateInternal</b> is called.
/// Arguments is exactly the same as <see cref="reflection::description::IValueObservableList::ItemChanged"/>.
/// </p>
/// </remarks>
template<typename T>
class ObservableListBase : public collections::EnumerableBase<T>
{
using K = typename KeyType<T>::Type;
protected:
collections::List<T> items;
virtual void NotifyUpdateInternal(vint start, vint count, vint newCount)
{
}
virtual bool QueryInsert(vint index, const T& value)
{
return true;
}
virtual void BeforeInsert(vint index, const T& value)
{
}
virtual void AfterInsert(vint index, const T& value)
{
}
virtual bool QueryRemove(vint index, const T& value)
{
return true;
}
virtual void BeforeRemove(vint index, const T& value)
{
}
virtual void AfterRemove(vint index, vint count)
{
}
public:
collections::IEnumerator<T>* CreateEnumerator()const
{
return items.CreateEnumerator();
}
/// <summary>Trigger <b>NotifyUpdateInternal</b> manually.</summary>
/// <returns>Returns true if arguments are not out of range.</returns>
/// <param name="start">The index of the first item that are changed.</param>
/// <param name="count">The number of items that are changed, the default value is 1.</param>
/// <remarks>
/// <p>
/// This is useful when the container is not actually changed, but data in some items are changed.
/// For example, in an observable list of shared pointers,
/// properties of elements are changed does not trigger callbacks because it doesn't change pointers in the list.
/// </p>
/// <p>
/// If subscribers need to know about such change, calling this function is an easy way to do it.
/// </p>
/// </remarks>
bool NotifyUpdate(vint start, vint count = 1)
{
if (start<0 || start >= items.Count() || count <= 0 || start + count>items.Count())
{
return false;
}
else
{
NotifyUpdateInternal(start, count, count);
return true;
}
}
bool Contains(const K& item)const
{
return items.Contains(item);
}
vint Count()const
{
return items.Count();
}
vint Count()
{
return items.Count();
}
const T& Get(vint index)const
{
return items.Get(index);
}
const T& operator[](vint index)const
{
return items.Get(index);
}
vint IndexOf(const K& item)const
{
return items.IndexOf(item);
}
vint Add(const T& item)
{
return Insert(items.Count(), item);
}
bool Remove(const K& item)
{
vint index = items.IndexOf(item);
if (index == -1) return false;
return RemoveAt(index);
}
bool RemoveAt(vint index)
{
if (0 <= index && index < items.Count() && QueryRemove(index, items[index]))
{
BeforeRemove(index, items[index]);
T item = items[index];
items.RemoveAt(index);
AfterRemove(index, 1);
NotifyUpdateInternal(index, 1, 0);
return true;
}
return false;
}
bool RemoveRange(vint index, vint count)
{
if (count <= 0) return false;
if (0 <= index && index<items.Count() && index + count <= items.Count())
{
for (vint i = 0; i < count; i++)
{
if (!QueryRemove(index + 1, items[index + i])) return false;
}
for (vint i = 0; i < count; i++)
{
BeforeRemove(index + i, items[index + i]);
}
items.RemoveRange(index, count);
AfterRemove(index, count);
NotifyUpdateInternal(index, count, 0);
return true;
}
return false;
}
bool Clear()
{
vint count = items.Count();
for (vint i = 0; i < count; i++)
{
if (!QueryRemove(i, items[i])) return false;
}
for (vint i = 0; i < count; i++)
{
BeforeRemove(i, items[i]);
}
items.Clear();
AfterRemove(0, count);
NotifyUpdateInternal(0, count, 0);
return true;
}
vint Insert(vint index, const T& item)
{
if (0 <= index && index <= items.Count() && QueryInsert(index, item))
{
BeforeInsert(index, item);
items.Insert(index, item);
AfterInsert(index, item);
NotifyUpdateInternal(index, 0, 1);
return index;
}
else
{
return -1;
}
}
bool Set(vint index, const T& item)
{
if (0 <= index && index < items.Count())
{
if (QueryRemove(index, items[index]) && QueryInsert(index, item))
{
BeforeRemove(index, items[index]);
items.RemoveAt(index);
AfterRemove(index, 1);
BeforeInsert(index, item);
items.Insert(index, item);
AfterInsert(index, item);
NotifyUpdateInternal(index, 1, 1);
return true;
}
}
return false;
}
};
/// <summary>An observable container that maintain an implementation of <see cref="reflection::description::IValueObservableList"/>.</summary>
/// <typeparam name="T">Type of elements.</typeparam>
template<typename T>
class ObservableList : public ObservableListBase<T>
{
protected:
void NotifyUpdateInternal(vint start, vint count, vint newCount) override;
public:
};
namespace randomaccess_internal
{
template<typename T>
struct RandomAccessable<ObservableListBase<T>>
{
static const bool CanRead = true;
static const bool CanResize = false;
};
template<typename T>
struct RandomAccessable<ObservableList<T>>
{
static const bool CanRead = true;
static const bool CanResize = false;
};
}
}
}
#endif
/***********************************************************************
.\PREDEFINED\TYPEDVALUESERIALIZERPROVIDER.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_TYPES_TYPEDVALUESERIALIZERPROVIDER
#define VCZH_REFLECTION_TYPES_TYPEDVALUESERIALIZERPROVIDER
#include <limits.h>
#include <float.h>
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
Constants
***********************************************************************/
template<typename T>
struct TypedValueSerializerMinMax;
template<>
struct TypedValueSerializerMinMax<vint8_t>
{
static constexpr vint8_t Min = _I8_MIN;
static constexpr vint8_t Max = _I8_MAX;
};
template<>
struct TypedValueSerializerMinMax<vint16_t>
{
static constexpr vint16_t Min = _I16_MIN;
static constexpr vint16_t Max = _I16_MAX;
};
template<>
struct TypedValueSerializerMinMax<vint32_t>
{
static constexpr vint32_t Min = _I32_MIN;
static constexpr vint32_t Max = _I32_MAX;
};
template<>
struct TypedValueSerializerMinMax<vint64_t>
{
static constexpr vint64_t Min = _I64_MIN;
static constexpr vint64_t Max = _I64_MAX;
};
template<>
struct TypedValueSerializerMinMax<vuint8_t>
{
static constexpr vuint8_t Min = 0;
static constexpr vuint8_t Max = _UI8_MAX;
};
template<>
struct TypedValueSerializerMinMax<vuint16_t>
{
static constexpr vuint16_t Min = 0;
static constexpr vuint16_t Max = _UI16_MAX;
};
template<>
struct TypedValueSerializerMinMax<vuint32_t>
{
static constexpr vuint32_t Min = 0;
static constexpr vuint32_t Max = _UI32_MAX;
};
template<>
struct TypedValueSerializerMinMax<vuint64_t>
{
static constexpr vuint64_t Min = 0;
static constexpr vuint64_t Max = _UI64_MAX;
};
template<>
struct TypedValueSerializerMinMax<float>
{
static constexpr float Min = (float)-FLT_MAX;
static constexpr float Max = (float)FLT_MAX;
};
template<>
struct TypedValueSerializerMinMax<double>
{
static constexpr double Min = (double)-DBL_MAX;
static constexpr double Max = (double)DBL_MAX;
};
/***********************************************************************
Signed Types
***********************************************************************/
template<typename T>
struct TypedValueSerializerProvider_Signed
{
static T GetDefaultValue()
{
return 0;
}
static bool Serialize(const T& input, WString& output)
{
output = i64tow(input);
return true;
}
static bool Deserialize(const WString& input, T& output)
{
constexpr T MinValue = TypedValueSerializerMinMax<T>::Min;
constexpr T MaxValue = TypedValueSerializerMinMax<T>::Max;
bool success = false;
vint64_t result = wtoi64_test(input, success);
if (!success) return false;
if (result < MinValue || result > MaxValue) return false;
output = (T)result;
return true;
}
};
/***********************************************************************
Unsigned Types
***********************************************************************/
template<typename T>
struct TypedValueSerializerProvider_Unsigned
{
static T GetDefaultValue()
{
return 0;
}
static bool Serialize(const T& input, WString& output)
{
output = u64tow(input);
return true;
}
static bool Deserialize(const WString& input, T& output)
{
constexpr T MaxValue = TypedValueSerializerMinMax<T>::Max;
bool success = false;
vuint64_t result = wtou64_test(input, success);
if (!success) return false;
if (result > MaxValue) return false;
output = (T)result;
return true;
}
};
/***********************************************************************
Floating Point Types
***********************************************************************/
template<typename T>
struct TypedValueSerializerProvider_FloatingPoint
{
static T GetDefaultValue()
{
return 0;
}
static bool Serialize(const T& input, WString& output)
{
output = ftow(input);
if (output == L"-0") output = L"0";
return true;
}
static bool Deserialize(const WString& input, T& output)
{
constexpr T MinValue = TypedValueSerializerMinMax<T>::Min;
constexpr T MaxValue = TypedValueSerializerMinMax<T>::Max;
bool success = false;
double result = wtof_test(input, success);
if (!success) return false;
if (result < MinValue || result > MaxValue) return false;
output = (T)result;
return true;
}
};
/***********************************************************************
Serializable Types
***********************************************************************/
#define DEFINE_SIGNED_TVSP(TYPENAME)\
template<> struct TypedValueSerializerProvider<TYPENAME> : TypedValueSerializerProvider_Signed<TYPENAME> {};\
DEFINE_SIGNED_TVSP(vint8_t)
DEFINE_SIGNED_TVSP(vint16_t)
DEFINE_SIGNED_TVSP(vint32_t)
DEFINE_SIGNED_TVSP(vint64_t)
#undef DEFINE_SIGNED_TVSP
#define DEFINE_UNSIGNED_TVSP(TYPENAME)\
template<> struct TypedValueSerializerProvider<TYPENAME> : TypedValueSerializerProvider_Unsigned<TYPENAME> {};\
DEFINE_UNSIGNED_TVSP(vuint8_t)
DEFINE_UNSIGNED_TVSP(vuint16_t)
DEFINE_UNSIGNED_TVSP(vuint32_t)
DEFINE_UNSIGNED_TVSP(vuint64_t)
#undef DEFINE_UNSIGNED_TVSP
#define DEFINE_FLOAT_TVSP(TYPENAME)\
template<> struct TypedValueSerializerProvider<TYPENAME> : TypedValueSerializerProvider_FloatingPoint<TYPENAME> {};\
DEFINE_FLOAT_TVSP(float)
DEFINE_FLOAT_TVSP(double)
#undef DEFINE_FLOAT_TVSP
#define DEFINE_TVSP(TYPENAME)\
template<>\
struct TypedValueSerializerProvider<TYPENAME>\
{\
static TYPENAME GetDefaultValue();\
static bool Serialize(const TYPENAME& input, WString& output);\
static bool Deserialize(const WString& input, TYPENAME& output);\
};\
DEFINE_TVSP(bool)
DEFINE_TVSP(wchar_t)
DEFINE_TVSP(WString)
DEFINE_TVSP(Locale)
DEFINE_TVSP(DateTime)
#undef DEFINE_TYPED_VALUE_SERIALIZER_PROVIDER
}
}
}
#endif
/***********************************************************************
.\PREDEFINED\PREDEFINEDTYPES.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_TYPES_PREDEFINEDTYPES
#define VCZH_REFLECTION_TYPES_PREDEFINEDTYPES
#include <math.h>
namespace vl
{
namespace reflection
{
namespace description
{
struct VoidValue {};
/***********************************************************************
Collections
***********************************************************************/
/// <summary>The reflectable version of <see cref="collections::IEnumerator`1"/>.</summary>
class IValueEnumerator : public virtual IDescriptable, public Description<IValueEnumerator>
{
public:
/// <summary>Get the reference to the current value in the enumerator.</summary>
/// <returns>The current value.</returns>
/// <remarks><see cref="Next"/> needs to be called to make the first value available.</remarks>
virtual Value GetCurrent() = 0;
/// <summary>Get the position of the current value in the enumerator.</summary>
/// <returns>The position of the current value.</returns>
virtual vint GetIndex() = 0;
/// <summary>Prepare for the next value.</summary>
/// <returns>Returns false if there is no more value.</returns>
virtual bool Next() = 0;
};
/// <summary>The reflectable version of <see cref="collections::IEnumerable`1"/>.</summary>
/// <remarks><see cref="BoxParameter`1"/> will create a <see cref="Value"/> storing a shared pointer to an instance of this interface from an enumerable.</remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// MyClass(vint _data = 0)
/// :data(_data)
/// {
/// }
///
/// vint data;
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(vint), { L"data" })
/// CLASS_MEMBER_FIELD(data)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// LazyList<Ptr<MyClass>> cs = Range<vint>(1, 10)
/// .Select([](vint i)
/// {
/// return Ptr(new MyClass(i));
/// });
///
/// Value boxed = BoxParameter(cs);
/// {
/// auto enumerable = UnboxValue<Ptr<IValueEnumerable>>(boxed);
/// auto enumerator = enumerable->CreateEnumerator();
/// while (enumerator->Next())
/// {
/// Console::Write(itow(UnboxValue<Ptr<MyClass>>(enumerator->GetCurrent())->data) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
/// {
/// auto enumerator = boxed.Invoke(L"CreateEnumerator");
/// while (UnboxValue<bool>(enumerator.Invoke(L"Next")))
/// {
/// Console::Write(itow(UnboxValue<vint>(enumerator.GetProperty(L"Current").GetProperty(L"data"))) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
class IValueEnumerable : public virtual IDescriptable, public Description<IValueEnumerable>
{
public:
/// <summary>
/// Create an enumerator. <see cref="IValueEnumerator::Next"/> should be called before reading the first value.
/// </summary>
/// <returns>The enumerator.</returns>
virtual Ptr<IValueEnumerator> CreateEnumerator() = 0;
/// <summary>Get the underlying collection object, which is boxed to be this interface.</summary>
/// <returns>The underlying collection object, could be nullptr.</returns>
virtual const Object* GetCollectionObject() { return nullptr; }
/// <summary>Create an enumerable from another lazy list.</summary>
/// <returns>The created enumerable.</returns>
/// <param name="values">The lazy list to wrap.</param>
static Ptr<IValueEnumerable> Create(collections::LazyList<Value> values);
};
/// <summary>
/// The reflectable version of readonly
/// <see cref="collections::Array`2"/>,
/// <see cref="collections::List`2"/> or
/// <see cref="collections::SortedList`2"/>
/// <see cref="collections::ObservableListBase`2"/>
/// <see cref="collections::ObservableList`2"/>
/// </summary>
class IValueReadonlyList : public virtual IValueEnumerable, public Description<IValueReadonlyList>
{
public:
/// <summary>Get the number of elements in the container.</summary>
/// <returns>The number of elements.</returns>
virtual vint GetCount() = 0;
/// <summary>Get the reference to the specified element.</summary>
/// <returns>The reference to the specified element. It will crash when the index is out of range.</returns>
/// <param name="index">The index of the element.</param>
virtual Value Get(vint index) = 0;
/// <summary>Test does the list contain a value or not.</summary>
/// <returns>Returns true if the list contains the specified value.</returns>
/// <param name="value">The value to test.</param>
virtual bool Contains(const Value& value) = 0;
/// <summary>Get the position of a value in this list.</summary>
/// <returns>Returns the position of first element that equals to the specified value. Returns -1 if failed to find.</returns>
/// <param name="value">The value to find.</param>
virtual vint IndexOf(const Value& value) = 0;
};
/// <summary>
/// The reflectable version of writable
/// <see cref="collections::Array`2"/>
/// </summary>
/// <remarks><see cref="BoxParameter`1"/> will create a <see cref="Value"/> storing a shared pointer to an instance of this interface from a container.</remarks>
class IValueArray : public virtual IValueReadonlyList, public Description<IValueArray>
{
public:
/// <summary>Replace an element in the specified position.</summary>
/// <returns>Returns true if this operation succeeded. It will crash when the index is out of range</returns>
/// <param name="index">The position of the element to replace.</param>
/// <param name="value">The new value to replace.</param>
virtual void Set(vint index, const Value& value) = 0;
/// <summary>Append a value at the end of the list.</summary>
/// <returns>The index of the added item.</returns>
/// <param name="value">The value to add.</param>
virtual void Resize(vint size) = 0;
/// <summary>Create an empty array.</summary>
/// <returns>The created list.</returns>
static Ptr<IValueArray> Create();
/// <summary>Create an array with elements copied from another readonly list.</summary>
/// <returns>The created list.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueArray> Create(Ptr<IValueReadonlyList> values);
/// <summary>Create an array with elements copied from another lazy list.</summary>
/// <returns>The created list.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueArray> Create(collections::LazyList<Value> values);
};
/// <summary>
/// The reflectable version of writable
/// <see cref="collections::Array`2"/> or
/// <see cref="collections::List`2"/> or
/// <see cref="collections::ObservableListBase`2"/>
/// </summary>
/// <remarks><see cref="BoxParameter`1"/> will create a <see cref="Value"/> storing a shared pointer to an instance of this interface from a container.</remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// MyClass(vint _data = 0)
/// :data(_data)
/// {
/// }
///
/// vint data;
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(vint), { L"data" })
/// CLASS_MEMBER_FIELD(data)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// List<Ptr<MyClass>> cs;
/// CopyFrom(cs, Range<vint>(1, 10)
/// .Select([](vint i)
/// {
/// return Ptr(new MyClass(i));
/// })
/// );
///
/// Value boxed = BoxParameter(cs);
/// {
/// auto list = UnboxValue<Ptr<IValueList>>(boxed);
/// for (vint i = 0; i < list->GetCount(); i++)
/// {
/// Console::Write(itow(UnboxValue<Ptr<MyClass>>(list->Get(i))->data) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
///
/// for (vint i = 1; i <= 5; i++)
/// {
/// cs.RemoveAt(i);
/// }
///
/// {
/// for (vint i = 0; i < UnboxValue<vint>(boxed.GetProperty(L"Count")); i++)
/// {
/// Console::Write(itow(UnboxValue<vint>(boxed.Invoke(L"Get", (Value_xs(), i)).GetProperty(L"data"))) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
class IValueList : public virtual IValueReadonlyList, public Description<IValueList>
{
public:
/// <summary>Replace an element in the specified position.</summary>
/// <returns>Returns true if this operation succeeded. It will crash when the index is out of range</returns>
/// <param name="index">The position of the element to replace.</param>
/// <param name="value">The new value to replace.</param>
virtual void Set(vint index, const Value& value) = 0;
/// <summary>Append a value at the end of the list.</summary>
/// <returns>The index of the added item.</returns>
/// <param name="value">The value to add.</param>
virtual vint Add(const Value& value) = 0;
/// <summary>Insert a value at the specified position.</summary>
/// <returns>The index of the added item. It will crash if the index is out of range</returns>
/// <param name="index">The position to insert the value.</param>
/// <param name="value">The value to add.</param>
virtual vint Insert(vint index, const Value& value) = 0;
/// <summary>Remove an element from the list. If multiple elements equal to the specified value, only the first one will be removed.</summary>
/// <returns>Returns true if the element is removed.</returns>
/// <param name="value">The item to remove.</param>
virtual bool Remove(const Value& value) = 0;
/// <summary>Remove an element at a specified position.</summary>
/// <returns>Returns true if the element is removed. It will crash when the index is out of range.</returns>
/// <param name="index">The index of the element to remove.</param>
virtual bool RemoveAt(vint index) = 0;
/// <summary>Remove all elements.</summary>
virtual void Clear() = 0;
/// <summary>Create an empty list.</summary>
/// <returns>The created list.</returns>
static Ptr<IValueList> Create();
/// <summary>Create a list with elements copied from another readonly list.</summary>
/// <returns>The created list.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueList> Create(Ptr<IValueReadonlyList> values);
/// <summary>Create a list with elements copied from another lazy list.</summary>
/// <returns>The created list.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueList> Create(collections::LazyList<Value> values);
};
/// <summary>
/// The reflectable version of list container which triggers an event whenever items are changed.
/// </summary>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// MyClass(vint _data = 0)
/// :data(_data)
/// {
/// }
///
/// vint data;
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(vint), { L"data" })
/// CLASS_MEMBER_FIELD(data)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// ObservableList<Ptr<MyClass>> cs;
/// CopyFrom(cs, Range<vint>(1, 10)
/// .Select([](vint i)
/// {
/// return Ptr(new MyClass(i));
/// })
/// );
///
/// Value boxed = BoxParameter(cs);
/// auto list = UnboxValue<Ptr<IValueObservableList>>(boxed);
/// {
/// for (vint i = 0; i < list->GetCount(); i++)
/// {
/// Console::Write(itow(UnboxValue<Ptr<MyClass>>(list->Get(i))->data) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
///
/// {
/// using CallbackType = Func<void(vint, vint, vint)>;
/// CallbackType callbackFunction = [](vint index, vint oldCount, vint newCount)
/// {
/// Console::WriteLine(L"ItemChanged(" + itow(index) + L", " + itow(oldCount) + L", " + itow(newCount) + L");");
/// };
///
/// auto handler = boxed.AttachEvent(L"ItemChanged", BoxParameter(callbackFunction));
/// for (vint i = 1; i <= 5; i++)
/// {
/// cs.RemoveAt(i);
/// }
/// boxed.DetachEvent(L"ItemChanged", handler);
/// }
///
/// {
/// for (vint i = 0; i < UnboxValue<vint>(boxed.GetProperty(L"Count")); i++)
/// {
/// Console::Write(itow(UnboxValue<vint>(boxed.Invoke(L"Get", (Value_xs(), i)).GetProperty(L"data"))) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
class IValueObservableList : public virtual IValueList, public Description<IValueObservableList>
{
typedef void ItemChangedProc(vint index, vint oldCount, vint newCount);
public:
/// <summary>
/// <p>Event that is triggered whenever items are changed.</p>
/// <p>The first argument is the index of the first item that is changed.</p>
/// <p>The second argument is the number of original items that are replaced by new items.</p>
/// <p>The third argument is the number of new items that replace original items.</p>
/// </summary>
/// <remarks>
/// <p>If an item is changed, oldCount and newCount are both 1.</p>
/// <p>If several items are removed from the list, newCount is 0.</p>
/// <p>If several items are inserted to the list, oldCount is 0.</p>
/// <p>This event is triggered when the updating is done, original items are not possible to access at the moment.</p>
/// </remarks>
Event<ItemChangedProc> ItemChanged;
/// <summary>Create an empty list.</summary>
/// <returns>The created list.</returns>
static Ptr<IValueObservableList> Create();
/// <summary>Create a list with elements copied from another readonly list.</summary>
/// <returns>The created list.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueObservableList> Create(Ptr<IValueReadonlyList> values);
/// <summary>Create a list with elements copied from another lazy list.</summary>
/// <returns>The created list.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueObservableList> Create(collections::LazyList<Value> values);
};
/// <summary>
/// The reflectable version of readonly <see cref="collections::Dictionary`4"/>.
/// </summary>
class IValueReadonlyDictionary : public virtual IDescriptable, public Description<IValueReadonlyDictionary>
{
public:
/// <summary>Get all keys.</summary>
/// <returns>All keys.</returns>
virtual Ptr<IValueReadonlyList> GetKeys() = 0;
/// <summary>Get all values.</summary>
/// <returns>All values.</returns>
virtual Ptr<IValueReadonlyList> GetValues() = 0;
/// <summary>Get the number of keys.</summary>
/// <returns>The number of keys. It is also the number of values.</returns>
virtual vint GetCount() = 0;
/// <summary>Get the value associated to a specified key.</summary>
/// <returns>The reference to the value. It will crash if the key does not exist.</returns>
/// <param name="key">The key to find.</param>
virtual Value Get(const Value& key) = 0;
/// <summary>Get the underlying collection object, which is boxed to be this interface.</summary>
/// <returns>The underlying collection object, could be nullptr.</returns>
virtual const Object* GetCollectionObject() { return nullptr; }
};
/// <summary>
/// The reflectable version of writable <see cref="collections::Dictionary`4"/>.
/// </summary>
/// <remarks><see cref="BoxParameter`1"/> will create a <see cref="Value"/> storing a shared pointer to an instance of this interface from a dictionary.</remarks>
/// <example><![CDATA[
/// // reflectable C++ types
///
/// namespace mynamespace
/// {
/// class MyClass : public Object, public Description<MyClass>
/// {
/// public:
/// MyClass(vint _data = 0)
/// :data(_data)
/// {
/// }
///
/// vint data;
/// };
/// }
///
/// #define MY_TYPELIST(F)\
/// F(mynamespace::MyClass)\
///
/// // it is recommended to put the content below in a separated header file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// MY_TYPELIST(DECL_TYPE_INFO)
/// }
/// }
/// }
///
/// // it is recommended to put the content below in a separated cpp file
///
/// namespace vl
/// {
/// namespace reflection
/// {
/// namespace description
/// {
/// using namespace mynamespace;
///
/// #define _ ,
///
/// MY_TYPELIST(IMPL_CPP_TYPE_INFO)
///
/// BEGIN_CLASS_MEMBER(MyClass)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(), NO_PARAMETER)
/// CLASS_MEMBER_CONSTRUCTOR(Ptr<MyClass>(vint), { L"data" })
/// CLASS_MEMBER_FIELD(data)
/// END_CLASS_MEMBER(MyClass)
///
/// #undef _
/// }
/// }
/// }
///
/// class MyTypeLoader : public Object, public ITypeLoader
/// {
/// public:
/// void Load(ITypeManager* manager)
/// {
/// MY_TYPELIST(ADD_TYPE_INFO)
/// }
///
/// void Unload(ITypeManager* manager)
/// {
/// }
/// };
///
/// // main function
///
/// int main()
/// {
/// LoadPredefinedTypes();
/// GetGlobalTypeManager()->AddTypeLoader(new MyTypeLoader);
/// GetGlobalTypeManager()->Load();
/// {
/// Dictionary<vint, Ptr<MyClass>> cs;
/// CopyFrom(cs, Range<vint>(1, 10)
/// .Select([](vint i) -> Pair<vint, Ptr<MyClass>>
/// {
/// return { i, Ptr(new MyClass(i * i)) };
/// })
/// );
///
/// Value boxed = BoxParameter(cs);
/// {
/// auto dictionary = UnboxValue<Ptr<IValueDictionary>>(boxed);
/// for (vint i = 0; i < dictionary->GetCount(); i++)
/// {
/// Value key = dictionary->GetKeys()->Get(i);
/// Console::Write(itow(UnboxValue<Ptr<MyClass>>(dictionary->Get(key))->data) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
///
/// for (vint i = 1; i <= 5; i++)
/// {
/// cs.Remove(i * 2);
/// }
///
/// {
/// for (vint i = 0; i < UnboxValue<vint>(boxed.GetProperty(L"Count")); i++)
/// {
/// Value key = boxed.GetProperty(L"Keys").Invoke(L"Get", (Value_xs(), i));
/// Console::Write(itow(UnboxValue<vint>(boxed.Invoke(L"Get", (Value_xs(), key)).GetProperty(L"data"))) + L" ");
/// }
/// Console::WriteLine(L"");
/// }
/// }
/// DestroyGlobalTypeManager();
/// }
/// ]]></example>
class IValueDictionary : public virtual IValueReadonlyDictionary, public Description<IValueDictionary>
{
public:
/// <summary>Replace the value associated to a specified key.</summary>
/// <returns>Returns true if the value is replaced.</returns>
/// <param name="key">The key to find. If the key does not exist, it will be added to the dictionary.</param>
/// <param name="value">The associated value to replace.</param>
virtual void Set(const Value& key, const Value& value) = 0;
/// <summary>Remove a key with the associated value.</summary>
/// <returns>Returns true if the key and the value is removed.</returns>
/// <param name="key">The key to find.</param>
virtual bool Remove(const Value& key) = 0;
/// <summary>Remove all elements.</summary>
virtual void Clear() = 0;
/// <summary>Create an empty dictionary.</summary>
/// <returns>The created dictionary.</returns>
static Ptr<IValueDictionary> Create();
/// <summary>Create a dictionary with elements copied from another readonly dictionary.</summary>
/// <returns>The created dictionary.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueDictionary> Create(Ptr<IValueReadonlyDictionary> values);
/// <summary>Create a dictionary with elements copied from another lazy list.</summary>
/// <returns>The created dictionary.</returns>
/// <param name="values">Elements to copy.</param>
static Ptr<IValueDictionary> Create(collections::LazyList<collections::Pair<Value, Value>> values);
};
/***********************************************************************
Interface Implementation Proxy
***********************************************************************/
class IValueInterfaceProxy : public virtual IDescriptable, public Description<IValueInterfaceProxy>
{
public:
virtual Value Invoke(IMethodInfo* methodInfo, Ptr<IValueReadonlyList> arguments) = 0;
};
/// <summary>A reflectable version of <see cref="Func`1"/>.</summary>
/// <remarks><see cref="BoxParameter`1"/> will create a <see cref="Value"/> storing a shared pointer to an instance of this interface from a function.</remarks>
class IValueFunctionProxy : public virtual IDescriptable, public Description<IValueFunctionProxy>
{
public:
/// <summary>Call the function.</summary>
/// <returns>Return value from the function.</returns>
/// <param name="arguments">Arguments to call the function.</param>
virtual Value Invoke(Ptr<IValueReadonlyList> arguments) = 0;
};
/// <summary>A reflectable subscription, usually created by the <b>bind</b> expression in Workflow script.</summary>
class IValueSubscription : public virtual IDescriptable, public Description<IValueSubscription>
{
typedef void ValueChangedProc(const Value& newValue);
public:
/// <summary>Event that triggered when the binding source is changed.</summary>
/// <remarks>The first argument is the new value of the binding source.</remarks>
Event<ValueChangedProc> ValueChanged;
/// <summary>Start the subscription.</summary>
/// <returns>Returns true if this operation succeeded.</summary>
virtual bool Open() = 0;
/// <summary>Manually trigger the event.</summary>
/// <returns>Returns true if this operation succeeded.</summary>
virtual bool Update() = 0;
/// <summary>Stop the subscription.</summary>
/// <returns>Returns true if this operation succeeded.</summary>
virtual bool Close() = 0;
};
/***********************************************************************
Interface Implementation Proxy (Implement)
***********************************************************************/
class ValueInterfaceRoot : public virtual IDescriptable
{
protected:
Ptr<IValueInterfaceProxy> proxy;
void SetProxy(Ptr<IValueInterfaceProxy> value)
{
proxy = value;
}
public:
Ptr<IValueInterfaceProxy> GetProxy()
{
return proxy;
}
};
template<typename T>
class ValueInterfaceProxy
{
};
#pragma warning(push)
#pragma warning(disable:4250)
template<typename TInterface, typename ...TBaseInterfaces>
class ValueInterfaceImpl : public virtual ValueInterfaceRoot, public virtual TInterface, public ValueInterfaceProxy<TBaseInterfaces>...
{
public:
~ValueInterfaceImpl()
{
FinalizeAggregation();
}
};
#pragma warning(pop)
/***********************************************************************
Runtime Exception
***********************************************************************/
class IValueCallStack : public virtual IDescriptable, public Description<IValueCallStack>
{
public:
virtual Ptr<IValueReadonlyDictionary> GetLocalVariables() = 0;
virtual Ptr<IValueReadonlyDictionary> GetLocalArguments() = 0;
virtual Ptr<IValueReadonlyDictionary> GetCapturedVariables() = 0;
virtual Ptr<IValueReadonlyDictionary> GetGlobalVariables() = 0;
virtual WString GetFunctionName() = 0;
virtual WString GetSourceCodeBeforeCodegen() = 0;
virtual WString GetSourceCodeAfterCodegen() = 0;
virtual vint GetRowBeforeCodegen() = 0;
virtual vint GetRowAfterCodegen() = 0;
};
class IValueException : public virtual IDescriptable, public Description<IValueException>
{
public:
#pragma push_macro("GetMessage")
#if defined GetMessage
#undef GetMessage
#endif
virtual WString GetMessage() = 0;
#pragma pop_macro("GetMessage")
virtual bool GetFatal() = 0;
virtual Ptr<IValueReadonlyList> GetCallStack() = 0;
static Ptr<IValueException> Create(const WString& message);
};
}
}
}
#endif
/***********************************************************************
.\METADATA\METADATA.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_METADATA_METADATA
#define VCZH_REFLECTION_METADATA_METADATA
namespace vl
{
namespace reflection
{
namespace description
{
template<typename T>
struct TypeInfoRetriver;
/// <summary>
/// A reference holder to an unboxed object.
/// </summary>
/// <typeparam name="T">The type of the unboxed object.</typeparam>
template<typename T>
struct Unboxed
{
private:
T* object;
bool owned;
public:
Unboxed(T* _object, bool _owned) : object(_object), owned(_owned) {}
Unboxed(Unboxed<T>&& unboxed) : object(unboxed.object), owned(unboxed.owned) { unboxed.object = nullptr; }
~Unboxed() { if (object && owned) { delete object; } }
Unboxed() = delete;
Unboxed(const Unboxed<T>&&) = delete;
Unboxed<T>& operator=(const Unboxed<T>&) = delete;
Unboxed<T>& operator=(Unboxed<T>&&) = delete;
/// <summary>
/// Get the reference of the unboxed object.
/// It is recommended only to use this reference when the <see cref="Unboxe`1"/> is still alive.
/// </summary>
/// <returns>The unboxed object.</returns>
T& Ref() const { CHECK_ERROR(object, L"vl::reflection::description::Unboxed<T>::Ref()#The object has been moved away."); return *object; }
/// <summary>
/// Test if the unboxed object is owned.
/// </summary>
/// <returns></returns>
bool IsOwned() const
{
return owned;
}
};
template<typename T>
Value BoxValue(const T& object, ITypeDescriptor* typeDescriptor = nullptr);
template<typename T>
T UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor = nullptr, const WString& valueName = WString::Unmanaged(L"value"));
template<typename T>
Value BoxParameter(T&& object, ITypeDescriptor* typeDescriptor = nullptr);
template<typename T>
Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor = nullptr, const WString& valueName = WString::Unmanaged(L"value"));
#ifndef VCZH_DEBUG_NO_REFLECTION
/***********************************************************************
TypeInfo
***********************************************************************/
#define DECL_TYPE_INFO(TYPENAME) template<>struct TypeInfo<TYPENAME>{ static const TypeInfoContent content; };
#define IMPL_VL_TYPE_INFO(TYPENAME) const TypeInfoContent TypeInfo<TYPENAME>::content = { L ## #TYPENAME, nullptr, TypeInfoContent::VlppType };
#define IMPL_CPP_TYPE_INFO(TYPENAME) const TypeInfoContent TypeInfo<TYPENAME>::content = { L ## #TYPENAME, nullptr, TypeInfoContent::CppType };
#define IMPL_TYPE_INFO_RENAME(TYPENAME, EXPECTEDNAME) const TypeInfoContent TypeInfo<TYPENAME>::content = { L ## #EXPECTEDNAME, L ## #TYPENAME, TypeInfoContent::Renamed };
struct TypeInfoContent
{
enum TypeInfoCppName
{
VlppType, // vl::<type-name>
CppType, // <type-name>
Renamed, // CppFullTypeName
};
const wchar_t* typeName;
const wchar_t* cppFullTypeName;
TypeInfoCppName cppName;
};
template<typename T>
struct TypeInfo;
/// <summary>Get a registered type given a C++ type.</summary>
/// <returns>Returns the metadata class for this registered type.</returns>
/// <typeparam name="T">The C++ type to get the registered type.</typeparam>
/// <remarks>
/// Returning null means the type registration is declared but the type manager has not started.
/// Failing to compile means that the type registration is not declared.
/// See <see cref="Description`1"/> about how to register a type.
/// </remarks>
template<typename T>
ITypeDescriptor* GetTypeDescriptor()
{
static vint typeVersion = -1;
static ITypeDescriptor* cached = nullptr;
if (auto tm = GetGlobalTypeManager())
{
auto currentVersion = tm->GetTypeVersion();
if (typeVersion != currentVersion)
{
cached = GetTypeDescriptor(TypeInfo<T>::content.typeName);
}
return cached;
}
else
{
typeVersion = -1;
return nullptr;
}
}
#endif
#ifndef VCZH_DEBUG_NO_REFLECTION
/***********************************************************************
TypeInfoImp
***********************************************************************/
class TypeDescriptorTypeInfo : public Object, public ITypeInfo
{
protected:
ITypeDescriptor* typeDescriptor;
TypeInfoHint hint;
public:
TypeDescriptorTypeInfo(ITypeDescriptor* _typeDescriptor, TypeInfoHint _hint);
~TypeDescriptorTypeInfo();
Decorator GetDecorator()override;
TypeInfoHint GetHint()override;
ITypeInfo* GetElementType()override;
ITypeDescriptor* GetTypeDescriptor()override;
vint GetGenericArgumentCount()override;
ITypeInfo* GetGenericArgument(vint index)override;
WString GetTypeFriendlyName()override;
};
class DecoratedTypeInfo : public Object, public ITypeInfo
{
protected:
Ptr<ITypeInfo> elementType;
public:
DecoratedTypeInfo(Ptr<ITypeInfo> _elementType);
~DecoratedTypeInfo();
TypeInfoHint GetHint()override;
ITypeInfo* GetElementType()override;
ITypeDescriptor* GetTypeDescriptor()override;
vint GetGenericArgumentCount()override;
ITypeInfo* GetGenericArgument(vint index)override;
};
class RawPtrTypeInfo : public DecoratedTypeInfo
{
public:
RawPtrTypeInfo(Ptr<ITypeInfo> _elementType);
~RawPtrTypeInfo();
Decorator GetDecorator()override;
WString GetTypeFriendlyName()override;
};
class SharedPtrTypeInfo : public DecoratedTypeInfo
{
public:
SharedPtrTypeInfo(Ptr<ITypeInfo> _elementType);
~SharedPtrTypeInfo();
Decorator GetDecorator()override;
WString GetTypeFriendlyName()override;
};
class NullableTypeInfo : public DecoratedTypeInfo
{
public:
NullableTypeInfo(Ptr<ITypeInfo> _elementType);
~NullableTypeInfo();
Decorator GetDecorator()override;
WString GetTypeFriendlyName()override;
};
class GenericTypeInfo : public DecoratedTypeInfo
{
protected:
collections::List<Ptr<ITypeInfo>> genericArguments;
public:
GenericTypeInfo(Ptr<ITypeInfo> _elementType);
~GenericTypeInfo();
Decorator GetDecorator()override;
vint GetGenericArgumentCount()override;
ITypeInfo* GetGenericArgument(vint index)override;
WString GetTypeFriendlyName()override;
void AddGenericArgument(Ptr<ITypeInfo> value);
};
#endif
#ifndef VCZH_DEBUG_NO_REFLECTION
/***********************************************************************
SerializableTypeDescriptor
***********************************************************************/
class TypeDescriptorImplBase : public Object, public ITypeDescriptor, private ITypeDescriptor::ICpp
{
private:
TypeDescriptorFlags typeDescriptorFlags;
const TypeInfoContent* typeInfoContent;
WString typeName;
WString cppFullTypeName;
const WString& GetFullName()override;
protected:
const TypeInfoContent* GetTypeInfoContentInternal();
public:
TypeDescriptorImplBase(TypeDescriptorFlags _typeDescriptorFlags, const TypeInfoContent* _typeInfoContent);
~TypeDescriptorImplBase();
ITypeDescriptor::ICpp* GetCpp()override;
TypeDescriptorFlags GetTypeDescriptorFlags()override;
const WString& GetTypeName()override;
};
class ValueTypeDescriptorBase : public TypeDescriptorImplBase
{
protected:
bool loaded;
Ptr<IValueType> valueType;
Ptr<IEnumType> enumType;
Ptr<ISerializableType> serializableType;
virtual void LoadInternal();;
void Load();
public:
ValueTypeDescriptorBase(TypeDescriptorFlags _typeDescriptorFlags, const TypeInfoContent* _typeInfoContent);
~ValueTypeDescriptorBase();
bool IsAggregatable()override;
IValueType* GetValueType()override;
IEnumType* GetEnumType()override;
ISerializableType* GetSerializableType()override;
vint GetBaseTypeDescriptorCount()override;
ITypeDescriptor* GetBaseTypeDescriptor(vint index)override;
bool CanConvertTo(ITypeDescriptor* targetType)override;
vint GetPropertyCount()override;
IPropertyInfo* GetProperty(vint index)override;
bool IsPropertyExists(const WString& name, bool inheritable)override;
IPropertyInfo* GetPropertyByName(const WString& name, bool inheritable)override;
vint GetEventCount()override;
IEventInfo* GetEvent(vint index)override;
bool IsEventExists(const WString& name, bool inheritable)override;
IEventInfo* GetEventByName(const WString& name, bool inheritable)override;
vint GetMethodGroupCount()override;
IMethodGroupInfo* GetMethodGroup(vint index)override;
bool IsMethodGroupExists(const WString& name, bool inheritable)override;
IMethodGroupInfo* GetMethodGroupByName(const WString& name, bool inheritable)override;
IMethodGroupInfo* GetConstructorGroup()override;
};
template<typename T, TypeDescriptorFlags TDFlags>
class TypedValueTypeDescriptorBase : public ValueTypeDescriptorBase
{
public:
TypedValueTypeDescriptorBase()
:ValueTypeDescriptorBase(TDFlags, &TypeInfo<T>::content)
{
}
};
/***********************************************************************
ParameterInfoImpl
***********************************************************************/
class ParameterInfoImpl : public Object, public IParameterInfo
{
protected:
IMethodInfo* ownerMethod;
WString name;
Ptr<ITypeInfo> type;
public:
ParameterInfoImpl(IMethodInfo* _ownerMethod, const WString& _name, Ptr<ITypeInfo> _type);
~ParameterInfoImpl();
ITypeDescriptor* GetOwnerTypeDescriptor()override;
const WString& GetName()override;
ITypeInfo* GetType()override;
IMethodInfo* GetOwnerMethod()override;
};
/***********************************************************************
MethodInfoImpl
***********************************************************************/
class MethodInfoImpl : public Object, public IMethodInfo
{
friend class PropertyInfoImpl;
protected:
IMethodGroupInfo* ownerMethodGroup;
IPropertyInfo* ownerProperty;
collections::List<Ptr<IParameterInfo>> parameters;
Ptr<ITypeInfo> returnInfo;
bool isStatic;
virtual Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)=0;
virtual Value CreateFunctionProxyInternal(const Value& thisObject) = 0;
public:
MethodInfoImpl(IMethodGroupInfo* _ownerMethodGroup, Ptr<ITypeInfo> _return, bool _isStatic);
~MethodInfoImpl();
ITypeDescriptor* GetOwnerTypeDescriptor()override;
IPropertyInfo* GetOwnerProperty()override;
const WString& GetName()override;
IMethodGroupInfo* GetOwnerMethodGroup()override;
vint GetParameterCount()override;
IParameterInfo* GetParameter(vint index)override;
ITypeInfo* GetReturn()override;
bool IsStatic()override;
void CheckArguments(collections::Array<Value>& arguments)override;
Value Invoke(const Value& thisObject, collections::Array<Value>& arguments)override;
Value CreateFunctionProxy(const Value& thisObject)override;
bool AddParameter(Ptr<IParameterInfo> parameter);
bool SetOwnerMethodgroup(IMethodGroupInfo* _ownerMethodGroup);
};
/***********************************************************************
MethodGroupInfoImpl
***********************************************************************/
class MethodGroupInfoImpl : public Object, public IMethodGroupInfo
{
protected:
ITypeDescriptor* ownerTypeDescriptor;
WString name;
collections::List<Ptr<IMethodInfo>> methods;
public:
MethodGroupInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name);
~MethodGroupInfoImpl();
ITypeDescriptor* GetOwnerTypeDescriptor()override;
const WString& GetName()override;
vint GetMethodCount()override;
IMethodInfo* GetMethod(vint index)override;
bool AddMethod(Ptr<IMethodInfo> _method);
};
/***********************************************************************
EventInfoImpl
***********************************************************************/
class EventInfoImpl : public Object, public IEventInfo
{
friend class PropertyInfoImpl;
protected:
ITypeDescriptor* ownerTypeDescriptor;
collections::List<IPropertyInfo*> observingProperties;
WString name;
Ptr<ITypeInfo> handlerType;
virtual Ptr<IEventHandler> AttachInternal(DescriptableObject* thisObject, Ptr<IValueFunctionProxy> handler)=0;
virtual bool DetachInternal(DescriptableObject* thisObject, Ptr<IEventHandler> handler)=0;
virtual void InvokeInternal(DescriptableObject* thisObject, Ptr<IValueReadonlyList> arguments)=0;
virtual Ptr<ITypeInfo> GetHandlerTypeInternal()=0;
public:
EventInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name);
~EventInfoImpl();
ITypeDescriptor* GetOwnerTypeDescriptor()override;
const WString& GetName()override;
ITypeInfo* GetHandlerType()override;
vint GetObservingPropertyCount()override;
IPropertyInfo* GetObservingProperty(vint index)override;
Ptr<IEventHandler> Attach(const Value& thisObject, Ptr<IValueFunctionProxy> handler)override;
bool Detach(const Value& thisObject, Ptr<IEventHandler> handler)override;
void Invoke(const Value& thisObject, Ptr<IValueReadonlyList> arguments)override;
};
/***********************************************************************
TypeDescriptorImpl
***********************************************************************/
class PropertyInfoImpl : public Object, public IPropertyInfo
{
protected:
ITypeDescriptor* ownerTypeDescriptor;
WString name;
Ptr<ICpp> cpp;
MethodInfoImpl* getter;
MethodInfoImpl* setter;
EventInfoImpl* valueChangedEvent;
public:
PropertyInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, MethodInfoImpl* _getter, MethodInfoImpl* _setter, EventInfoImpl* _valueChangedEvent);
~PropertyInfoImpl();
ITypeDescriptor* GetOwnerTypeDescriptor()override;
const WString& GetName()override;
IPropertyInfo::ICpp* GetCpp()override;
bool IsReadable()override;
bool IsWritable()override;
ITypeInfo* GetReturn()override;
IMethodInfo* GetGetter()override;
IMethodInfo* GetSetter()override;
IEventInfo* GetValueChangedEvent()override;
Value GetValue(const Value& thisObject)override;
void SetValue(Value& thisObject, const Value& newValue)override;
};
class PropertyInfoImpl_StaticCpp : public PropertyInfoImpl, private IPropertyInfo::ICpp
{
private:
WString referenceTemplate;
const WString& GetReferenceTemplate()override;
public:
PropertyInfoImpl_StaticCpp(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, MethodInfoImpl* _getter, MethodInfoImpl* _setter, EventInfoImpl* _valueChangedEvent, const WString& _referenceTemplate);
~PropertyInfoImpl_StaticCpp();
IPropertyInfo::ICpp* GetCpp()override;
};
/***********************************************************************
FieldInfoImpl
***********************************************************************/
class FieldInfoImpl : public Object, public IPropertyInfo
{
protected:
ITypeDescriptor* ownerTypeDescriptor;
Ptr<ITypeInfo> returnInfo;
WString name;
virtual Value GetValueInternal(const Value& thisObject)=0;
virtual void SetValueInternal(Value& thisObject, const Value& newValue)=0;
public:
FieldInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, Ptr<ITypeInfo> _returnInfo);
~FieldInfoImpl();
ITypeDescriptor* GetOwnerTypeDescriptor()override;
const WString& GetName()override;
bool IsReadable()override;
bool IsWritable()override;
ITypeInfo* GetReturn()override;
IMethodInfo* GetGetter()override;
IMethodInfo* GetSetter()override;
IEventInfo* GetValueChangedEvent()override;
Value GetValue(const Value& thisObject)override;
void SetValue(Value& thisObject, const Value& newValue)override;
};
/***********************************************************************
TypeDescriptorImpl
***********************************************************************/
class TypeDescriptorImpl : public TypeDescriptorImplBase
{
private:
bool loaded;
collections::List<ITypeDescriptor*> baseTypeDescriptors;
collections::Dictionary<WString, Ptr<IPropertyInfo>> properties;
collections::Dictionary<WString, Ptr<IEventInfo>> events;
collections::Dictionary<WString, Ptr<MethodGroupInfoImpl>> methodGroups;
Ptr<MethodGroupInfoImpl> constructorGroup;
protected:
MethodGroupInfoImpl* PrepareMethodGroup(const WString& name);
MethodGroupInfoImpl* PrepareConstructorGroup();
IPropertyInfo* AddProperty(Ptr<IPropertyInfo> value);
IEventInfo* AddEvent(Ptr<IEventInfo> value);
IMethodInfo* AddMethod(const WString& name, Ptr<MethodInfoImpl> value);
IMethodInfo* AddConstructor(Ptr<MethodInfoImpl> value);
void AddBaseType(ITypeDescriptor* value);
virtual void LoadInternal()=0;
void Load();
public:
TypeDescriptorImpl(TypeDescriptorFlags _typeDescriptorFlags, const TypeInfoContent* _typeInfoContent);
~TypeDescriptorImpl();
bool IsAggregatable()override;
IValueType* GetValueType()override;
IEnumType* GetEnumType()override;
ISerializableType* GetSerializableType()override;
vint GetBaseTypeDescriptorCount()override;
ITypeDescriptor* GetBaseTypeDescriptor(vint index)override;
bool CanConvertTo(ITypeDescriptor* targetType)override;
vint GetPropertyCount()override;
IPropertyInfo* GetProperty(vint index)override;
bool IsPropertyExists(const WString& name, bool inheritable)override;
IPropertyInfo* GetPropertyByName(const WString& name, bool inheritable)override;
vint GetEventCount()override;
IEventInfo* GetEvent(vint index)override;
bool IsEventExists(const WString& name, bool inheritable)override;
IEventInfo* GetEventByName(const WString& name, bool inheritable)override;
vint GetMethodGroupCount()override;
IMethodGroupInfo* GetMethodGroup(vint index)override;
bool IsMethodGroupExists(const WString& name, bool inheritable)override;
IMethodGroupInfo* GetMethodGroupByName(const WString& name, bool inheritable)override;
IMethodGroupInfo* GetConstructorGroup()override;
};
#endif
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
/***********************************************************************
CustomFieldInfoImpl
***********************************************************************/
template<typename TClass, typename TField>
class CustomFieldInfoImpl : public FieldInfoImpl
{
protected:
TField TClass::* fieldRef;
Value GetValueInternal(const Value& thisObject)override
{
TClass* object = UnboxValue<TClass*>(thisObject);
if (object)
{
return BoxParameter(object->*fieldRef, GetReturn()->GetTypeDescriptor());
}
return Value();
}
void SetValueInternal(Value& thisObject, const Value& newValue)override
{
if constexpr (std::is_copy_assignable_v<TField>)
{
TClass* object = UnboxValue<TClass*>(thisObject);
if (object)
{
auto result = UnboxParameter<TField>(newValue, GetReturn()->GetTypeDescriptor(), L"newValue");
object->*fieldRef = result.Ref();
}
}
else
{
throw PropertyIsNotWritableException(this);
}
}
public:
CustomFieldInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, TField TClass::* _fieldRef)
:FieldInfoImpl(_ownerTypeDescriptor, _name, TypeInfoRetriver<TField>::CreateTypeInfo())
, fieldRef(_fieldRef)
{
}
IPropertyInfo::ICpp* GetCpp()override
{
return nullptr;
}
bool IsWritable()override
{
return std::is_copy_assignable_v<TField>;
}
};
#endif
/***********************************************************************
PrimitiveTypeDescriptor
***********************************************************************/
#ifndef VCZH_DEBUG_NO_REFLECTION
template<typename T>
class SerializableValueType : public Object, public virtual IValueType
{
public:
Value CreateDefault()override
{
return BoxValue<T>(TypedValueSerializerProvider<T>::GetDefaultValue());
}
};
template<typename T>
class SerializableType : public Object, public virtual ISerializableType
{
public:
bool Serialize(const Value& input, WString& output)override
{
return TypedValueSerializerProvider<T>::Serialize(UnboxValue<T>(input), output);
}
bool Deserialize(const WString& input, Value& output)override
{
T value;
if (!TypedValueSerializerProvider<T>::Deserialize(input, value))
{
return false;
}
output = BoxValue<T>(value);
return true;
}
};
#endif
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
template<typename T>
class PrimitiveTypeDescriptor : public TypedValueTypeDescriptorBase<T, TypeDescriptorFlags::Primitive>
{
protected:
void LoadInternal()override
{
this->valueType = Ptr(new SerializableValueType<T>());
this->serializableType = Ptr(new SerializableType<T>());
}
};
/***********************************************************************
EnumTypeDescriptor
***********************************************************************/
template<typename T>
class EnumValueType : public Object, public virtual IValueType
{
public:
Value CreateDefault()override
{
return BoxValue<T>(static_cast<T>(0));
}
};
template<typename T, bool Flag>
class EnumType : public Object, public virtual IEnumType
{
protected:
collections::Dictionary<WString, T> candidates;
public:
void AddItem(WString name, T value)
{
candidates.Add(name, value);
}
bool IsFlagEnum()override
{
return Flag;
}
vint GetItemCount()override
{
return candidates.Count();
}
WString GetItemName(vint index)override
{
if (index < 0 || index >= candidates.Count())
{
return L"";
}
return candidates.Keys()[index];
}
vuint64_t GetItemValue(vint index)override
{
if (index < 0 || index >= candidates.Count())
{
return 0;
}
return static_cast<vuint64_t>(candidates.Values()[index]);
}
vint IndexOfItem(WString name)override
{
return candidates.Keys().IndexOf(name);
}
Value ToEnum(vuint64_t value)override
{
return BoxValue<T>(static_cast<T>(value));
}
vuint64_t FromEnum(const Value& value)override
{
return static_cast<vuint64_t>(UnboxValue<T>(value));
}
};
template<typename T, TypeDescriptorFlags TDFlags>
class EnumTypeDescriptor : public TypedValueTypeDescriptorBase<T, TDFlags>
{
using TEnumType = EnumType<T, TDFlags == TypeDescriptorFlags::FlagEnum>;
protected:
Ptr<TEnumType> enumType;
void LoadInternal()override
{
this->enumType = Ptr(new TEnumType);
this->valueType = Ptr(new EnumValueType<T>());
TypedValueTypeDescriptorBase<T, TDFlags>::enumType = enumType;
}
};
/***********************************************************************
StructTypeDescriptor
***********************************************************************/
template<typename T>
class StructValueType : public Object, public virtual IValueType
{
public:
Value CreateDefault()override
{
return BoxValue<T>(T{});
}
};
template<typename T, TypeDescriptorFlags TDFlags>
class StructTypeDescriptor : public TypedValueTypeDescriptorBase<T, TDFlags>
{
protected:
template<typename TField>
class StructFieldInfo : public FieldInfoImpl
{
protected:
TField T::* field;
Value GetValueInternal(const Value& thisObject)override
{
auto structValue = thisObject.GetBoxedValue().Cast<IValueType::TypedBox<T>>();
if (!structValue)
{
throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
}
return BoxValue<TField>(structValue->value.*field);
}
void SetValueInternal(Value& thisObject, const Value& newValue)override
{
auto structValue = thisObject.GetBoxedValue().Cast<IValueType::TypedBox<T>>();
if (!structValue)
{
throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
}
(structValue->value.*field) = UnboxValue<TField>(newValue);
}
public:
StructFieldInfo(ITypeDescriptor* _ownerTypeDescriptor, TField T::* _field, const WString& _name)
:field(_field)
, FieldInfoImpl(_ownerTypeDescriptor, _name, TypeInfoRetriver<TField>::CreateTypeInfo())
{
}
IPropertyInfo::ICpp* GetCpp()override
{
return nullptr;
}
};
protected:
collections::Dictionary<WString, Ptr<IPropertyInfo>> fields;
public:
StructTypeDescriptor()
{
this->valueType = Ptr(new StructValueType<T>());
}
vint GetPropertyCount()override
{
this->Load();
return fields.Count();
}
IPropertyInfo* GetProperty(vint index)override
{
this->Load();
if (index < 0 || index >= fields.Count())
{
return nullptr;
}
return fields.Values()[index].Obj();
}
bool IsPropertyExists(const WString& name, bool inheritable)override
{
this->Load();
return fields.Keys().Contains(name);
}
IPropertyInfo* GetPropertyByName(const WString& name, bool inheritable)override
{
this->Load();
vint index = fields.Keys().IndexOf(name);
if (index == -1) return nullptr;
return fields.Values()[index].Obj();
}
};
#endif
}
}
}
#endif
/***********************************************************************
.\BOXING\TYPEINFORETRIVER.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_BOXING_TYPEINFORETRIVER
#define VCZH_REFLECTION_BOXING_TYPEINFORETRIVER
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
TypeFlagTester
***********************************************************************/
enum class TypeFlags
{
NonGenericType =0,
FunctionType =1<<0,
EnumerableType =1<<1,
ReadonlyListType =1<<2,
ArrayType =1<<3,
ListType =1<<4,
ObservableListType =1<<5,
ReadonlyDictionaryType =1<<6,
DictionaryType =1<<7,
};
template<typename T>
struct ValueRetriver
{
T* pointer;
};
template<typename T>
struct ValueRetriver<T&>
{
T* pointer;
};
template<typename TDerived, TypeFlags Flag>
struct TypeFlagTester
{
static const TypeFlags Result=TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::FunctionType>
{
template<typename T>
static void* Inherit(const Func<T>* source){ return {}; }
static char Inherit(void* source){ return {}; }
static char Inherit(const void* source){ return {}; }
static const TypeFlags Result=sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer))==sizeof(void*)?TypeFlags::FunctionType:TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::EnumerableType>
{
template<typename T>
static void* Inherit(const collections::LazyList<T>* source){ return {}; }
template<typename T>
static void* Inherit(const collections::IEnumerable<T>* source) { return {}; }
static char Inherit(void* source){ return {}; }
static char Inherit(const void* source){ return {}; }
static const TypeFlags Result=sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer))==sizeof(void*)?TypeFlags::EnumerableType:TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::ReadonlyListType>
{
template<typename T>
static void* Inherit(const collections::Array<T>* source){ return {}; }
template<typename T>
static void* Inherit(const collections::List<T>* source) { return {}; }
template<typename T>
static void* Inherit(const collections::SortedList<T>* source) { return {}; }
template<typename T>
static void* Inherit(const collections::ObservableListBase<T>* source) { return {}; }
static char Inherit(void* source){ return {}; }
static char Inherit(const void* source){ return {}; }
static const TypeFlags Result=sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer))==sizeof(void*)?TypeFlags::ReadonlyListType:TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::ArrayType>
{
template<typename T>
static void* Inherit(collections::Array<T>* source) { return {}; }
static char Inherit(void* source) { return {}; }
static char Inherit(const void* source) { return {}; }
static const TypeFlags Result = sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer)) == sizeof(void*) ? TypeFlags::ArrayType : TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::ListType>
{
template<typename T>
static void* Inherit(collections::List<T>* source) { return {}; }
template<typename T>
static void* Inherit(collections::ObservableListBase<T>* source) { return {}; }
static char Inherit(void* source){ return {}; }
static char Inherit(const void* source){ return {}; }
static const TypeFlags Result=sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer))==sizeof(void*)?TypeFlags::ListType:TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::ObservableListType>
{
template<typename T>
static void* Inherit(collections::ObservableList<T>* source) { return {}; }
static char Inherit(void* source) { return {}; }
static char Inherit(const void* source) { return {}; }
static const TypeFlags Result = sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer)) == sizeof(void*) ? TypeFlags::ObservableListType : TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::ReadonlyDictionaryType>
{
template<typename K, typename V>
static void* Inherit(const collections::Dictionary<K, V>* source){ return {}; }
static char Inherit(void* source){ return {}; }
static char Inherit(const void* source){ return {}; }
static const TypeFlags Result=sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer))==sizeof(void*)?TypeFlags::ReadonlyDictionaryType:TypeFlags::NonGenericType;
};
template<typename TDerived>
struct TypeFlagTester<TDerived, TypeFlags::DictionaryType>
{
template<typename K, typename V>
static void* Inherit(collections::Dictionary<K, V>* source){ return {}; }
static char Inherit(void* source){ return {}; }
static char Inherit(const void* source){ return {}; }
static const TypeFlags Result=sizeof(Inherit(((ValueRetriver<TDerived>*)0)->pointer))==sizeof(void*)?TypeFlags::DictionaryType:TypeFlags::NonGenericType;
};
/***********************************************************************
TypeFlagSelector
***********************************************************************/
template<typename T, TypeFlags Flag>
struct TypeFlagSelectorCase
{
static const TypeFlags Result=TypeFlags::NonGenericType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::FunctionType)>
{
static const TypeFlags Result=TypeFlags::FunctionType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::EnumerableType)>
{
static const TypeFlags Result=TypeFlags::EnumerableType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::EnumerableType|(vint)TypeFlags::ReadonlyListType)>
{
static const TypeFlags Result = TypeFlags::ReadonlyListType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::EnumerableType|(vint)TypeFlags::ReadonlyListType|(vint)TypeFlags::ArrayType)>
{
static const TypeFlags Result = TypeFlags::ArrayType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::EnumerableType|(vint)TypeFlags::ReadonlyListType|(vint)TypeFlags::ListType)>
{
static const TypeFlags Result = TypeFlags::ListType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::EnumerableType|(vint)TypeFlags::ReadonlyListType|(vint)TypeFlags::ListType|(vint)TypeFlags::ObservableListType)>
{
static const TypeFlags Result = TypeFlags::ObservableListType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::EnumerableType|(vint)TypeFlags::ReadonlyDictionaryType)>
{
static const TypeFlags Result=TypeFlags::ReadonlyDictionaryType;
};
template<typename T>
struct TypeFlagSelectorCase<T, (TypeFlags)((vint)TypeFlags::EnumerableType |(vint)TypeFlags::ReadonlyDictionaryType |(vint)TypeFlags::DictionaryType)>
{
static const TypeFlags Result=TypeFlags::DictionaryType;
};
template<typename T>
struct TypeFlagSelector
{
static const TypeFlags Result =
TypeFlagSelectorCase<
T,
(TypeFlags)
( (vint)TypeFlagTester<T, TypeFlags::FunctionType>::Result
| (vint)TypeFlagTester<T, TypeFlags::EnumerableType>::Result
| (vint)TypeFlagTester<T, TypeFlags::ReadonlyListType>::Result
| (vint)TypeFlagTester<T, TypeFlags::ArrayType>::Result
| (vint)TypeFlagTester<T, TypeFlags::ListType>::Result
| (vint)TypeFlagTester<T, TypeFlags::ObservableListType>::Result
| (vint)TypeFlagTester<T, TypeFlags::ReadonlyDictionaryType>::Result
| (vint)TypeFlagTester<T, TypeFlags::DictionaryType>::Result
)
>::Result;
};
/***********************************************************************
TypeHintTester
***********************************************************************/
template<typename T>
struct TypeHintTester
{
static const TypeInfoHint Result = TypeInfoHint::Normal;
};
template<TypeFlags Flags>
struct TypeHintTesterForReference
{
static const TypeInfoHint Result = TypeInfoHint::NativeCollectionReference;
};
template<>
struct TypeHintTesterForReference<TypeFlags::NonGenericType>
{
static const TypeInfoHint Result = TypeInfoHint::Normal;
};
template<>
struct TypeHintTesterForReference<TypeFlags::FunctionType>
{
static const TypeInfoHint Result = TypeInfoHint::Normal;
};
template<typename T>
struct TypeHintTester<T*>
{
static const TypeInfoHint Result = TypeHintTester<T>::Result;
};
template<typename T>
struct TypeHintTester<T&>
{
static const TypeInfoHint Result = TypeHintTester<T>::Result == TypeInfoHint::Normal
? TypeHintTesterForReference<TypeFlagSelector<T&>::Result>::Result
: TypeHintTester<T>::Result
;
};
template<typename T>
struct TypeHintTester<const T>
{
static const TypeInfoHint Result = TypeHintTester<T>::Result;
};
template<typename T>
struct TypeHintTester<collections::LazyList<T>>
{
static const TypeInfoHint Result = TypeInfoHint::LazyList;
};
template<typename T>
struct TypeHintTester<collections::Array<T>>
{
static const TypeInfoHint Result = TypeInfoHint::Array;
};
template<typename T>
struct TypeHintTester<collections::List<T>>
{
static const TypeInfoHint Result = TypeInfoHint::List;
};
template<typename T>
struct TypeHintTester<collections::SortedList<T>>
{
static const TypeInfoHint Result = TypeInfoHint::SortedList;
};
template<typename T>
struct TypeHintTester<collections::ObservableList<T>>
{
static const TypeInfoHint Result = TypeInfoHint::ObservableList;
};
template<typename K, typename V>
struct TypeHintTester<collections::Dictionary<K, V>>
{
static const TypeInfoHint Result = TypeInfoHint::Dictionary;
};
/***********************************************************************
DetailTypeInfoRetriver
***********************************************************************/
template<typename T, TypeFlags Flag>
struct DetailTypeInfoRetriver;
/***********************************************************************
Basic Types
***********************************************************************/
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::NonGenericType>
{
static const ITypeInfo::Decorator Decorator=ITypeInfo::TypeDescriptor;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo(TypeInfoHint hint)
{
return Ptr(new TypeDescriptorTypeInfo(GetTypeDescriptor<T>(), hint));
}
#endif
};
/***********************************************************************
Decorated Types
***********************************************************************/
template<typename T>
struct DetailTypeInfoRetriver<T*, TypeFlags::NonGenericType>
{
typedef DetailTypeInfoRetriver<T, TypeFlags::NonGenericType> UpLevelRetriver;
static const ITypeInfo::Decorator Decorator=ITypeInfo::RawPtr;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo(TypeInfoHint hint)
{
return Ptr(new RawPtrTypeInfo(TypeInfoRetriver<T>::CreateTypeInfo()));
}
#endif
};
template<typename T>
struct DetailTypeInfoRetriver<Ptr<T>, TypeFlags::NonGenericType>
{
typedef DetailTypeInfoRetriver<T, TypeFlags::NonGenericType> UpLevelRetriver;
static const ITypeInfo::Decorator Decorator=ITypeInfo::SharedPtr;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo(TypeInfoHint hint)
{
return Ptr(new SharedPtrTypeInfo(TypeInfoRetriver<T>::CreateTypeInfo()));
}
#endif
};
template<typename T>
struct DetailTypeInfoRetriver<Nullable<T>, TypeFlags::NonGenericType>
{
typedef DetailTypeInfoRetriver<T, TypeFlags::NonGenericType> UpLevelRetriver;
static const ITypeInfo::Decorator Decorator=ITypeInfo::Nullable;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo(TypeInfoHint hint)
{
return Ptr(new NullableTypeInfo(TypeInfoRetriver<T>::CreateTypeInfo()));
}
#endif
};
/***********************************************************************
Containers
***********************************************************************/
template<typename T, typename TCollectionType>
struct DetailTypeInfoRetriver_Template1
{
typedef DetailTypeInfoRetriver<T, TypeFlags::NonGenericType> UpLevelRetriver;
static const ITypeInfo::Decorator Decorator = UpLevelRetriver::Decorator;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo(TypeInfoHint hint)
{
auto arrayType = Ptr(new TypeDescriptorTypeInfo(GetTypeDescriptor<TCollectionType>(), hint));
auto genericType = Ptr(new GenericTypeInfo(arrayType));
genericType->AddGenericArgument(TypeInfoRetriver<typename T::ElementType>::CreateTypeInfo());
auto type = Ptr(new SharedPtrTypeInfo(genericType));
return type;
}
#endif
};
template<typename T, typename TCollectionType>
struct DetailTypeInfoRetriver_Template2
{
typedef DetailTypeInfoRetriver<T, TypeFlags::NonGenericType> UpLevelRetriver;
static const ITypeInfo::Decorator Decorator = UpLevelRetriver::Decorator;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo(TypeInfoHint hint)
{
auto arrayType = Ptr(new TypeDescriptorTypeInfo(GetTypeDescriptor<TCollectionType>(), hint));
auto genericType = Ptr(new GenericTypeInfo(arrayType));
genericType->AddGenericArgument(TypeInfoRetriver<typename T::KeyContainer::ElementType>::CreateTypeInfo());
genericType->AddGenericArgument(TypeInfoRetriver<typename T::ValueContainer::ElementType>::CreateTypeInfo());
auto type = Ptr(new SharedPtrTypeInfo(genericType));
return type;
}
#endif
};
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::EnumerableType> : DetailTypeInfoRetriver_Template1<T, IValueEnumerable>
{
};
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::ReadonlyListType> : DetailTypeInfoRetriver_Template1<T, IValueReadonlyList>
{
};
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::ArrayType> : DetailTypeInfoRetriver_Template1<T, IValueArray>
{
};
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::ListType> : DetailTypeInfoRetriver_Template1<T, IValueList>
{
};
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::ObservableListType> : DetailTypeInfoRetriver_Template1<T, IValueObservableList>
{
};
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::ReadonlyDictionaryType> : DetailTypeInfoRetriver_Template2<T, IValueReadonlyDictionary>
{
};
template<typename T>
struct DetailTypeInfoRetriver<T, TypeFlags::DictionaryType> : DetailTypeInfoRetriver_Template2<T, IValueDictionary>
{
};
/***********************************************************************
Functions
***********************************************************************/
#ifndef VCZH_DEBUG_NO_REFLECTION
namespace internal_helper
{
template<typename T>
struct GenericArgumentAdder
{
static void Add(Ptr<GenericTypeInfo> genericType)
{
}
};
template<typename T0, typename ...TNextArgs>
struct GenericArgumentAdder<TypeTuple<T0, TNextArgs...>>
{
static void Add(Ptr<GenericTypeInfo> genericType)
{
genericType->AddGenericArgument(TypeInfoRetriver<T0>::CreateTypeInfo());
GenericArgumentAdder<TypeTuple<TNextArgs...>>::Add(genericType);
}
};
}
#endif
template<typename R, typename ...TArgs>
struct DetailTypeInfoRetriver<Func<R(TArgs...)>, TypeFlags::FunctionType>
{
typedef DetailTypeInfoRetriver<const Func<R(TArgs...)>, TypeFlags::NonGenericType> UpLevelRetriver;
static const ITypeInfo::Decorator Decorator=UpLevelRetriver::Decorator;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo(TypeInfoHint hint)
{
auto functionType = Ptr(new TypeDescriptorTypeInfo(GetTypeDescriptor<IValueFunctionProxy>(), hint));
auto genericType = Ptr(new GenericTypeInfo(functionType));
genericType->AddGenericArgument(TypeInfoRetriver<R>::CreateTypeInfo());
internal_helper::GenericArgumentAdder<TypeTuple<TArgs...>>::Add(genericType);
auto type = Ptr(new SharedPtrTypeInfo(genericType));
return type;
}
#endif
};
/***********************************************************************
TypeInfoRetriver
***********************************************************************/
template<typename T>
struct TypeInfoRetriver
{
static const TypeFlags TypeFlag = TypeFlagSelector<T>::Result;
static const TypeInfoHint Hint = TypeHintTester<T>::Result;
typedef DetailTypeInfoRetriver<std::remove_cvref_t<T>, TypeFlag> Detail;
static const ITypeInfo::Decorator Decorator = Detail::Decorator;
#ifndef VCZH_DEBUG_NO_REFLECTION
static Ptr<ITypeInfo> CreateTypeInfo()
{
return DetailTypeInfoRetriver<std::remove_cvref_t<T>, TypeFlag>::CreateTypeInfo(Hint);
}
#endif
};
template<>
struct TypeInfoRetriver<void> : public TypeInfoRetriver<VoidValue>
{
};
}
}
}
#endif
/***********************************************************************
.\BOXING\BOXINGVALUE.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_BOXING_BOXINGVALUE
#define VCZH_REFLECTION_BOXING_BOXINGVALUE
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
BoxValue, UnboxValue
***********************************************************************/
template<typename T, ITypeInfo::Decorator Decorator>
struct ValueAccessor
{
};
/// <summary>Box an reflectable object. Its type cannot be generic.</summary>
/// <returns>The boxed value.</returns>
/// <typeparam name="T">Type of the object.</typeparam>
/// <param name="object">The object to box.</param>
/// <param name="typeDescriptor">The type descriptor of the object (optional).</param>
template<typename T>
Value BoxValue(const T& object, ITypeDescriptor* typeDescriptor)
{
using Type = std::remove_cvref_t<T>;
return ValueAccessor<Type, TypeInfoRetriver<Type>::Decorator>::BoxValue(object, typeDescriptor);
}
/// <summary>Unbox a reflectable object. Its type cannot be generic.</summary>
/// <returns>The unboxed object.</returns>
/// <typeparam name="T">Type of the object.</typeparam>
/// <param name="value">The value to unbox.</param>
/// <param name="typeDescriptor">The type descriptor of the object (optional).</param>
/// <param name="valueName">The name of the object to provide a friendly exception message if the conversion is failed (optional).</param>
template<typename T>
T UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
using Type = std::remove_cvref_t<T>;
return ValueAccessor<Type, TypeInfoRetriver<Type>::Decorator>::UnboxValue(value, typeDescriptor, valueName);
}
/***********************************************************************
Basic Types
***********************************************************************/
template<typename T>
struct ValueAccessor<T*, ITypeInfo::RawPtr>
{
static Value BoxValue(T* object, ITypeDescriptor* typeDescriptor)
{
return Value::From(object);
}
static T* UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
if(value.IsNull()) return nullptr;
T* result = nullptr;
if (value.GetRawPtr())
{
result = value.GetRawPtr()->SafeAggregationCast<T>();
}
if(!result)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if(!typeDescriptor)
{
typeDescriptor=GetTypeDescriptor<T>();
}
throw ArgumentTypeMismtatchException(valueName, typeDescriptor, Value::RawPtr, value);
#else
CHECK_FAIL(L"vl::reflection::description::UnboxValue()#Argument type mismatch.");
#endif
}
return result;
}
};
template<typename T>
struct ValueAccessor<Ptr<T>, ITypeInfo::SharedPtr>
{
static Value BoxValue(Ptr<T> object, ITypeDescriptor* typeDescriptor)
{
return Value::From(object);
}
static Ptr<T> UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
if (value.IsNull()) return nullptr;
Ptr<T> result;
if(value.GetValueType()==Value::RawPtr || value.GetValueType()==Value::SharedPtr)
{
result = Ptr(value.GetRawPtr()->SafeAggregationCast<T>());
}
if(!result)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if(!typeDescriptor)
{
typeDescriptor=GetTypeDescriptor<T>();
}
throw ArgumentTypeMismtatchException(valueName, typeDescriptor, Value::SharedPtr, value);
#else
CHECK_FAIL(L"vl::reflection::description::UnboxValue()#Argument type mismatch.");
#endif
}
return result;
}
};
template<typename T>
struct ValueAccessor<Nullable<T>, ITypeInfo::Nullable>
{
static Value BoxValue(Nullable<T> object, ITypeDescriptor* typeDescriptor)
{
return object?ValueAccessor<T, ITypeInfo::TypeDescriptor>::BoxValue(object.Value(), typeDescriptor):Value();
}
static Nullable<T> UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
if(value.IsNull())
{
return Nullable<T>();
}
else
{
return ValueAccessor<T, ITypeInfo::TypeDescriptor>::UnboxValue(value, typeDescriptor, valueName);
}
}
};
template<typename T>
struct ValueAccessor<T, ITypeInfo::TypeDescriptor>
{
static Value BoxValue(const T& object, ITypeDescriptor* typeDescriptor)
{
using Type = std::remove_cvref_t<T>;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if(!typeDescriptor)
{
typeDescriptor = GetTypeDescriptor<Type>();
}
#endif
return Value::From(Ptr(new IValueType::TypedBox<Type>(object)), typeDescriptor);
}
static T UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
using Type = std::remove_cvref_t<T>;
if (auto unboxedValue = value.GetBoxedValue().Cast<IValueType::TypedBox<Type>>())
{
return unboxedValue->value;
}
else
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if (!typeDescriptor)
{
typeDescriptor = GetTypeDescriptor<Type>();
}
throw ArgumentTypeMismtatchException(valueName, typeDescriptor, Value::BoxedValue, value);
#else
CHECK_FAIL(L"vl::reflection::description::UnboxValue()#Argument type mismatch.");
#endif
}
}
};
template<>
struct ValueAccessor<Value, ITypeInfo::TypeDescriptor>
{
static Value BoxValue(const Value& object, ITypeDescriptor* typeDescriptor)
{
return object;
}
static Value UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return value;
}
};
template<>
struct ValueAccessor<VoidValue, ITypeInfo::TypeDescriptor>
{
static Value BoxValue(const VoidValue& object, ITypeDescriptor* typeDescriptor)
{
return Value();
}
static VoidValue UnboxValue(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return VoidValue();
}
};
}
}
}
#endif
/***********************************************************************
.\BOXING\BOXINGPARAMETER.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_BOXING_BOXINGPARAMETER
#define VCZH_REFLECTION_BOXING_BOXINGPARAMETER
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
BoxParameter, UnboxParameter
***********************************************************************/
template<typename T, TypeFlags Flag>
struct ParameterAccessor
{
};
/// <summary>Box an reflectable object. It supports generic types such as containers, functions (should be Func&lt;T&gt;), etc.</summary>
/// <returns>The boxed value.</returns>
/// <typeparam name="T">Type of the object.</typeparam>
/// <param name="object">The object to box.</param>
/// <param name="typeDescriptor">The type descriptor of the object (optional).</param>
template<typename T>
Value BoxParameter(T&& object, ITypeDescriptor* typeDescriptor)
{
using TIR = TypeInfoRetriver<std::remove_reference_t<T>>;
return ParameterAccessor<std::remove_reference_t<T>, TIR::TypeFlag>::BoxParameter(object, typeDescriptor);
}
/// <summary>Box an reflectable object. It supports generic types such as containers, functions (should be Func&lt;T&gt;), etc.</summary>
/// <typeparam name="T">Type of the object.</typeparam>
/// <returns>The unboxed object. It could be the same object that is boxed, or it could be a new object.</returns>
/// <param name="value">The value to unbox.</param>
/// <param name="typeDescriptor">The type descriptor of the object (optional).</param>
/// <param name="valueName">The name of the object to provide a friendly exception message if the conversion is failed (optional).</param>
template<typename T>
Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor , const WString& valueName)
{
using TIR = TypeInfoRetriver<std::remove_reference_t<T>>;
return ParameterAccessor<T, TIR::TypeFlag>::UnboxParameter(value, typeDescriptor, valueName);
}
/***********************************************************************
BoxParametersToList
***********************************************************************/
inline void BoxParametersToList(Ptr<IValueList> arguments) {}
template<typename T0, typename ...TArgs>
void BoxParametersToList(Ptr<IValueList> arguments, T0&& p0, TArgs&& ...args)
{
arguments->Add(description::BoxParameter(p0));
BoxParametersToList(arguments, args...);
}
class Value_xs
{
protected:
collections::Array<Value> arguments;
public:
Value_xs()
{
}
template<typename T>
Value_xs& operator,(T& value)
{
arguments.Resize(arguments.Count() + 1);
arguments[arguments.Count() - 1] = BoxParameter(value);
return *this;
}
Value_xs& operator,(const Value& value)
{
arguments.Resize(arguments.Count() + 1);
arguments[arguments.Count() - 1] = value;
return *this;
}
operator collections::Array<Value>& ()
{
return arguments;
}
};
/***********************************************************************
Basic Types
***********************************************************************/
template<typename T>
struct ParameterAccessor<T, TypeFlags::NonGenericType>
{
static Value BoxParameter(const T& object, ITypeDescriptor* typeDescriptor)
{
return BoxValue<T>(object, typeDescriptor);
}
static Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return { new T(std::move(UnboxValue<T>(value, typeDescriptor, valueName))), true };
}
};
}
}
}
#endif
/***********************************************************************
.\BOXING\INVOKEWITHBOXEDPARAMETERS.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_BOXING_INVOKEWITHBOXEDPARAMETERS
#define VCZH_REFLECTION_BOXING_INVOKEWITHBOXEDPARAMETERS
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
UnboxAndCall
***********************************************************************/
namespace unboxcall_helper
{
template<typename T, vint I>
struct ArgPack
{
using TArg = T;
static const vint Index = I;
};
template<typename ...TArgs>
struct ArgPacks
{
};
template<typename TArgPacks, typename ...TArgs>
struct MakeArgPacks_;
template<typename ...TPacked>
struct MakeArgPacks_<ArgPacks<TPacked...>>
{
using Type = ArgPacks<TPacked...>;
};
template<typename ...TPacked, typename T0, typename ...TArgs>
struct MakeArgPacks_<ArgPacks<TPacked...>, T0, TArgs...>
{
using Type = typename MakeArgPacks_<ArgPacks<TPacked..., ArgPack<T0, sizeof...(TPacked)>>, TArgs...>::Type;
};
}
template<typename ...TArgs>
using MakeArgPacks = typename unboxcall_helper::MakeArgPacks_<unboxcall_helper::ArgPacks<>, TArgs...>::Type;
namespace unboxcall_helper
{
template<typename TArgPacks>
struct Unbox;
template<typename ...TArgPacks>
struct Unbox<ArgPacks<TArgPacks...>>
{
template<typename TFunction>
static auto AndCallObject(TFunction&& function, IMethodInfo* methodInfo, const Ptr<IValueReadonlyList>& arguments) -> decltype(function(std::declval<typename TArgPacks::TArg>()...))
{
// function(arguments)
return function(UnboxParameter<std::remove_cvref_t<typename TArgPacks::TArg>>(
arguments->Get(TArgPacks::Index),
(methodInfo ? methodInfo->GetParameter(TArgPacks::Index)->GetType()->GetTypeDescriptor() : nullptr)
).Ref()...);
}
template<typename TFunction>
static auto AndCallFunction(TFunction function, IMethodInfo* methodInfo, collections::Array<Value>& arguments) -> decltype(function(std::declval<typename TArgPacks::TArg>()...))
{
// function(arguments)
return function(UnboxParameter<std::remove_cvref_t<typename TArgPacks::TArg>>(
arguments[TArgPacks::Index],
(methodInfo ? methodInfo->GetParameter(TArgPacks::Index)->GetType()->GetTypeDescriptor() : nullptr)
).Ref()...);
}
template<typename TClass, typename TFunction>
static auto AndCallMethod(TFunction function, IMethodInfo* methodInfo, collections::Array<Value>& arguments, TClass* object) -> decltype((object->*function)(std::declval<typename TArgPacks::TArg>()...))
{
// (object->*function)(arguments)
return (object->*function)(UnboxParameter<std::remove_cvref_t<typename TArgPacks::TArg>>(
arguments[TArgPacks::Index],
(methodInfo ? methodInfo->GetParameter(TArgPacks::Index)->GetType()->GetTypeDescriptor() : nullptr)
).Ref()...);
}
template<typename TClass, typename TFunction>
static auto AndCallExternal(TFunction function, IMethodInfo* methodInfo, collections::Array<Value>& arguments, TClass* object) -> decltype(function(object, std::declval<typename TArgPacks::TArg>()...))
{
// function(object, arguments)
return function(
object,
UnboxParameter<std::remove_cvref_t<typename TArgPacks::TArg>>(
arguments[TArgPacks::Index],
(methodInfo ? methodInfo->GetParameter(TArgPacks::Index)->GetType()->GetTypeDescriptor() : nullptr)
).Ref()...
);
}
template<typename TClass, typename R>
static R AndNew(IMethodInfo* methodInfo, collections::Array<Value>& arguments)
{
// new TClass(arguments)
return R(new TClass(UnboxParameter<std::remove_cvref_t<typename TArgPacks::TArg>>(
arguments[TArgPacks::Index],
(methodInfo ? methodInfo->GetParameter(TArgPacks::Index)->GetType()->GetTypeDescriptor() : nullptr)
).Ref()...));
}
};
}
/***********************************************************************
Invoke
***********************************************************************/
namespace invoke_helper
{
template<typename TClass, typename R, typename ...TArgs>
Value InvokeMethod(TClass* object, R(__thiscall TClass::* method)(TArgs...), IMethodInfo* methodInfo, collections::Array<Value>& arguments)
{
using TArgPacks = MakeArgPacks<TArgs...>;
if constexpr (std::is_same_v<R, void>)
{
unboxcall_helper::Unbox<TArgPacks>::AndCallMethod(method, methodInfo, arguments, object);
return {};
}
else
{
auto td = methodInfo ? methodInfo->GetReturn()->GetTypeDescriptor() : nullptr;
return BoxParameter(unboxcall_helper::Unbox<TArgPacks>::AndCallMethod(method, methodInfo, arguments, object), td);
}
}
template<typename TClass, typename R, typename ...TArgs>
Value InvokeExternal(TClass* object, R(*method)(TClass*, TArgs...), IMethodInfo* methodInfo, collections::Array<Value>& arguments)
{
using TArgPacks = MakeArgPacks<TArgs...>;
if constexpr (std::is_same_v<R, void>)
{
unboxcall_helper::Unbox<TArgPacks>::AndCallExternal(method, methodInfo, arguments, object);
return {};
}
else
{
auto td = methodInfo ? methodInfo->GetReturn()->GetTypeDescriptor() : nullptr;
return BoxParameter(unboxcall_helper::Unbox<TArgPacks>::AndCallExternal(method, methodInfo, arguments, object), td);
}
}
template<typename R, typename ...TArgs>
Value InvokeFunction(R(*method)(TArgs...), IMethodInfo* methodInfo, collections::Array<Value>& arguments)
{
using TArgPacks = MakeArgPacks<TArgs...>;
if constexpr (std::is_same_v<R, void>)
{
unboxcall_helper::Unbox<TArgPacks>::AndCallFunction(method, methodInfo, arguments);
return {};
}
else
{
auto td = methodInfo ? methodInfo->GetReturn()->GetTypeDescriptor() : nullptr;
return BoxParameter(unboxcall_helper::Unbox<TArgPacks>::AndCallFunction(method, methodInfo, arguments), td);
}
}
template<typename TFunction, typename ...TArgs>
Value InvokeObject(TFunction& function, IMethodInfo* methodInfo, const Ptr<IValueReadonlyList>& arguments)
{
using TArgPacks = MakeArgPacks<TArgs...>;
using TResult = decltype(unboxcall_helper::Unbox<TArgPacks>::AndCallObject(function, methodInfo, arguments));
if constexpr (std::is_same_v<TResult, void>)
{
unboxcall_helper::Unbox<TArgPacks>::AndCallObject(function, methodInfo, arguments);
return {};
}
else
{
auto td = methodInfo ? methodInfo->GetReturn()->GetTypeDescriptor() : nullptr;
return BoxParameter(unboxcall_helper::Unbox<TArgPacks>::AndCallObject(function, methodInfo, arguments), td);
}
}
}
}
}
}
#endif
/***********************************************************************
.\WRAPPERS\CONTAINERWRAPPERS.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_WRAPPERS_CONTAINERWRAPPERS
#define VCZH_REFLECTION_WRAPPERS_CONTAINERWRAPPERS
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
Enumerable Wrappers
***********************************************************************/
template<typename T>
class TypedEnumerator : public Object, public collections::IEnumerator<T>
{
private:
Ptr<IValueEnumerable> enumerable;
Ptr<IValueEnumerator> enumerator;
vint index;
T value;
public:
TypedEnumerator(Ptr<IValueEnumerable> _enumerable, vint _index, const T& _value)
:enumerable(_enumerable)
,index(_index)
,value(_value)
{
enumerator=enumerable->CreateEnumerator();
vint current=-1;
while(current++<index)
{
enumerator->Next();
}
}
TypedEnumerator(Ptr<IValueEnumerable> _enumerable)
:enumerable(_enumerable)
,index(-1)
{
Reset();
}
collections::IEnumerator<T>* Clone()const override
{
return new TypedEnumerator<T>(enumerable, index, value);
}
const T& Current()const override
{
return value;
}
vint Index()const override
{
return index;
}
bool Next() override
{
if(enumerator->Next())
{
index++;
value=UnboxValue<T>(enumerator->GetCurrent());
return true;
}
else
{
return false;
}
}
void Reset() override
{
index=-1;
enumerator=enumerable->CreateEnumerator();
}
};
/// <summary>Convert a reflectable container to a lazy list to the known element type.</summary>
/// <returns>The created lazy list.</returns>
/// <typeparam name="T">The expected element type.</typeparam>
/// <param name="value">The reflectable container.</param>
template<typename T>
collections::LazyList<T> GetLazyList(Ptr<IValueEnumerable> value)
{
return collections::LazyList<T>(new TypedEnumerator<T>(value));
}
/// <summary>Convert a reflectable container to a lazy list to the known element type.</summary>
/// <returns>The created lazy list.</returns>
/// <typeparam name="T">The expected element type.</typeparam>
/// <param name="value">The reflectable container.</param>
template<typename T>
collections::LazyList<T> GetLazyList(Ptr<IValueReadonlyList> value)
{
return collections::Range<vint>(0, value->GetCount())
.Select([value](vint i)
{
return UnboxValue<T>(value->Get(i));
});
}
/// <summary>Convert a reflectable container to a lazy list to the known element type.</summary>
/// <returns>The created lazy list.</returns>
/// <typeparam name="T">The expected element type.</typeparam>
/// <param name="value">The reflectable container.</param>
template<typename T>
collections::LazyList<T> GetLazyList(Ptr<IValueArray> value)
{
return GetLazyList<T>(Ptr<IValueReadonlyList>(value));
}
/// <summary>Convert a reflectable container to a lazy list to the known element type.</summary>
/// <returns>The created lazy list.</returns>
/// <typeparam name="T">The expected element type.</typeparam>
/// <param name="value">The reflectable container.</param>
template<typename T>
collections::LazyList<T> GetLazyList(Ptr<IValueList> value)
{
return GetLazyList<T>(Ptr<IValueReadonlyList>(value));
}
/// <summary>Convert a reflectable container to a lazy list to the known element type.</summary>
/// <returns>The created lazy list.</returns>
/// <typeparam name="T">The expected element type.</typeparam>
/// <param name="value">The reflectable container.</param>
template<typename T>
collections::LazyList<T> GetLazyList(Ptr<IValueObservableList> value)
{
return GetLazyList<T>(Ptr<IValueReadonlyList>(value));
}
/// <summary>Convert a reflectable dictionary to a lazy list to the known element type.</summary>
/// <returns>The created lazy list.</returns>
/// <typeparam name="K">The expected key type.</typeparam>
/// <typeparam name="V">The expected value type.</typeparam>
/// <param name="value">The reflectable dictionary.</param>
template<typename K, typename V>
collections::LazyList<collections::Pair<K, V>> GetLazyList(Ptr<IValueReadonlyDictionary> value)
{
return collections::Range<vint>(0, value->GetCount())
.Select([value](vint i)
{
return collections::Pair<K, V>(UnboxValue<K>(value->GetKeys()->Get(i)), UnboxValue<V>(value->GetValues()->Get(i)));
});
}
/// <summary>Convert a reflectable dictionary to a lazy list to the known element type.</summary>
/// <returns>The created lazy list.</returns>
/// <typeparam name="K">The expected key type.</typeparam>
/// <typeparam name="V">The expected value type.</typeparam>
/// <param name="value">The reflectable dictionary.</param>
template<typename K, typename V>
collections::LazyList<collections::Pair<K, V>> GetLazyList(Ptr<IValueDictionary> value)
{
return GetLazyList<K, V>(Ptr<IValueReadonlyDictionary>(value));
}
/***********************************************************************
Collection Wrappers
***********************************************************************/
namespace trait_helper
{
template<typename T>
struct RemovePtr
{
typedef T Type;
};
template<typename T>
struct RemovePtr<T*>
{
typedef T Type;
};
template<typename T>
struct RemovePtr<Ptr<T>>
{
typedef T Type;
};
}
#pragma warning(push)
#pragma warning(disable:4250)
template<typename T>
class ValueEnumerableWrapper;
template<typename TWrapper, typename TEnumerator>
class ValueEnumeratorWrapper : public Object, public virtual IValueEnumerator
{
protected:
typedef typename trait_helper::RemovePtr<TEnumerator>::Type ContainerType;
typedef typename ContainerType::ElementType ElementType;
Ptr<TWrapper> enumerableWrapper;
TEnumerator wrapperPointer;
public:
ValueEnumeratorWrapper(const Ptr<TWrapper>& _enumerableWrapper, const TEnumerator& _wrapperPointer)
:enumerableWrapper(_enumerableWrapper)
, wrapperPointer(_wrapperPointer)
{
}
Value GetCurrent()override
{
if (!enumerableWrapper->wrapperPointer) throw ObjectDisposedException();
return BoxValue<ElementType>(wrapperPointer->Current());
}
vint GetIndex()override
{
if (!enumerableWrapper->wrapperPointer) throw ObjectDisposedException();
return wrapperPointer->Index();
}
bool Next()override
{
if (!enumerableWrapper->wrapperPointer) throw ObjectDisposedException();
return wrapperPointer->Next();
}
};
#define WRAPPER_POINTER this->wrapperPointer
#define ENSURE_WRAPPER_POINTER if (!WRAPPER_POINTER) throw ObjectDisposedException()
template<typename T>
class ValueEnumerableWrapper : public Object, public virtual collections::ICollectionReference, public virtual IValueEnumerable
{
template<typename TWrapper, typename TEnumerator>
friend class ValueEnumeratorWrapper;
protected:
typedef typename trait_helper::RemovePtr<T>::Type ContainerType;
typedef typename ContainerType::ElementType ElementType;
T wrapperPointer;
public:
ValueEnumerableWrapper(const T& _wrapperPointer)
:wrapperPointer(_wrapperPointer)
{
}
void OnDisposed()override
{
wrapperPointer = nullptr;
}
Ptr<IValueEnumerator> CreateEnumerator()override
{
ENSURE_WRAPPER_POINTER;
return Ptr(new ValueEnumeratorWrapper<
ValueEnumerableWrapper<T>,
Ptr<collections::IEnumerator<ElementType>>
>(
Ptr(this),
Ptr(wrapperPointer->CreateEnumerator())
));
}
const Object* GetCollectionObject()override
{
if constexpr (std::is_same_v<typename trait_helper::RemovePtr<T>::Type*, T>)
{
if (wrapperPointer->GetCollectionReference() == this)
{
return wrapperPointer;
}
else
{
return nullptr;
}
}
else
{
return nullptr;
}
}
};
template<typename T>
class ValueReadonlyListWrapper : public ValueEnumerableWrapper<T>, public virtual IValueReadonlyList
{
protected:
typedef typename trait_helper::RemovePtr<T>::Type ContainerType;
typedef typename ContainerType::ElementType ElementType;
typedef typename KeyType<ElementType>::Type ElementKeyType;
public:
ValueReadonlyListWrapper(const T& _wrapperPointer)
:ValueEnumerableWrapper<T>(_wrapperPointer)
{
}
vint GetCount()override
{
ENSURE_WRAPPER_POINTER;
return WRAPPER_POINTER->Count();
}
Value Get(vint index)override
{
ENSURE_WRAPPER_POINTER;
return BoxValue<ElementType>(WRAPPER_POINTER->Get(index));
}
bool Contains(const Value& value)override
{
ENSURE_WRAPPER_POINTER;
ElementKeyType item = UnboxValue<ElementKeyType>(value);
return WRAPPER_POINTER->Contains(item);
}
vint IndexOf(const Value& value)override
{
ENSURE_WRAPPER_POINTER;
ElementKeyType item = UnboxValue<ElementKeyType>(value);
return WRAPPER_POINTER->IndexOf(item);
}
};
template<typename T>
class ValueArrayWrapper : public ValueReadonlyListWrapper<T>, public virtual IValueArray
{
protected:
typedef typename trait_helper::RemovePtr<T>::Type ContainerType;
typedef typename ContainerType::ElementType ElementType;
typedef typename KeyType<ElementType>::Type ElementKeyType;
public:
ValueArrayWrapper(const T& _wrapperPointer)
:ValueReadonlyListWrapper<T>(_wrapperPointer)
{
}
void Set(vint index, const Value& value)override
{
ENSURE_WRAPPER_POINTER;
ElementType item = UnboxValue<ElementType>(value);
WRAPPER_POINTER->Set(index, item);
}
void Resize(vint size)override
{
ENSURE_WRAPPER_POINTER;
return WRAPPER_POINTER->Resize(size);
}
};
template<typename T>
class ValueListWrapper : public ValueReadonlyListWrapper<T>, public virtual IValueList
{
protected:
typedef typename trait_helper::RemovePtr<T>::Type ContainerType;
typedef typename ContainerType::ElementType ElementType;
typedef typename KeyType<ElementType>::Type ElementKeyType;
public:
ValueListWrapper(const T& _wrapperPointer)
:ValueReadonlyListWrapper<T>(_wrapperPointer)
{
}
void Set(vint index, const Value& value)override
{
ENSURE_WRAPPER_POINTER;
ElementType item = UnboxValue<ElementType>(value);
WRAPPER_POINTER->Set(index, item);
}
vint Add(const Value& value)override
{
ENSURE_WRAPPER_POINTER;
ElementType item = UnboxValue<ElementType>(value);
return WRAPPER_POINTER->Add(item);
}
vint Insert(vint index, const Value& value)override
{
ENSURE_WRAPPER_POINTER;
ElementType item = UnboxValue<ElementType>(value);
return WRAPPER_POINTER->Insert(index, item);
}
bool Remove(const Value& value)override
{
ENSURE_WRAPPER_POINTER;
ElementKeyType item = UnboxValue<ElementKeyType>(value);
return WRAPPER_POINTER->Remove(item);
}
bool RemoveAt(vint index)override
{
ENSURE_WRAPPER_POINTER;
return WRAPPER_POINTER->RemoveAt(index);
}
void Clear()override
{
ENSURE_WRAPPER_POINTER;
WRAPPER_POINTER->Clear();
}
};
template<typename T>
class ValueObservableListWrapper : public ValueListWrapper<T>, public virtual IValueObservableList
{
public:
ValueObservableListWrapper(const T& _wrapperPointer)
:ValueListWrapper<T>(_wrapperPointer)
{
}
};
template<typename T>
class ValueReadonlyDictionaryWrapper : public virtual Object, public virtual collections::ICollectionReference, public virtual IValueReadonlyDictionary
{
protected:
typedef typename trait_helper::RemovePtr<T>::Type ContainerType;
typedef typename ContainerType::KeyContainer KeyContainer;
typedef typename ContainerType::ValueContainer ValueContainer;
typedef typename KeyContainer::ElementType KeyValueType;
typedef typename KeyType<KeyValueType>::Type KeyKeyType;
typedef typename ValueContainer::ElementType ValueType;
T wrapperPointer;
Ptr<IValueReadonlyList> keys;
Ptr<IValueReadonlyList> values;
public:
ValueReadonlyDictionaryWrapper(const T& _wrapperPointer)
:wrapperPointer(_wrapperPointer)
{
}
void OnDisposed()override
{
wrapperPointer = nullptr;
keys = nullptr;
values = nullptr;
}
Ptr<IValueReadonlyList> GetKeys()override
{
ENSURE_WRAPPER_POINTER;
if (!keys)
{
keys = UnboxValue<Ptr<IValueReadonlyList>>(BoxParameter(wrapperPointer->Keys()));
}
return keys;
}
Ptr<IValueReadonlyList> GetValues()override
{
ENSURE_WRAPPER_POINTER;
if (!values)
{
values = UnboxValue<Ptr<IValueReadonlyList>>(BoxParameter(wrapperPointer->Values()));
}
return values;
}
vint GetCount()override
{
ENSURE_WRAPPER_POINTER;
return wrapperPointer->Count();
}
Value Get(const Value& key)override
{
ENSURE_WRAPPER_POINTER;
KeyKeyType item = UnboxValue<KeyKeyType>(key);
ValueType result = wrapperPointer->Get(item);
return BoxValue<ValueType>(result);
}
const Object* GetCollectionObject()override
{
if constexpr (std::is_same_v<typename trait_helper::RemovePtr<T>::Type*, T>)
{
if (wrapperPointer->GetCollectionReference() == this)
{
return wrapperPointer;
}
else
{
return nullptr;
}
}
else
{
return nullptr;
}
}
};
#define KEY_VALUE_TYPE typename ValueReadonlyDictionaryWrapper<T>::KeyValueType
#define VALUE_TYPE typename ValueReadonlyDictionaryWrapper<T>::ValueType
#define KEY_KEY_TYPE typename ValueReadonlyDictionaryWrapper<T>::KeyKeyType
template<typename T>
class ValueDictionaryWrapper : public virtual ValueReadonlyDictionaryWrapper<T>, public virtual IValueDictionary
{
public:
ValueDictionaryWrapper(const T& _wrapperPointer)
:ValueReadonlyDictionaryWrapper<T>(_wrapperPointer)
{
}
void Set(const Value& key, const Value& value)override
{
ENSURE_WRAPPER_POINTER;
KEY_VALUE_TYPE item = UnboxValue<KEY_VALUE_TYPE>(key);
VALUE_TYPE result = UnboxValue<VALUE_TYPE>(value);
WRAPPER_POINTER->Set(item, result);
}
bool Remove(const Value& key)override
{
ENSURE_WRAPPER_POINTER;
KEY_KEY_TYPE item = UnboxValue<KEY_KEY_TYPE>(key);
return WRAPPER_POINTER->Remove(item);
}
void Clear()override
{
ENSURE_WRAPPER_POINTER;
WRAPPER_POINTER->Clear();
}
};
#undef KEY_VALUE_TYPE
#undef VALUE_TYPE
#undef KEY_KEY_TYPE
#undef ENSURE_WRAPPER_POINTER
#undef WRAPPER_POINTER
#pragma warning(pop)
}
}
namespace collections
{
template<typename T>
void ObservableList<T>::NotifyUpdateInternal(vint start, vint count, vint newCount)
{
if (auto colref = this->template TryGetCollectionReference<reflection::description::IValueObservableList>())
{
colref->ItemChanged(start, count, newCount);
}
}
}
}
#endif
/***********************************************************************
.\BOXING\BOXINGPARAMETER_CONTAINERS.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_BOXING_BOXINGPARAMETER_CONTAINERS
#define VCZH_REFLECTION_BOXING_BOXINGPARAMETER_CONTAINERS
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
Containers
***********************************************************************/
template<typename TValueItf, typename TExpectedItf, template<typename T> class TValueImpl, typename T>
auto GetValueCollectionFromCollection(T* collection) -> std::enable_if_t<std::is_convertible_v<TValueItf*, TExpectedItf*>, Ptr<TExpectedItf>>
{
auto colref = collection->template TryGetCollectionReference<TValueImpl<T*>>();
if (colref) return colref;
colref = Ptr(new TValueImpl<T*>(collection));
collection->SetCollectionReference(colref);
return colref;
}
template<typename TValueItf, typename TExpectedItf, template<typename T> class TValueImpl, typename T>
auto GetValueCollectionFromCollection(T* collection) -> std::enable_if_t<!std::is_convertible_v<TValueItf*, TExpectedItf*>, Ptr<TExpectedItf>>
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
throw ArgumentTypeMismtatchException(
WString::Unmanaged(L"collection"),
Description<TExpectedItf>::GetAssociatedTypeDescriptor(),
Description<TValueItf>::GetAssociatedTypeDescriptor()
);
#else
CHECK_FAIL(L"vl::reflection::description::GetValueCollectionFromCollection()#Argument type mismatch.");
#endif
}
template<typename TValueItf, typename T>
Ptr<TValueItf> ChooseValueCollectionFromNonDictionaryEnumerable(const collections::IEnumerable<T>* enumerable)
{
auto writable = const_cast<Object*>(enumerable->GetCollectionObject());
if (auto xs = dynamic_cast<collections::ObservableList<std::remove_cvref_t<T>>*>(writable))
{
return GetValueCollectionFromCollection<IValueObservableList, TValueItf, ValueObservableListWrapper>(xs);
}
else if (auto xs = dynamic_cast<collections::ObservableListBase<std::remove_cvref_t<T>>*>(writable))
{
return GetValueCollectionFromCollection<IValueList, TValueItf, ValueListWrapper>(xs);
}
else if (auto xs = dynamic_cast<collections::List<std::remove_cvref_t<T>>*>(writable))
{
return GetValueCollectionFromCollection<IValueList, TValueItf, ValueListWrapper>(xs);
}
else if (auto xs = dynamic_cast<collections::Array<std::remove_cvref_t<T>>*>(writable))
{
return GetValueCollectionFromCollection<IValueArray, TValueItf, ValueArrayWrapper>(xs);
}
else if (auto xs = dynamic_cast<collections::SortedList<std::remove_cvref_t<T>>*>(writable))
{
return GetValueCollectionFromCollection<IValueReadonlyList, TValueItf, ValueReadonlyListWrapper>(xs);
}
else
{
return GetValueCollectionFromCollection<IValueEnumerable, TValueItf, ValueEnumerableWrapper>(xs);
}
}
template<typename TValueItf, typename T>
Ptr<TValueItf> ChooseValueCollectionFromEnumerable(const collections::IEnumerable<T>* enumerable)
{
return ChooseValueCollectionFromNonDictionaryEnumerable<TValueItf>(enumerable);
}
template<typename TValueItf, typename K, typename V>
Ptr<TValueItf> ChooseValueCollectionFromEnumerable(const collections::IEnumerable<collections::Pair<K, V>>* enumerable)
{
auto writable = const_cast<Object*>(enumerable->GetCollectionObject());
if (auto xs = dynamic_cast<collections::Dictionary<std::remove_cvref_t<K>, std::remove_cvref_t<V>>*>(writable))
{
return GetValueCollectionFromCollection<IValueDictionary, TValueItf, ValueDictionaryWrapper>(xs);
}
else
{
return ChooseValueCollectionFromNonDictionaryEnumerable<TValueItf>(enumerable);
}
}
template<typename TValueItf, typename T>
Value GetValueFromEnumerable(const collections::IEnumerable<T>& enumerable)
{
auto result = ChooseValueCollectionFromEnumerable<TValueItf>(&enumerable);
ITypeDescriptor* td = nullptr;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
td = Description<TValueItf>::GetAssociatedTypeDescriptor();
#endif
return BoxValue(result, td);
}
template<typename T, typename TValueItf>
Unboxed<T> UnboxCollection(const Ptr<TValueItf>& colref)
{
using TCollection = std::remove_const_t<T>;
if (auto colobj = dynamic_cast<TCollection*>(const_cast<Object*>(colref->GetCollectionObject())))
{
return { colobj,false };
}
else
{
auto collection = new TCollection();
auto lazyList = GetLazyList<typename TCollection::ElementType>(colref);
collections::CopyFrom(*collection, lazyList);
return { collection, true };
}
}
template<typename T, typename TValueItf>
Unboxed<T> UnboxDictionary(const Ptr<TValueItf>& colref)
{
using TCollection = std::remove_const_t<T>;
if (auto colobj = dynamic_cast<TCollection*>(const_cast<Object*>(colref->GetCollectionObject())))
{
return { colobj,false };
}
else
{
auto collection = new TCollection();
auto lazyList = GetLazyList<
typename TCollection::KeyContainer::ElementType,
typename TCollection::ValueContainer::ElementType
>(colref);
collections::CopyFrom(*collection, lazyList);
return { collection, true };
}
}
template<typename T>
struct ParameterAccessor<const collections::LazyList<T>, TypeFlags::EnumerableType>
{
static Value BoxParameter(const collections::LazyList<T>& object, ITypeDescriptor* typeDescriptor)
{
Ptr<IValueEnumerable> result = IValueEnumerable::Create(
collections::From(object)
.Select([](const T& item)
{
return BoxValue<T>(item);
})
);
ITypeDescriptor* td = nullptr;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
td = Description<IValueEnumerable>::GetAssociatedTypeDescriptor();
#endif
return BoxValue(result, td);
}
};
template<typename T>
struct ParameterAccessor<collections::LazyList<T>, TypeFlags::EnumerableType>
{
static Value BoxParameter(collections::LazyList<T>& object, ITypeDescriptor* typeDescriptor)
{
return ParameterAccessor<const collections::LazyList<T>, TypeFlags::EnumerableType>::BoxParameter(object, typeDescriptor);
}
static Unboxed<collections::LazyList<T>> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
typedef typename collections::LazyList<T>::ElementType ElementType;
Ptr<IValueEnumerable> listProxy = UnboxValue<Ptr<IValueEnumerable>>(value, typeDescriptor, valueName);
return { new collections::LazyList<T>(std::move(GetLazyList<T>(listProxy))), true };
}
};
template<typename T>
struct ParameterAccessor<T, TypeFlags::ReadonlyListType>
{
static Value BoxParameter(T& object, ITypeDescriptor* typeDescriptor)
{
return GetValueFromEnumerable<IValueReadonlyList>(object);
}
static Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return UnboxCollection<T>(UnboxValue<Ptr<IValueReadonlyList>>(value, typeDescriptor, valueName));
}
};
template<typename T>
struct ParameterAccessor<T, TypeFlags::ArrayType>
{
static Value BoxParameter(T& object, ITypeDescriptor* typeDescriptor)
{
return GetValueFromEnumerable<IValueArray>(object);
}
static Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return UnboxCollection<T>(UnboxValue<Ptr<IValueArray>>(value, typeDescriptor, valueName));
}
};
template<typename T>
struct ParameterAccessor<T, TypeFlags::ListType>
{
static Value BoxParameter(T& object, ITypeDescriptor* typeDescriptor)
{
return GetValueFromEnumerable<IValueList>(object);
}
static Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return UnboxCollection<T>(UnboxValue<Ptr<IValueList>>(value, typeDescriptor, valueName));
}
};
template<typename T>
struct ParameterAccessor<T, TypeFlags::ObservableListType>
{
static Value BoxParameter(T& object, ITypeDescriptor* typeDescriptor)
{
return GetValueFromEnumerable<IValueObservableList>(object);
}
static Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return UnboxCollection<T>(UnboxValue<Ptr<IValueObservableList>>(value, typeDescriptor, valueName));
}
};
template<typename T>
struct ParameterAccessor<T, TypeFlags::ReadonlyDictionaryType>
{
static Value BoxParameter(T& object, ITypeDescriptor* typeDescriptor)
{
return GetValueFromEnumerable<IValueReadonlyDictionary>(object);
}
static Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return UnboxDictionary<T>(UnboxValue<Ptr<IValueReadonlyDictionary>>(value, typeDescriptor, valueName));
}
};
template<typename T>
struct ParameterAccessor<T, TypeFlags::DictionaryType>
{
static Value BoxParameter(T& object, ITypeDescriptor* typeDescriptor)
{
return GetValueFromEnumerable<IValueDictionary>(object);
}
static Unboxed<T> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
return UnboxDictionary<T>(UnboxValue<Ptr<IValueDictionary>>(value, typeDescriptor, valueName));
}
};
}
}
}
#endif
/***********************************************************************
.\WRAPPERS\FUNCTIONWRAPPERS.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_WRAPPERS_FUNCTIONWRAPPERS
#define VCZH_REFLECTION_WRAPPERS_FUNCTIONWRAPPERS
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
Function Wrappers
***********************************************************************/
template<typename T>
class ValueFunctionProxyWrapper
{
};
template<typename R, typename ...TArgs>
class ValueFunctionProxyWrapper<R(TArgs...)> : public Object, public virtual IValueFunctionProxy
{
typedef Func<R(TArgs...)> FunctionType;
protected:
FunctionType function;
public:
ValueFunctionProxyWrapper(const FunctionType& _function)
:function(_function)
{
}
FunctionType GetFunction()
{
return function;
}
Value Invoke(Ptr<IValueReadonlyList> arguments)override
{
if (!arguments || arguments->GetCount() != sizeof...(TArgs))
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
throw ArgumentCountMismtatchException();
#else
CHECK_FAIL(L"Argument count mismatch.");
#endif
}
return invoke_helper::InvokeObject<FunctionType, TArgs...>(function, nullptr, arguments);
}
};
}
}
}
#endif
/***********************************************************************
.\BOXING\BOXINGPARAMETER_FUNCTIONS.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_BOXING_BOXINGPARAMETER_FUNCTIONS
#define VCZH_REFLECTION_BOXING_BOXINGPARAMETER_FUNCTIONS
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
Functions
***********************************************************************/
template<typename R, typename ...TArgs>
struct ParameterAccessor<Func<R(TArgs...)>, TypeFlags::FunctionType>
{
static Value BoxParameter(const Func<R(TArgs...)>& object, ITypeDescriptor* typeDescriptor)
{
typedef R(RawFunctionType)(TArgs...);
Ptr<IValueFunctionProxy> result=Ptr(new ValueFunctionProxyWrapper<RawFunctionType>(object));
ITypeDescriptor* td = nullptr;
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
td = Description<IValueFunctionProxy>::GetAssociatedTypeDescriptor();
#endif
return BoxValue<Ptr<IValueFunctionProxy>>(result, td);
}
static Unboxed<Func<R(TArgs...)>> UnboxParameter(const Value& value, ITypeDescriptor* typeDescriptor, const WString& valueName)
{
typedef R(RawFunctionType)(TArgs...);
typedef Func<R(TArgs...)> FunctionType;
typedef ValueFunctionProxyWrapper<RawFunctionType> ProxyType;
if (auto functionProxy = UnboxValue<Ptr<IValueFunctionProxy>>(value, typeDescriptor, valueName))
{
if (auto proxy = functionProxy.Cast<ProxyType>())
{
return { new FunctionType(std::move(proxy->GetFunction())), true };
}
else
{
return { new FunctionType([functionProxy](TArgs ...args)
{
Ptr<IValueList> arguments = IValueList::Create();
BoxParametersToList(arguments, std::forward<TArgs>(args)...);
auto result = functionProxy->Invoke(arguments);
if constexpr (!std::is_same_v<R, void>)
{
auto unboxed = description::UnboxParameter<std::remove_cvref_t<R>>(result);
if (std::is_reference_v<R>)
{
CHECK_ERROR(!unboxed.IsOwned(), L"It is impossible to return a reference from a unboxed value, when the unboxing has to call new T(...).");
}
return unboxed.Ref();
}
}), true };
}
}
else
{
return { new FunctionType(),true };
}
}
};
template<typename R, typename ...TArgs>
struct ParameterAccessor<const Func<R(TArgs...)>, TypeFlags::FunctionType> : ParameterAccessor<Func<R(TArgs...)>, TypeFlags::FunctionType>
{
};
}
}
}
#endif
/***********************************************************************
.\BOXING\BOXING.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_BOXING_BOXING
#define VCZH_REFLECTION_BOXING_BOXING
#endif
/***********************************************************************
.\METADATA\METADATA_MEMBER.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_METADATA_METADATA_MEMBER
#define VCZH_REFLECTION_METADATA_METADATA_MEMBER
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
ConstructorArgumentAdder
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
namespace internal_helper
{
template<typename T>
struct ConstructorArgumentAdder
{
static void Add(MethodInfoImpl* methodInfo, const wchar_t* parameterNames[], vint index)
{
}
};
template<typename T0, typename ...TNextArgs>
struct ConstructorArgumentAdder<TypeTuple<T0, TNextArgs...>>
{
static void Add(MethodInfoImpl* methodInfo, const wchar_t* parameterNames[], vint index)
{
methodInfo->AddParameter(Ptr(new ParameterInfoImpl(methodInfo, parameterNames[index], TypeInfoRetriver<T0>::CreateTypeInfo())));
ConstructorArgumentAdder<TypeTuple<TNextArgs...>>::Add(methodInfo, parameterNames, index + 1);
}
};
}
/***********************************************************************
MethodInfoImpl
***********************************************************************/
template<typename T>
class CustomConstructorInfoImpl{};
template<typename TClass, typename T>
class CustomMethodInfoImpl{};
template<typename TClass, typename T>
class CustomExternalMethodInfoImpl{};
template<typename T>
class CustomStaticMethodInfoImpl{};
template<typename TClass, typename T>
class CustomEventInfoImpl{};
#endif
}
}
}
#endif
/***********************************************************************
.\METADATA\METADATA_EVENT.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_METADATA_METADATA_EVENT
#define VCZH_REFLECTION_METADATA_METADATA_EVENT
namespace vl
{
namespace reflection
{
namespace description
{
template<typename ...TArgs>
struct EventHelper
{
using Handler = const Func<void(TArgs...)>&;
class EventHandlerImpl : public Object, public reflection::description::IEventHandler
{
public:
Ptr<EventHandler> handler;
EventHandlerImpl(Ptr<EventHandler> _handler)
:handler(_handler)
{
}
bool IsAttached()override
{
return handler->IsAttached();
}
};
static Ptr<reflection::description::IEventHandler> Attach(Event<void(TArgs...)>& e, Handler handler)
{
return Ptr(new EventHandlerImpl(e.Add(handler)));
}
static bool Detach(Event<void(TArgs...)>& e, Ptr<reflection::description::IEventHandler> handler)
{
auto impl = handler.Cast<EventHandlerImpl>();
if (!impl) return false;
return e.Remove(impl->handler);
}
static Event<void(TArgs...)>& Invoke(Event<void(TArgs...)>& e)
{
return e;
}
};
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
/***********************************************************************
CustomEventInfoImpl<void(TArgs...)>
***********************************************************************/
template<typename TClass, typename ...TArgs>
class CustomEventInfoImpl<TClass, void(TArgs...)> : public EventInfoImpl
{
protected:
Event<void(TArgs...)> TClass::* eventRef;
Ptr<IEventHandler> AttachInternal(DescriptableObject* thisObject, Ptr<IValueFunctionProxy> handler)override
{
TClass* object = UnboxValue<TClass*>(Value::From(thisObject), GetOwnerTypeDescriptor(), L"thisObject");
Event<void(TArgs...)>& eventObject = object->*eventRef;
auto func = Func<void(TArgs...)>([=](TArgs ...args)
{
auto arguments = IValueList::Create();
BoxParametersToList(arguments, std::forward<TArgs>(args)...);
handler->Invoke(arguments);
});
return EventHelper<TArgs...>::Attach(eventObject, func);
}
bool DetachInternal(DescriptableObject* thisObject, Ptr<IEventHandler> handler)override
{
TClass* object = UnboxValue<TClass*>(Value::From(thisObject), GetOwnerTypeDescriptor(), L"thisObject");
Event<void(TArgs...)>& eventObject = object->*eventRef;
return EventHelper<TArgs...>::Detach(eventObject, handler);
}
void InvokeInternal(DescriptableObject* thisObject, Ptr<IValueReadonlyList> arguments)override
{
TClass* object = UnboxValue<TClass*>(Value::From(thisObject), GetOwnerTypeDescriptor(), L"thisObject");
Event<void(TArgs...)>& eventObject = object->*eventRef;
invoke_helper::InvokeObject<Event<void(TArgs...)>, TArgs...>(eventObject, nullptr, arguments);
}
Ptr<ITypeInfo> GetHandlerTypeInternal()override
{
return TypeInfoRetriver<Func<void(TArgs...)>>::CreateTypeInfo();
}
public:
CustomEventInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, Event<void(TArgs...)> TClass::* _eventRef)
:EventInfoImpl(_ownerTypeDescriptor, _name)
, eventRef(_eventRef)
{
}
~CustomEventInfoImpl()
{
}
IEventInfo::ICpp* GetCpp()override
{
return nullptr;
}
};
template<typename T>
struct CustomEventFunctionTypeRetriver
{
typedef vint Type;
};
template<typename TClass, typename TEvent>
struct CustomEventFunctionTypeRetriver<Event<TEvent> TClass::*>
{
typedef TEvent Type;
};
#endif
}
}
}
#endif
/***********************************************************************
.\METADATA\METADATA_FUNCTION.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_METADATA_METADATA_FUNCTION
#define VCZH_REFLECTION_METADATA_METADATA_FUNCTION
namespace vl
{
namespace reflection
{
namespace description
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
/***********************************************************************
CustomConstructorInfoImpl<R(TArgs...)>
***********************************************************************/
template<typename R, typename ...TArgs>
class CustomConstructorInfoImpl<R(TArgs...)> : public MethodInfoImpl
{
using TClass = typename trait_helper::RemovePtr<std::remove_cvref_t<R>>::Type;
protected:
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override
{
return BoxParameter(unboxcall_helper::Unbox<MakeArgPacks<TArgs...>>::template AndNew<TClass, R>(this, arguments));
}
Value CreateFunctionProxyInternal(const Value& thisObject)override
{
auto proxy = Func([](TArgs ...args)->R
{
R result = R(new TClass(args...));
return result;
});
return BoxParameter(proxy);
}
public:
CustomConstructorInfoImpl(const wchar_t* parameterNames[])
:MethodInfoImpl(0, TypeInfoRetriver<R>::CreateTypeInfo(), true)
{
internal_helper::ConstructorArgumentAdder<TypeTuple<TArgs...>>::Add(this, parameterNames, 0);
}
IMethodInfo::ICpp* GetCpp()override
{
return nullptr;
}
};
/***********************************************************************
CustomMethodInfoImpl<TClass, R(TArgs...)>
CustomExternalMethodInfoImpl<TClass, R(TArgs...)>
***********************************************************************/
class MethodInfoImpl_StaticCpp : public MethodInfoImpl, private IMethodInfo::ICpp
{
private:
WString invokeTemplate;
WString closureTemplate;
const WString& GetInvokeTemplate()override
{
return invokeTemplate;
}
const WString& GetClosureTemplate()override
{
return closureTemplate;
}
public:
MethodInfoImpl_StaticCpp(IMethodGroupInfo* _ownerMethodGroup, Ptr<ITypeInfo> _return, bool _isStatic, const wchar_t* _invokeTemplate, const wchar_t* _closureTemplate)
:MethodInfoImpl(_ownerMethodGroup, _return, _isStatic)
{
CHECK_ERROR((_invokeTemplate == nullptr) == (_closureTemplate == nullptr), L"MethodInfoImpl_StaticCpp::MethodInfoImpl_StaticCpp()#Templates should all be set or default at the same time.");
if (_invokeTemplate)
{
invokeTemplate = WString::Unmanaged(_invokeTemplate);
}
if (_closureTemplate)
{
closureTemplate = WString::Unmanaged(_closureTemplate);
}
}
IMethodInfo::ICpp* GetCpp()override
{
return invokeTemplate.Length() == 0 || closureTemplate.Length() == 0 ? nullptr : this;
}
};
template<typename TClass, typename R, typename ...TArgs>
class CustomMethodInfoImpl<TClass, R(TArgs...)> : public MethodInfoImpl_StaticCpp
{
protected:
R(__thiscall TClass::* method)(TArgs...);
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override
{
TClass* object = UnboxValue<TClass*>(thisObject, GetOwnerTypeDescriptor(), L"thisObject");
return invoke_helper::InvokeMethod<TClass, R, TArgs...>(object, method, this, arguments);
}
Value CreateFunctionProxyInternal(const Value& thisObject)override
{
TClass* object = UnboxValue<TClass*>(thisObject, GetOwnerTypeDescriptor(), L"thisObject");
Func<R(TArgs...)> proxy(object, method);
return BoxParameter(proxy);
}
public:
CustomMethodInfoImpl(const wchar_t* parameterNames[], R(__thiscall TClass::* _method)(TArgs...), const wchar_t* _invokeTemplate, const wchar_t* _closureTemplate)
:MethodInfoImpl_StaticCpp(0, TypeInfoRetriver<R>::CreateTypeInfo(), false, _invokeTemplate, _closureTemplate)
, method(_method)
{
internal_helper::ConstructorArgumentAdder<TypeTuple<TArgs...>>::Add(this, parameterNames, 0);
}
};
template<typename TClass, typename R, typename ...TArgs>
class CustomExternalMethodInfoImpl<TClass, R(TArgs...)> : public MethodInfoImpl_StaticCpp
{
protected:
R(*method)(TClass*, TArgs...);
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override
{
TClass* object = UnboxValue<TClass*>(thisObject, GetOwnerTypeDescriptor(), L"thisObject");
return invoke_helper::InvokeExternal<TClass, R, TArgs...>(object, method, this, arguments);
}
Value CreateFunctionProxyInternal(const Value& thisObject)override
{
TClass* object = UnboxValue<TClass*>(thisObject, GetOwnerTypeDescriptor(), L"thisObject");
auto proxy = Func([object, this](TArgs... args)->decltype(auto) { return method(object, args...); });
return BoxParameter(proxy);
}
public:
CustomExternalMethodInfoImpl(const wchar_t* parameterNames[], R(*_method)(TClass*, TArgs...), const wchar_t* _invokeTemplate, const wchar_t* _closureTemplate)
:MethodInfoImpl_StaticCpp(0, TypeInfoRetriver<R>::CreateTypeInfo(), false, _invokeTemplate, _closureTemplate)
, method(_method)
{
internal_helper::ConstructorArgumentAdder<TypeTuple<TArgs...>>::Add(this, parameterNames, 0);
}
};
/***********************************************************************
CustomStaticMethodInfoImpl<R(TArgs...)>
***********************************************************************/
template<typename R, typename ...TArgs>
class CustomStaticMethodInfoImpl<R(TArgs...)> : public MethodInfoImpl_StaticCpp
{
protected:
R(* method)(TArgs...);
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override
{
return invoke_helper::InvokeFunction<R, TArgs...>(method, this, arguments);
}
Value CreateFunctionProxyInternal(const Value& thisObject)override
{
Func<R(TArgs...)> proxy(method);
return BoxParameter(proxy);
}
public:
CustomStaticMethodInfoImpl(const wchar_t* parameterNames[], R(* _method)(TArgs...), const wchar_t* _invokeTemplate, const wchar_t* _closureTemplate)
:MethodInfoImpl_StaticCpp(0, TypeInfoRetriver<R>::CreateTypeInfo(), true, _invokeTemplate, _closureTemplate)
,method(_method)
{
internal_helper::ConstructorArgumentAdder<TypeTuple<TArgs...>>::Add(this, parameterNames, 0);
}
};
#endif
}
}
}
#endif
/***********************************************************************
.\REFLECTION\MACROS.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_REFLECTION_MACROS
#define VCZH_REFLECTION_REFLECTION_MACROS
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
/***********************************************************************
Macros
***********************************************************************/
namespace vl
{
namespace reflection
{
namespace description
{
template<typename T>
struct CustomTypeDescriptorSelector{};
struct MethodPointerBinaryData
{
typedef collections::Dictionary<MethodPointerBinaryData, IMethodInfo*> MethodMap;
class IIndexer : public virtual IDescriptable
{
public:
virtual void IndexMethodInfo(const MethodPointerBinaryData& data, IMethodInfo* methodInfo) = 0;
virtual IMethodInfo* GetIndexedMethodInfo(const MethodPointerBinaryData& data) = 0;
};
vint data[4];
friend std::strong_ordering operator<=>(const MethodPointerBinaryData& a, const MethodPointerBinaryData& b)
{
for (vint i = 0; i < sizeof(data) / sizeof(*data); i++)
{
auto result = a.data[i] <=> b.data[i];
if (result != 0) return result;
}
return std::strong_ordering::equal;
}
friend bool operator==(const MethodPointerBinaryData& a, const MethodPointerBinaryData& b)
{
return (a <=> b) == 0;
}
};
template<typename T>
union MethodPointerBinaryDataRetriver
{
T methodPointer;
MethodPointerBinaryData binaryData;
MethodPointerBinaryDataRetriver(T _methodPointer)
{
memset(&binaryData, 0, sizeof(binaryData));
methodPointer = _methodPointer;
}
const MethodPointerBinaryData& GetBinaryData()
{
static_assert(sizeof(T) <= sizeof(MethodPointerBinaryData), "Your C++ compiler is bad!");
return binaryData;
}
};
template<typename T, TypeDescriptorFlags TDFlags>
struct MethodPointerBinaryDataRecorder
{
static void RecordMethod(const MethodPointerBinaryData& data, ITypeDescriptor* td, IMethodInfo* methodInfo)
{
}
};
template<typename T>
struct MethodPointerBinaryDataRecorder<T, TypeDescriptorFlags::Interface>
{
static void RecordMethod(const MethodPointerBinaryData& data, ITypeDescriptor* td, IMethodInfo* methodInfo)
{
auto impl = dynamic_cast<MethodPointerBinaryData::IIndexer*>(td);
CHECK_ERROR(impl != nullptr, L"Internal error: RecordMethod can only be called when registering methods.");
impl->IndexMethodInfo(data, methodInfo);
}
};
template<typename T>
using FUNCTIONNAME_AddPointer = T*;
/***********************************************************************
Type
***********************************************************************/
#define BEGIN_TYPE_INFO_NAMESPACE namespace vl{namespace reflection{namespace description{
#define END_TYPE_INFO_NAMESPACE }}}
#define ADD_TYPE_INFO(TYPENAME)\
{\
auto type = Ptr(new CustomTypeDescriptorSelector<TYPENAME>::CustomTypeDescriptorImpl());\
manager->SetTypeDescriptor(TypeInfo<TYPENAME>::content.typeName, type);\
}
/***********************************************************************
InterfaceProxy
***********************************************************************/
#define INTERFACE_PROXY_CTOR_RAWPTR(INTERFACE)\
static INTERFACE* Create(Ptr<IValueInterfaceProxy> proxy)\
{\
auto obj = new ValueInterfaceProxy<INTERFACE>();\
obj->SetProxy(proxy);\
return obj;\
}\
#define INTERFACE_PROXY_CTOR_SHAREDPTR(INTERFACE)\
static Ptr<INTERFACE> Create(Ptr<IValueInterfaceProxy> proxy)\
{\
auto obj = Ptr(new ValueInterfaceProxy<INTERFACE>());\
obj->SetProxy(proxy);\
return obj;\
}\
#define BEGIN_INTERFACE_PROXY_NOPARENT_HEADER(INTERFACE)\
template<>\
class ValueInterfaceProxy<INTERFACE> : public ValueInterfaceImpl<INTERFACE>\
{\
typedef INTERFACE _interface_proxy_InterfaceType;\
public:\
#define BEGIN_INTERFACE_PROXY_NOPARENT_RAWPTR(INTERFACE)\
BEGIN_INTERFACE_PROXY_NOPARENT_HEADER(INTERFACE)\
INTERFACE_PROXY_CTOR_RAWPTR(INTERFACE)\
#define BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(INTERFACE)\
BEGIN_INTERFACE_PROXY_NOPARENT_HEADER(INTERFACE)\
INTERFACE_PROXY_CTOR_SHAREDPTR(INTERFACE)\
#define BEGIN_INTERFACE_PROXY_HEADER(INTERFACE, ...)\
template<>\
class ValueInterfaceProxy<INTERFACE> : public ValueInterfaceImpl<INTERFACE, __VA_ARGS__>\
{\
typedef INTERFACE _interface_proxy_InterfaceType;\
public:\
#define BEGIN_INTERFACE_PROXY_RAWPTR(INTERFACE, ...)\
BEGIN_INTERFACE_PROXY_HEADER(INTERFACE, __VA_ARGS__)\
INTERFACE_PROXY_CTOR_RAWPTR(INTERFACE)\
#define BEGIN_INTERFACE_PROXY_SHAREDPTR(INTERFACE, ...)\
BEGIN_INTERFACE_PROXY_HEADER(INTERFACE, __VA_ARGS__)\
INTERFACE_PROXY_CTOR_SHAREDPTR(INTERFACE)\
#define END_INTERFACE_PROXY(INTERFACE)\
};
/***********************************************************************
InterfaceProxy::Invoke
***********************************************************************/
template<typename TClass, typename TReturn, typename ...TArgument>
auto MethodTypeTrait(TArgument...)->TReturn(TClass::*)(TArgument...)
{
return nullptr;
}
#define PREPARE_INVOKE_INTERFACE_PROXY(METHODNAME, ...)\
static ITypeDescriptor* _interface_proxy_typeDescriptor = nullptr;\
static IMethodInfo* _interface_proxy_methodInfo = nullptr;\
if (_interface_proxy_typeDescriptor != static_cast<DescriptableObject*>(this)->GetTypeDescriptor())\
{\
_interface_proxy_typeDescriptor = static_cast<DescriptableObject*>(this)->GetTypeDescriptor();\
CHECK_ERROR(_interface_proxy_typeDescriptor != nullptr, L"Internal error: The type of this interface has not been registered.");\
auto impl = dynamic_cast<MethodPointerBinaryData::IIndexer*>(_interface_proxy_typeDescriptor);\
CHECK_ERROR(impl != nullptr, L"Internal error: BEGIN_INTERFACE_PROXY is the only correct way to register an interface with a proxy.");\
auto _interface_proxy_method\
= (decltype(MethodTypeTrait<_interface_proxy_InterfaceType, decltype(METHODNAME(__VA_ARGS__))>(__VA_ARGS__)))\
&_interface_proxy_InterfaceType::METHODNAME;\
MethodPointerBinaryDataRetriver<decltype(_interface_proxy_method)> binaryData(_interface_proxy_method);\
_interface_proxy_methodInfo = impl->GetIndexedMethodInfo(binaryData.GetBinaryData());\
}\
#define INVOKE_INTERFACE_PROXY(METHODNAME, ...)\
PREPARE_INVOKE_INTERFACE_PROXY(METHODNAME, __VA_ARGS__)\
proxy->Invoke(_interface_proxy_methodInfo, IValueList::Create(collections::From((collections::Array<Value>&)(Value_xs(), __VA_ARGS__))))
#define INVOKE_INTERFACE_PROXY_NOPARAMS(METHODNAME)\
PREPARE_INVOKE_INTERFACE_PROXY(METHODNAME)\
proxy->Invoke(_interface_proxy_methodInfo, IValueList::Create())
#define INVOKEGET_INTERFACE_PROXY(METHODNAME, ...)\
PREPARE_INVOKE_INTERFACE_PROXY(METHODNAME, __VA_ARGS__)\
return UnboxParameter<decltype(METHODNAME(__VA_ARGS__))>(proxy->Invoke(_interface_proxy_methodInfo, IValueList::Create(collections::From((collections::Array<Value>&)(Value_xs(), __VA_ARGS__))))).Ref()
#define INVOKEGET_INTERFACE_PROXY_NOPARAMS(METHODNAME)\
PREPARE_INVOKE_INTERFACE_PROXY(METHODNAME)\
return UnboxParameter<decltype(METHODNAME())>(proxy->Invoke(_interface_proxy_methodInfo, IValueList::Create())).Ref()
/***********************************************************************
Enum
***********************************************************************/
#define BEGIN_ENUM_ITEM_FLAG(TYPENAME, TDFLAGS)\
template<>\
struct CustomTypeDescriptorSelector<TYPENAME>\
{\
public:\
class CustomTypeDescriptorImpl : public EnumTypeDescriptor<TYPENAME, TDFLAGS>\
{\
typedef TYPENAME EnumType;\
public:\
void LoadInternal()override\
{\
EnumTypeDescriptor<TYPENAME, TDFLAGS>::LoadInternal();\
#define BEGIN_ENUM_ITEM(TYPENAME) BEGIN_ENUM_ITEM_FLAG(TYPENAME, TypeDescriptorFlags::NormalEnum)
#define BEGIN_ENUM_ITEM_MERGABLE(TYPENAME) BEGIN_ENUM_ITEM_FLAG(TYPENAME, TypeDescriptorFlags::FlagEnum)
#define END_ENUM_ITEM(TYPENAME)\
}\
};\
};
#define ENUM_ITEM_NAMESPACE(TYPENAME) typedef TYPENAME EnumItemNamespace;
#define ENUM_ITEM(ITEMNAME) enumType->AddItem(L ## #ITEMNAME, ITEMNAME);
#define ENUM_NAMESPACE_ITEM(ITEMNAME) enumType->AddItem(L ## #ITEMNAME, EnumItemNamespace::ITEMNAME);
#define ENUM_CLASS_ITEM(ITEMNAME) enumType->AddItem(L ## #ITEMNAME, EnumType::ITEMNAME);
/***********************************************************************
Struct
***********************************************************************/
#define BEGIN_STRUCT_MEMBER_FLAG(TYPENAME, TDFLAGS)\
template<>\
struct CustomTypeDescriptorSelector<TYPENAME>\
{\
public:\
class CustomTypeDescriptorImpl : public StructTypeDescriptor<TYPENAME, TDFLAGS>\
{\
typedef TYPENAME StructType;\
protected:\
void LoadInternal()override\
{
#define BEGIN_STRUCT_MEMBER(TYPENAME)\
BEGIN_STRUCT_MEMBER_FLAG(TYPENAME, TypeDescriptorFlags::Struct)
#define END_STRUCT_MEMBER(TYPENAME)\
}\
};\
};
#define STRUCT_MEMBER(FIELDNAME)\
fields.Add(L ## #FIELDNAME, Ptr(new StructFieldInfo<decltype(((StructType*)0)->FIELDNAME)>(this, &StructType::FIELDNAME, L ## #FIELDNAME)));
/***********************************************************************
Class
***********************************************************************/
#define BEGIN_CLASS_MEMBER(TYPENAME)\
template<>\
struct CustomTypeDescriptorSelector<TYPENAME>\
{\
public:\
class CustomTypeDescriptorImpl : public TypeDescriptorImpl\
{\
typedef TYPENAME ClassType;\
static const TypeDescriptorFlags TDFlags = TypeDescriptorFlags::Class;\
public:\
CustomTypeDescriptorImpl()\
:TypeDescriptorImpl(TDFlags, &TypeInfo<TYPENAME>::content)\
{\
Description<TYPENAME>::SetAssociatedTypeDescriptor(this);\
}\
~CustomTypeDescriptorImpl()\
{\
Description<TYPENAME>::SetAssociatedTypeDescriptor(0);\
}\
protected:\
bool IsAggregatable()override\
{\
return std::is_convertible_v<TYPENAME*, AggregatableDescription<TYPENAME>*>;\
}\
void LoadInternal()override\
{
#define CLASS_MEMBER_BASE(TYPENAME)\
AddBaseType(description::GetTypeDescriptor<TYPENAME>());
#define END_CLASS_MEMBER(TYPENAME)\
if (GetBaseTypeDescriptorCount() == 0) CLASS_MEMBER_BASE(DescriptableObject)\
}\
};\
};
/***********************************************************************
Interface
***********************************************************************/
#define BEGIN_INTERFACE_MEMBER_NOPROXY_FLAG(TYPENAME, TDFLAGS)\
template<>\
struct CustomTypeDescriptorSelector<TYPENAME>\
{\
public:\
class CustomTypeDescriptorImpl : public TypeDescriptorImpl, public MethodPointerBinaryData::IIndexer\
{\
typedef TYPENAME ClassType;\
static const TypeDescriptorFlags TDFlags = TDFLAGS;\
MethodPointerBinaryData::MethodMap methodsForProxy;\
public:\
CustomTypeDescriptorImpl()\
:TypeDescriptorImpl(TDFLAGS, &TypeInfo<TYPENAME>::content)\
{\
Description<TYPENAME>::SetAssociatedTypeDescriptor(this);\
}\
~CustomTypeDescriptorImpl()\
{\
Description<TYPENAME>::SetAssociatedTypeDescriptor(0);\
}\
void IndexMethodInfo(const MethodPointerBinaryData& data, IMethodInfo* methodInfo)override\
{\
methodsForProxy.Add(data, methodInfo);\
}\
IMethodInfo* GetIndexedMethodInfo(const MethodPointerBinaryData& data)override\
{\
Load();\
return methodsForProxy[data];\
}\
protected:\
void LoadInternal()override\
{
#define BEGIN_INTERFACE_MEMBER_NOPROXY(TYPENAME)\
BEGIN_INTERFACE_MEMBER_NOPROXY_FLAG(TYPENAME, TypeDescriptorFlags::Interface)
#define BEGIN_INTERFACE_MEMBER(TYPENAME)\
BEGIN_INTERFACE_MEMBER_NOPROXY(TYPENAME)\
CLASS_MEMBER_EXTERNALCTOR(decltype(ValueInterfaceProxy<TYPENAME>::Create(nullptr))(Ptr<IValueInterfaceProxy>), { L"proxy" }, vl::reflection::description::ValueInterfaceProxy<TYPENAME>::Create)
#define END_INTERFACE_MEMBER(TYPENAME)\
if (GetBaseTypeDescriptorCount() == 0 && TDFlags == TypeDescriptorFlags::Interface) CLASS_MEMBER_BASE(IDescriptable)\
}\
};\
};
/***********************************************************************
Field
***********************************************************************/
#define CLASS_MEMBER_FIELD(FIELDNAME)\
AddProperty(\
Ptr(new CustomFieldInfoImpl<\
ClassType,\
decltype(((ClassType*)0)->FIELDNAME)\
>(this, L ## #FIELDNAME, &ClassType::FIELDNAME)\
));
/***********************************************************************
Constructor
***********************************************************************/
#define NO_PARAMETER {L""}
#define PROTECT_PARAMETERS(...) __VA_ARGS__
#define CLASS_MEMBER_CONSTRUCTOR(FUNCTIONTYPE, PARAMETERNAMES)\
{\
const wchar_t* parameterNames[]=PARAMETERNAMES;\
AddConstructor(Ptr(new CustomConstructorInfoImpl<FUNCTIONTYPE>(parameterNames)));\
}
#define CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(FUNCTIONTYPE, PARAMETERNAMES, SOURCE, INVOKETEMPLATE, CLOSURETEMPLATE)\
{\
const wchar_t* parameterNames[]=PARAMETERNAMES;\
AddConstructor(\
Ptr(new CustomStaticMethodInfoImpl<FUNCTIONTYPE>(parameterNames, SOURCE, INVOKETEMPLATE, CLOSURETEMPLATE))\
);\
}
#define CLASS_MEMBER_EXTERNALCTOR(FUNCTIONTYPE, PARAMETERNAMES, SOURCE)\
CLASS_MEMBER_EXTERNALCTOR_TEMPLATE(FUNCTIONTYPE, PROTECT_PARAMETERS(PARAMETERNAMES), (FUNCTIONNAME_AddPointer<FUNCTIONTYPE>)&::SOURCE, L"::" L ## #SOURCE L"($Arguments)", L"::vl::Func<$Func>(&::" L ## #SOURCE L")")
/***********************************************************************
Method
***********************************************************************/
#define CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE, SOURCE, INVOKETEMPLATE, CLOSURETEMPLATE)\
{\
const wchar_t* parameterNames[]=PARAMETERNAMES;\
AddMethod(\
L ## #FUNCTIONNAME,\
Ptr(new CustomExternalMethodInfoImpl<\
ClassType,\
vl::function_lambda::LambdaRetriveType<FUNCTIONTYPE>::FunctionType\
>(parameterNames, SOURCE, INVOKETEMPLATE, CLOSURETEMPLATE))\
);\
}
#define CLASS_MEMBER_EXTERNALMETHOD(FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE, SOURCE)\
CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), FUNCTIONTYPE, &::SOURCE, L"::" L ## #SOURCE L"($This, $Arguments)", L"::vl::Func<$Func>($This, &::" L ## #SOURCE L")")
#define CLASS_MEMBER_METHOD_OVERLOAD_RENAME_TEMPLATE(EXPECTEDNAME, FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE, INVOKETEMPLATE, CLOSURETEMPLATE)\
{\
const wchar_t* parameterNames[]=PARAMETERNAMES;\
auto methodInfo = Ptr(new CustomMethodInfoImpl<\
ClassType,\
vl::function_lambda::LambdaRetriveType<FUNCTIONTYPE>::FunctionType\
>\
(parameterNames, (FUNCTIONTYPE)&ClassType::FUNCTIONNAME, INVOKETEMPLATE, CLOSURETEMPLATE));\
AddMethod(\
L ## #EXPECTEDNAME,\
methodInfo\
);\
MethodPointerBinaryDataRetriver<FUNCTIONTYPE> binaryDataRetriver(&ClassType::FUNCTIONNAME);\
MethodPointerBinaryDataRecorder<ClassType, TDFlags>::RecordMethod(binaryDataRetriver.GetBinaryData(), this, methodInfo.Obj());\
}
#define CLASS_MEMBER_METHOD_OVERLOAD_RENAME(EXPECTEDNAME, FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE)\
CLASS_MEMBER_METHOD_OVERLOAD_RENAME_TEMPLATE(EXPECTEDNAME, FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), FUNCTIONTYPE, L"$This->" L ## #FUNCTIONNAME L"($Arguments)", L"::vl::Func<$Func>($This, &$Type::" L ## #FUNCTIONNAME L")")
#define CLASS_MEMBER_METHOD_OVERLOAD(FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE)\
CLASS_MEMBER_METHOD_OVERLOAD_RENAME_TEMPLATE(FUNCTIONNAME, FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), FUNCTIONTYPE, nullptr, nullptr)
#define CLASS_MEMBER_METHOD_RENAME(EXPECTEDNAME, FUNCTIONNAME, PARAMETERNAMES)\
CLASS_MEMBER_METHOD_OVERLOAD_RENAME(EXPECTEDNAME, FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), decltype(&ClassType::FUNCTIONNAME))
#define CLASS_MEMBER_METHOD(FUNCTIONNAME, PARAMETERNAMES)\
CLASS_MEMBER_METHOD_OVERLOAD(FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), decltype(&ClassType::FUNCTIONNAME))
/***********************************************************************
Static Method
***********************************************************************/
#define CLASS_MEMBER_STATIC_EXTERNALMETHOD_TEMPLATE(FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE, SOURCE, INVOKETEMPLATE, CLOSURETEMPLATE)\
{\
const wchar_t* parameterNames[]=PARAMETERNAMES;\
AddMethod(\
L ## #FUNCTIONNAME,\
Ptr(new CustomStaticMethodInfoImpl<\
std::remove_pointer_t<FUNCTIONTYPE>\
>(parameterNames, (FUNCTIONTYPE)SOURCE, INVOKETEMPLATE, CLOSURETEMPLATE))\
);\
}
#define CLASS_MEMBER_STATIC_EXTERNALMETHOD(FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE, SOURCE)\
CLASS_MEMBER_STATIC_EXTERNALMETHOD_TEMPLATE(FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), FUNCTIONTYPE, &::SOURCE, L"::" L ## #SOURCE L"($Arguments)", L"::vl::Func<$Func>(&::" L ## #SOURCE L")")
#define CLASS_MEMBER_STATIC_METHOD_OVERLOAD(FUNCTIONNAME, PARAMETERNAMES, FUNCTIONTYPE)\
CLASS_MEMBER_STATIC_EXTERNALMETHOD_TEMPLATE(FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), FUNCTIONTYPE, &ClassType::FUNCTIONNAME, nullptr, nullptr)
#define CLASS_MEMBER_STATIC_METHOD(FUNCTIONNAME, PARAMETERNAMES)\
CLASS_MEMBER_STATIC_METHOD_OVERLOAD(FUNCTIONNAME, PROTECT_PARAMETERS(PARAMETERNAMES), decltype(&ClassType::FUNCTIONNAME))
/***********************************************************************
Event
***********************************************************************/
#define CLASS_MEMBER_EVENT(EVENTNAME)\
AddEvent(\
Ptr(new CustomEventInfoImpl<\
ClassType,\
CustomEventFunctionTypeRetriver<decltype(&ClassType::EVENTNAME)>::Type\
>(this, L ## #EVENTNAME, &ClassType::EVENTNAME))\
);
/***********************************************************************
Property
***********************************************************************/
#define CLASS_MEMBER_PROPERTY_READONLY(PROPERTYNAME, GETTER)\
AddProperty(\
Ptr(new PropertyInfoImpl(\
this,\
L ## #PROPERTYNAME,\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #GETTER, true)->GetMethod(0)),\
nullptr,\
nullptr\
))\
);
#define CLASS_MEMBER_PROPERTY(PROPERTYNAME, GETTER, SETTER)\
AddProperty(\
Ptr(new PropertyInfoImpl(\
this,\
L ## #PROPERTYNAME,\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #GETTER, true)->GetMethod(0)),\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #SETTER, true)->GetMethod(0)),\
nullptr\
))\
);
#define CLASS_MEMBER_PROPERTY_EVENT(PROPERTYNAME, GETTER, SETTER, EVENT)\
AddProperty(\
Ptr(new PropertyInfoImpl(\
this,\
L ## #PROPERTYNAME,\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #GETTER, true)->GetMethod(0)),\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #SETTER, true)->GetMethod(0)),\
dynamic_cast<EventInfoImpl*>(GetEventByName(L ## #EVENT, true))\
))\
);
#define CLASS_MEMBER_PROPERTY_EVENT_READONLY(PROPERTYNAME, GETTER, EVENT)\
AddProperty(\
Ptr(new PropertyInfoImpl(\
this,\
L ## #PROPERTYNAME,\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #GETTER, true)->GetMethod(0)),\
nullptr,\
dynamic_cast<EventInfoImpl*>(GetEventByName(L ## #EVENT, true))\
))\
);
#define CLASS_MEMBER_PROPERTY_REFERENCETEMPLATE(PROPERTYNAME, GETTER, SETTER, REFERENCETEMPLATE)\
AddProperty(\
Ptr(new PropertyInfoImpl_StaticCpp(\
this,\
L ## #PROPERTYNAME,\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #GETTER, true)->GetMethod(0)),\
dynamic_cast<MethodInfoImpl*>(GetMethodGroupByName(L ## #SETTER, true)->GetMethod(0)),\
nullptr,\
WString::Unmanaged(REFERENCETEMPLATE)\
))\
);
#define CLASS_MEMBER_PROPERTY_READONLY_FAST(PROPERTYNAME)\
CLASS_MEMBER_METHOD(Get##PROPERTYNAME, NO_PARAMETER)\
CLASS_MEMBER_PROPERTY_READONLY(PROPERTYNAME, Get##PROPERTYNAME)\
#define CLASS_MEMBER_PROPERTY_FAST(PROPERTYNAME)\
CLASS_MEMBER_METHOD(Get##PROPERTYNAME, NO_PARAMETER)\
CLASS_MEMBER_METHOD(Set##PROPERTYNAME, {L"value"})\
CLASS_MEMBER_PROPERTY(PROPERTYNAME, Get##PROPERTYNAME, Set##PROPERTYNAME)\
#define CLASS_MEMBER_PROPERTY_EVENT_FAST(PROPERTYNAME, EVENTNAME)\
CLASS_MEMBER_METHOD(Get##PROPERTYNAME, NO_PARAMETER)\
CLASS_MEMBER_METHOD(Set##PROPERTYNAME, {L"value"})\
CLASS_MEMBER_PROPERTY_EVENT(PROPERTYNAME, Get##PROPERTYNAME, Set##PROPERTYNAME, EVENTNAME)\
#define CLASS_MEMBER_PROPERTY_EVENT_READONLY_FAST(PROPERTYNAME, EVENTNAME)\
CLASS_MEMBER_METHOD(Get##PROPERTYNAME, NO_PARAMETER)\
CLASS_MEMBER_PROPERTY_EVENT_READONLY(PROPERTYNAME, Get##PROPERTYNAME, EVENTNAME)\
}
}
}
#endif
#endif
/***********************************************************************
.\REFLECTION\REFLECTION.H
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/
#ifndef VCZH_REFLECTION_REFLECTION_REFLECTION
#define VCZH_REFLECTION_REFLECTION_REFLECTION
namespace vl
{
namespace reflection
{
namespace description
{
/***********************************************************************
Predefined Types
***********************************************************************/
#define REFLECTION_PREDEFINED_PRIMITIVE_TYPES(F)\
F(vuint8_t) \
F(vuint16_t) \
F(vuint32_t) \
F(vuint64_t) \
F(vint8_t) \
F(vint16_t) \
F(vint32_t) \
F(vint64_t) \
F(float) \
F(double) \
F(bool) \
F(wchar_t) \
F(WString) \
F(Locale) \
#define REFLECTION_PREDEFINED_SERIALIZABLE_TYPES(F)\
REFLECTION_PREDEFINED_PRIMITIVE_TYPES(F) \
F(DateTime) \
#ifndef VCZH_DEBUG_NO_REFLECTION
#define REFLECTION_PREDEFINED_COMPLEX_TYPES(F, VOID_TYPE)\
F(VOID_TYPE) \
F(VoidValue) \
F(IDescriptable) \
F(DescriptableObject) \
F(DateTime) \
F(IValueEnumerator) \
F(IValueEnumerable) \
F(IValueReadonlyList) \
F(IValueArray) \
F(IValueList) \
F(IValueObservableList) \
F(IValueReadonlyDictionary) \
F(IValueDictionary) \
F(IValueInterfaceProxy) \
F(IValueFunctionProxy) \
F(IValueSubscription) \
F(IValueCallStack) \
F(IValueException) \
F(IBoxedValue) \
F(IBoxedValue::CompareResult) \
F(IValueType) \
F(IEnumType) \
F(ISerializableType) \
F(ITypeInfo) \
F(ITypeInfo::Decorator) \
F(IMemberInfo) \
F(IEventHandler) \
F(IEventInfo) \
F(IPropertyInfo) \
F(IParameterInfo) \
F(IMethodInfo) \
F(IMethodGroupInfo) \
F(TypeDescriptorFlags) \
F(ITypeDescriptor) \
DECL_TYPE_INFO(Value)
REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DECL_TYPE_INFO)
REFLECTION_PREDEFINED_COMPLEX_TYPES(DECL_TYPE_INFO, void)
#endif
#undef DEFINE_TYPED_VALUE_SERIALIZER_PROVIDER
/***********************************************************************
Interface Implementation Proxy (Implement)
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
#pragma warning(push)
#pragma warning(disable:4250)
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(IValueEnumerator)
Value GetCurrent()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetCurrent);
}
vint GetIndex()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetIndex);
}
bool Next()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(Next);
}
END_INTERFACE_PROXY(IValueEnumerator)
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(IValueEnumerable)
Ptr<IValueEnumerator> CreateEnumerator()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(CreateEnumerator);
}
END_INTERFACE_PROXY(IValueEnumerable)
BEGIN_INTERFACE_PROXY_SHAREDPTR(IValueReadonlyList, IValueEnumerable)
vint GetCount()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetCount);
}
Value Get(vint index)override
{
INVOKEGET_INTERFACE_PROXY(Get, index);
}
bool Contains(const Value& value)override
{
INVOKEGET_INTERFACE_PROXY(Contains, value);
}
vint IndexOf(const Value& value)override
{
INVOKEGET_INTERFACE_PROXY(IndexOf, value);
}
END_INTERFACE_PROXY(IValueReadonlyList)
BEGIN_INTERFACE_PROXY_SHAREDPTR(IValueArray, IValueReadonlyList)
void Set(vint index, const Value& value)override
{
INVOKE_INTERFACE_PROXY(Set, index, value);
}
void Resize(vint size)override
{
INVOKE_INTERFACE_PROXY(Resize, size);
}
END_INTERFACE_PROXY(IValueList)
BEGIN_INTERFACE_PROXY_SHAREDPTR(IValueList, IValueReadonlyList)
void Set(vint index, const Value& value)override
{
INVOKE_INTERFACE_PROXY(Set, index, value);
}
vint Add(const Value& value)override
{
INVOKEGET_INTERFACE_PROXY(Add, value);
}
vint Insert(vint index, const Value& value)override
{
INVOKEGET_INTERFACE_PROXY(Insert, index, value);
}
bool Remove(const Value& value)override
{
INVOKEGET_INTERFACE_PROXY(Remove, value);
}
bool RemoveAt(vint index)override
{
INVOKEGET_INTERFACE_PROXY(RemoveAt, index);
}
void Clear()override
{
INVOKE_INTERFACE_PROXY_NOPARAMS(Clear);
}
END_INTERFACE_PROXY(IValueList)
BEGIN_INTERFACE_PROXY_SHAREDPTR(IValueObservableList, IValueList)
END_INTERFACE_PROXY(IValueObservableList)
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(IValueReadonlyDictionary)
Ptr<IValueReadonlyList> GetKeys()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetKeys);
}
Ptr<IValueReadonlyList> GetValues()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetValues);
}
vint GetCount()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetCount);
}
Value Get(const Value& key)override
{
INVOKEGET_INTERFACE_PROXY(Get, key);
}
END_INTERFACE_PROXY(IValueReadonlyDictionary)
BEGIN_INTERFACE_PROXY_SHAREDPTR(IValueDictionary, IValueReadonlyDictionary)
void Set(const Value& key, const Value& value)override
{
INVOKE_INTERFACE_PROXY(Set, key, value);
}
bool Remove(const Value& key)override
{
INVOKEGET_INTERFACE_PROXY(Remove, key);
}
void Clear()override
{
INVOKE_INTERFACE_PROXY_NOPARAMS(Clear);
}
END_INTERFACE_PROXY(IValueDictionary)
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(IValueSubscription)
bool Open()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(Open);
}
bool Update()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(Update);
}
bool Close()override
{
INVOKEGET_INTERFACE_PROXY_NOPARAMS(Close);
}
END_INTERFACE_PROXY(IValueSubscription)
#pragma warning(pop)
#endif
/***********************************************************************
Helper Functions
***********************************************************************/
extern vint ITypeDescriptor_GetTypeDescriptorCount();
extern ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(vint index);
extern ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(const WString& name);
extern ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(const Value& value);
/***********************************************************************
LoadPredefinedTypes
***********************************************************************/
/// <summary>Register all reflectable types in <b>VlppReflection</b>.</summary>
/// <returns>Returns true if this operation succeeded.</returns>
extern bool LoadPredefinedTypes();
}
}
}
#endif