This commit is contained in:
watrabi
2025-10-28 14:05:46 -04:00
parent 977f1ff4b8
commit c93494f795
452 changed files with 47860 additions and 152 deletions
+597
View File
@@ -0,0 +1,597 @@
#pragma once
#include "reflection/type.h"
#include "security/securitycontext.h"
#include "reflection/member.h"
#include "reflection/Type.h"
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
namespace RBX
{
namespace Reflection
{
class Callback;
// Base class that describes a Callback
class RBXBaseClass CallbackDescriptor : public MemberDescriptor
{
public:
typedef Callback ConstMember;
typedef Callback Member;
protected:
SignatureDescriptor signature;
bool async;
CallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security, bool async);
public:
inline const SignatureDescriptor& getSignature() const { return signature; }
bool isAsync() const { return async; }
};
class SyncCallbackDescriptor : public CallbackDescriptor
{
protected:
SyncCallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security);
public:
typedef boost::function<shared_ptr<Reflection::Tuple>(shared_ptr<const Reflection::Tuple> args)> GenericFunction;
// the preferred way to set a generic function:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<GenericFunction> function) const = 0;
virtual void clearCallback(DescribedBase* object) const = 0;
// use this function if you don't have a shared_ptr:
void setGenericCallbackHelper(DescribedBase* object, const GenericFunction& function) const;
};
class AsyncCallbackDescriptor : public CallbackDescriptor
{
public:
typedef boost::function<void(shared_ptr<const Reflection::Tuple>)> ResumeFunction;
typedef boost::function<void(std::string)> ErrorFunction;
typedef boost::function<void(shared_ptr<const Reflection::Tuple> args, ResumeFunction resumeFunction, ErrorFunction errorFunction)> GenericFunction;
// the preferred way to set a generic function:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<GenericFunction> function) const = 0;
virtual void clearCallback(DescribedBase* object) const = 0;
// use this function if you don't have a shared_ptr:
void setGenericCallbackHelper(DescribedBase* object, const GenericFunction& function) const;
protected:
AsyncCallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security);
static void callGenericImpl(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args,
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction);
template <typename Class, typename Function, typename Value>
void setGenericCallbackImpl(DescribedBase* object, Function Class::*member, void (Class::*onChanged)(const Function&), const Value& value) const
{
Class* c = static_cast<Class*>(object);
Function oldValue = c->*member;
c->*member = value;
if (onChanged)
(c->*onChanged)(oldValue);
}
};
// A light-weight convenience class that associates a CallbackDescriptor
// with a described object to create a "Callback"
class Callback
{
const CallbackDescriptor* descriptor;
DescribedBase* instance;
public:
inline Callback(const CallbackDescriptor& descriptor, DescribedBase* instance)
:descriptor(&descriptor),instance(instance)
{}
inline Callback(const Callback& other)
:descriptor(other.descriptor),instance(other.instance)
{}
inline Callback& operator =(const Callback& other)
{
this->descriptor = other.descriptor;
this->instance = other.instance;
return *this;
}
inline const RBX::Name& getName() const {
return descriptor->name;
}
inline DescribedBase* getInstance() const
{
return instance;
}
inline const CallbackDescriptor& getDescriptor() const
{
return *descriptor;
}
};
// Base class of typed CallbackDescriptors
template<typename Signature>
class SyncCallbackDesc : public SyncCallbackDescriptor
{
protected:
typedef typename boost::function<Signature> Function;
typedef typename boost::function_traits<Signature>::result_type result_type;
template<typename Result>
static typename boost::enable_if<boost::is_void<Result>, void>::type
callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args)
{
(*function)(args);
}
template<typename Result>
static typename boost::disable_if<boost::is_same<shared_ptr<const Tuple>, Result>, Result>::type
convertResult(shared_ptr<Reflection::Tuple> result)
{
// Extract the first value in the Tuple and return it as the result. Ignore other vales
if (result->values.size() == 0)
throw std::runtime_error("Callback did not return a value");
return result->values[0].convert<Result>();
}
template<typename Result>
static typename boost::enable_if<boost::is_same<shared_ptr<const Tuple>, Result>, Result>::type
convertResult(shared_ptr<Reflection::Tuple> result)
{
return result;
}
template<typename Result>
static typename boost::disable_if<boost::is_void<Result>, Result>::type
callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args)
{
shared_ptr<Reflection::Tuple> result = (*function)(args);
return convertResult<Result>(result);
}
class RBXInterface ISetter
{
public:
virtual ~ISetter() {}
virtual void setCallback(DescribedBase* object, const Function& value) const = 0;
};
boost::scoped_ptr<ISetter> setter;
SyncCallbackDesc(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security):
SyncCallbackDescriptor(classDescriptor, name, attributes, security)
{}
public:
void setCallback(DescribedBase* object, const Function& value) const
{
setter->setCallback(object, value);
}
void clearCallback(DescribedBase* object) const
{
setter->setCallback(object, Function());
}
};
// Specialized class that implements generic bindings and sets the signature
template <typename Signature, int arity>
class SyncCallbackDescImpl;
template<typename Signature>
class SyncCallbackDescImpl<Signature, 0> : public SyncCallbackDesc<Signature>
{
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
}
protected:
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security)
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 0));
this->signature.resultType = &Type::singleton<result_type>();
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
{
this->setCallback(object, boost::bind(callGeneric, function));
}
};
template<typename Signature>
class SyncCallbackDescImpl<Signature, 1> : public SyncCallbackDesc<Signature>
{
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
// TODO: Use const ref for args and bind with boost::cref?
typename boost::function_traits<Signature>::arg1_type arg1)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
args->values.push_back(arg1);
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
}
protected:
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, Descriptor::Attributes attributes, Security::Permissions security)
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 1));
this->signature.resultType = &Type::singleton<result_type>();
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
{
this->setCallback(object, boost::bind(callGeneric, function, _1));
}
};
template<typename Signature>
class SyncCallbackDescImpl<Signature, 2> : public SyncCallbackDesc<Signature>
{
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
typename boost::function_traits<Signature>::arg1_type arg1,
typename boost::function_traits<Signature>::arg2_type arg2)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
args->values.push_back(arg1);
args->values.push_back(arg2);
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
}
protected:
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, Descriptor::Attributes attributes, Security::Permissions security)
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 2));
this->signature.resultType = &Type::singleton<result_type>();
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
{
this->setCallback(object, boost::bind(callGeneric, function, _1, _2));
}
};
template<typename Signature>
class SyncCallbackDescImpl<Signature, 3> : public SyncCallbackDesc<Signature>
{
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
typename boost::function_traits<Signature>::arg1_type arg1,
typename boost::function_traits<Signature>::arg2_type arg2,
typename boost::function_traits<Signature>::arg3_type arg3)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
args->values.push_back(arg1);
args->values.push_back(arg2);
args->values.push_back(arg3);
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
}
protected:
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, const char* arg3name, Descriptor::Attributes attributes, Security::Permissions security)
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 3));
this->signature.resultType = &Type::singleton<result_type>();
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
this->signature.addArgument(RBX::Name::declare(arg3name), Type::singleton<typename boost::function_traits<Signature>::arg3_type>());
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
{
this->setCallback(object, boost::bind(callGeneric, function, _1, _2, _3));
}
};
template<typename Signature>
class SyncCallbackDescImpl<Signature, 4> : public SyncCallbackDesc<Signature>
{
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
typename boost::function_traits<Signature>::arg1_type arg1,
typename boost::function_traits<Signature>::arg2_type arg2,
typename boost::function_traits<Signature>::arg3_type arg3,
typename boost::function_traits<Signature>::arg4_type arg4)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
args->values.push_back(arg1);
args->values.push_back(arg2);
args->values.push_back(arg3);
args->values.push_back(arg4);
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
}
protected:
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, Descriptor::Attributes attributes, Security::Permissions security)
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 4));
this->signature.resultType = &Type::singleton<result_type>();
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
this->signature.addArgument(RBX::Name::declare(arg3name), Type::singleton<typename boost::function_traits<Signature>::arg3_type>());
this->signature.addArgument(RBX::Name::declare(arg4name), Type::singleton<typename boost::function_traits<Signature>::arg4_type>());
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
{
this->setCallback(object, boost::bind(callGeneric, function, _1, _2, _3, _4));
}
};
// The fully functional descriptor that binds to class members
template<typename Signature>
class BoundCallbackDesc : public SyncCallbackDescImpl<Signature, boost::function_traits<Signature>::arity>
{
typedef typename boost::function<Signature> Function;
template<class Class>
class Setter : public SyncCallbackDesc<Signature>::ISetter
{
typedef void (Class::*OnChanged)();
Function Class::*member;
OnChanged onChanged;
public:
Setter(Function Class::*member, OnChanged onChanged = NULL):member(member),onChanged(onChanged) {}
virtual void setCallback(DescribedBase* object, const Function& value) const
{
Class* c = static_cast<Class*>(object);
c->*member = value;
if (onChanged)
(c->*onChanged)();
}
};
public:
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 0>(Class::classDescriptor(), name, attributes, security)
{
this->setter.reset(new Setter<Class>(member));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 0>(Class::classDescriptor(), name, attributes, security)
{
this->setter.reset(new Setter<Class>(member, onChanged));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 1>(Class::classDescriptor(), name, arg1name, attributes, security)
{
this->setter.reset(new Setter<Class>(member));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 1>(Class::classDescriptor(), name, arg1name, attributes, security)
{
this->setter.reset(new Setter<Class>(member, onChanged));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 2>(Class::classDescriptor(), name, arg1name, arg2name, attributes, security)
{
this->setter.reset(new Setter<Class>(member));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 2>(Class::classDescriptor(), name, arg1name, arg2name, attributes, security)
{
this->setter.reset(new Setter<Class>(member, onChanged));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 3>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, attributes, security)
{
this->setter.reset(new Setter<Class>(member));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 3>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, attributes, security)
{
this->setter.reset(new Setter<Class>(member, onChanged));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 4>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, arg4name, attributes, security)
{
this->setter.reset(new Setter<Class>(member));
}
template<class Class>
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
:SyncCallbackDescImpl<Signature, 4>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, arg4name, attributes, security)
{
this->setter.reset(new Setter<Class>(member, onChanged));
}
};
template <class Class, typename Signature, int arity = boost::function_traits<Signature>::arity>
class BoundAsyncCallbackDesc;
template <class Class, typename Signature>
class BoundAsyncCallbackDesc<Class, Signature, 0> : public AsyncCallbackDescriptor
{
typedef boost::function<void(AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
callGenericImpl(function, args, resumeFunction, errorFunction);
}
void declareSignature()
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 0));
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
}
Function Class::*member;
void (Class::*onChanged)(const Function&);
public:
BoundAsyncCallbackDesc(const char* name, Function Class::*member, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
, member(member)
, onChanged(NULL)
{
declareSignature();
}
BoundAsyncCallbackDesc(const char* name, Function Class::*member, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
, member(member)
, onChanged(onChanged)
{
declareSignature();
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
{
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2));
}
virtual void clearCallback(DescribedBase* object) const
{
setGenericCallbackImpl(object, member, onChanged, Function());
}
};
template <class Class, typename Signature>
class BoundAsyncCallbackDesc<Class, Signature, 1> : public AsyncCallbackDescriptor
{
typedef typename boost::function_traits<Signature>::arg1_type Arg1;
typedef boost::function<void(Arg1, AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
Arg1 arg1,
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
args->values.push_back(arg1);
callGenericImpl(function, args, resumeFunction, errorFunction);
}
void declareSignature(const char* arg1name)
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 1));
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
}
Function Class::*member;
void (Class::*onChanged)(const Function&);
public:
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
, member(member)
, onChanged(NULL)
{
declareSignature(arg1name);
}
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
, member(member)
, onChanged(onChanged)
{
declareSignature(arg1name);
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
{
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2, _3));
}
virtual void clearCallback(DescribedBase* object) const
{
setGenericCallbackImpl(object, member, onChanged, Function());
}
};
template <class Class, typename Signature>
class BoundAsyncCallbackDesc<Class, Signature, 2> : public AsyncCallbackDescriptor
{
typedef typename boost::function_traits<Signature>::arg1_type Arg1;
typedef typename boost::function_traits<Signature>::arg2_type Arg2;
typedef boost::function<void(Arg1, Arg2, AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
Arg1 arg1,
Arg2 arg2,
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
{
shared_ptr<Reflection::Tuple> args(new Tuple());
args->values.push_back(arg1);
args->values.push_back(arg2);
callGenericImpl(function, args, resumeFunction, errorFunction);
}
void declareSignature(const char* arg1name, const char* arg2name)
{
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 2));
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
}
Function Class::*member;
void (Class::*onChanged)(const Function&);
public:
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
, member(member)
, onChanged(NULL)
{
declareSignature(arg1name, arg2name);
}
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
, member(member)
, onChanged(onChanged)
{
declareSignature(arg1name, arg2name);
}
public:
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
{
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2, _3, _4));
}
virtual void clearCallback(DescribedBase* object) const
{
setGenericCallbackImpl(object, member, onChanged, Function());
}
};
}
}
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include "util/Name.h"
#include "boost/utility.hpp"
#include <boost/thread/mutex.hpp>
namespace RBX
{
namespace Reflection
{
class Descriptor : public boost::noncopyable
{
static void checkLockedDown()
{
// If this following assertion fails then you need to put your class
// into FactoryRegistrator::FactoryRegistrator() or somewhere else.
// Failure of this test is so severe that we want to catch it in production, too.
if (lockedDown)
RBXCRASH();
}
public:
struct Attributes
{
bool isDeprecated;
const Descriptor* preferred; // used if isDeprecated
Attributes()
:isDeprecated(false)
,preferred(NULL)
{}
static Attributes deprecated(const Descriptor& preferred)
{
Attributes result;
result.isDeprecated = true;
result.preferred = &preferred;
return result;
}
static Attributes deprecated()
{
Attributes result;
result.isDeprecated = true;
return result;
}
};
static bool lockedDown; // After the first instance of a described class is created we cannot modify the reflection database
const RBX::Name& name;
scoped_ptr<bool> isReplicable;
scoped_ptr<bool> isOutdated;
const Attributes attributes;
Descriptor(const char* name, Attributes attributes)
:name(RBX::Name::declare(name))
,attributes(attributes)
,isReplicable(new bool(false))
,isOutdated(new bool(false))
{
checkLockedDown();
RBXASSERT(!this->name.empty());
}
Descriptor(const RBX::Name& name, Attributes attributes)
:name(name)
,attributes(attributes)
,isReplicable(new bool(false))
,isOutdated(new bool(false))
{
checkLockedDown();
RBXASSERT(!this->name.empty());
}
virtual ~Descriptor() {}
};
}
}
+375
View File
@@ -0,0 +1,375 @@
#pragma once
#include "reflection/Type.h"
#include "util/utilities.h"
#include "util/math.h"
#include <boost/bind.hpp>
#include <boost/unordered_map.hpp>
#include <boost/thread/once.hpp>
namespace RBX {
namespace Reflection {
class EnumDescriptor : public Type
{
public:
static std::vector< const EnumDescriptor* >::const_iterator enumsBegin();
static std::vector< const EnumDescriptor* >::const_iterator enumsEnd();
static size_t allEnumSize() {return allEnums().size();}
class Item : public Descriptor
{
public:
const EnumDescriptor& owner;
const int value; // value of the enum
const size_t index; // place in ordered enum values (0<=index<enumCount)
Item(const char* name, Descriptor::Attributes attributes, int value, size_t index, const EnumDescriptor& owner)
:Descriptor(name, attributes)
,value(value)
,index(index)
,owner(owner)
{
}
bool convertToValue(Variant& value) const
{
return owner.convertToValue(index, value);
}
bool convertToString(std::string& value) const
{
return owner.convertToString(index, value);
}
};
#if 0
typedef boost::unordered_map<const RBX::Name*, const EnumDescriptor*> EnumNameTable;
#else
typedef std::map<const RBX::Name*, const EnumDescriptor*> EnumNameTable;
#endif
private:
static EnumNameTable& allEnumsNameLookup();
static std::vector<const EnumDescriptor*>& allEnums();
static bool equalValue(const Item* item, int intValue)
{
return item->value == intValue;
}
static int count;
protected:
std::vector< const Item* > allItems;
size_t enumCount;
size_t enumCountMSB;
EnumDescriptor(const char* typeName);
~EnumDescriptor();
public:
size_t getEnumCount() const { return enumCount; }
size_t getEnumCountMSB() const { return enumCountMSB; }
std::vector< const Item* >::const_iterator begin() const {
return allItems.begin();
}
std::vector< const Item* >::const_iterator end() const {
return allItems.end();
}
static const EnumDescriptor* lookupDescriptor(const RBX::Name& name) {
EnumNameTable::const_iterator iter = allEnumsNameLookup().find(&name);
if (iter!=allEnumsNameLookup().end())
return iter->second;
else
return NULL;
}
static const EnumDescriptor* lookupDescriptor(const Type& type) {
if (type.isEnum)
return static_cast<const EnumDescriptor*>(&type);
else
return NULL;
}
bool isValue(int intValue) const {
return std::find_if(allItems.begin(), allItems.end(), boost::bind(&equalValue, _1, intValue)) != allItems.end();
}
virtual const Item* lookup(const char* text) const = 0;
virtual const Item* lookup(const Variant& value) const = 0;
virtual bool convertToValue(size_t index, Variant& value) const = 0;
virtual bool convertToString(size_t index, std::string& value) const = 0;
};
// A thread-safe singleton!
template<typename T>
class Singleton : boost::noncopyable
{
static T& doGetSingleton()
{
static T s;
return s;
}
static void initSingleton()
{
doGetSingleton();
}
public:
static T& singleton()
{
static boost::once_flag flag = BOOST_ONCE_INIT;
boost::call_once(&initSingleton, flag);
return doGetSingleton();
};
};
template<typename Enum> class EnumRegistrar;
template<typename Enum>
class EnumDesc : public EnumDescriptor
{
public:
friend class Singleton<const EnumDesc<Enum> >;
static const EnumDesc& singleton()
{
return Singleton<const EnumDesc<Enum> >::singleton();
}
private:
// You must implement the following constructor for each EnumDesc that you define
EnumDesc();
~EnumDesc()
{
// Force linking of EnumRegistrar<Enum>, which will force clients
// of this library to define EnumRegistrar<Enum>::registrar in
// their startup code.
Reflection::EnumRegistrar<Enum>::registrar.dummy();
std::for_each(allItems.begin(), allItems.end(), &del_fun<const Item>);
}
std::map<const RBX::Name*, Enum> nameToEnum;
std::map<const RBX::Name*, Enum> nameToEnumLegacy;
std::vector< const RBX::Name* > enumToName; // maps enum to Name (there may be gaps)
std::vector< std::string > enumToString; // maps enum to String (there may be gaps)
std::vector< const Item* > enumToItem; // maps enum to Item (there may be gaps)
std::vector< Enum > intToEnum; // maps legacy values to proper enum
std::vector< Enum > indexToEnum;
std::vector< size_t > enumToIndex; // maps enum to Index (there may be gaps)
// Used in constructor
void addPair(Enum value, const char* name, Descriptor::Attributes attributes = Descriptor::Attributes())
{
RBXASSERT_VERY_FAST(value >= 0);
// No spaces in enums:
RBXASSERT_VERY_FAST(std::string(name).find(' ') == std::string::npos);
// No no CamelCase in enums:
RBXASSERT_VERY_FAST(!isCamel(name));
const Item* item = new Item(name, attributes, value, enumCount, *this);
allItems.push_back(item);
if (intToEnum.size()<=(size_t)value)
intToEnum.resize(value+1, (Enum)-1);
intToEnum[value] = value;
RBXASSERT(value>=0);
if (enumToIndex.size()<=(size_t)value)
enumToIndex.resize(value+1, -1);
enumToIndex[value] = enumCount;
indexToEnum.push_back(value);
if (enumToName.size()<=(size_t)value)
enumToName.resize(value+1, &RBX::Name::getNullName());
enumToName[value] = &item->name;
if (enumToString.size()<=(size_t)value)
enumToString.resize(value+1);
enumToString[value] = name;
if (enumToItem.size()<=(size_t)value)
enumToItem.resize(value+1);
enumToItem[value] = item;
nameToEnum[&item->name] = value;
enumCount++;
enumCountMSB = Math::computeMSB(enumCount);
}
void addLegacy(int oldValue, const char* name, Enum value)
{
RBXASSERT_VERY_FAST(value >= 0);
if (intToEnum.size()<=(size_t)oldValue)
intToEnum.resize(oldValue+1, (Enum)-1);
intToEnum[oldValue] = value;
nameToEnumLegacy[&RBX::Name::declare(name)] = value;
}
void addLegacyName(const char* name, Enum value)
{
nameToEnumLegacy[&RBX::Name::declare(name)] = value;
}
public:
const RBX::Name& convertToName(const Enum& value) const
{
RBXASSERT(value>=0);
RBXASSERT(value<enumToItem.size());
if (value<0)
return RBX::Name::getNullName();
if ((size_t)value>=enumToName.size())
return RBX::Name::getNullName();
return *enumToName[value];
}
std::string convertToString(const Enum& value) const
{
RBXASSERT(value>=0);
RBXASSERT((size_t)value<enumToItem.size());
if (value<0)
return "";
if ((size_t)value>=enumToString.size())
return "";
return enumToString[value];
}
const Item* convertToItem(const Enum& value) const
{
RBXASSERT(value>=0);
RBXASSERT((size_t)value<enumToItem.size());
if (value<0)
return NULL;
if ((size_t)value>=enumToItem.size())
return NULL;
return enumToItem[value];
}
bool mapIntValue(int intValue, Enum& value) const
{
if (intValue < 0)
return false;
if ((size_t)intValue >= intToEnum.size())
return false;
value = intToEnum[intValue];
if ((int)value == -1)
return false;
return true;
}
bool convertToValue(const RBX::Name& name, Enum& value) const
{
typename std::map<const RBX::Name*, Enum>::const_iterator iter = nameToEnum.find(&name);
if (iter!=nameToEnum.end()) {
value = iter->second;
return true;
}
iter = nameToEnumLegacy.find(&name);
if (iter!=nameToEnumLegacy.end()) {
value = iter->second;
return true;
}
return false;
}
/*implement*/ const Item* lookup(const char* text) const
{
Enum e;
if (convertToValue(RBX::Name::lookup(text), e))
return convertToItem(e);
else
return NULL;
}
/*implement*/ const Item* lookup(const Variant& value) const
{
return convertToItem(value.cast<Enum>());
}
/*implement*/ bool convertToValue(size_t index, Variant& value) const
{
Enum enumValue;
bool result = convertToValue(index, enumValue);
value = enumValue;
return result;
}
/*implement*/ bool convertToString(size_t index, std::string& stringValue) const
{
Enum enumValue;
if(convertToValue(index, enumValue)){
stringValue = convertToString(enumValue);
return true;
}
return false;
}
bool convertToValue(const char* text, Enum& value) const
{
return convertToValue(RBX::Name::lookup(text), value);
}
size_t convertToIndex(Enum value) const
{
RBXASSERT(value>=0);
if ((size_t)value<enumToIndex.size())
return enumToIndex[value];
else
return -1;
}
bool convertToValue(size_t index, Enum& value) const
{
if (index<enumCount) {
value = indexToEnum[index];
return true;
}
else {
return false;
}
}
};
// Helper macro
// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
#define RBX_REGISTER_ENUM(Enum) namespace RBX { namespace Reflection { \
template<> \
const Type& Type::getSingleton<Enum>() \
{ \
return EnumDesc<Enum>::singleton(); \
} \
template<> EnumRegistrar<Enum> EnumRegistrar<Enum>::registrar(0); \
template<> TypeRegistrar<Enum> TypeRegistrar<Enum>::registrar(0); \
}}
// This class is intended to prevent clients of the library
// from forgetting to initialize the enum descriptor
template<typename Enum>
class EnumRegistrar : boost::noncopyable
{
int x;
//// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
EnumRegistrar(int i):x(i)
{
// This call registers the enum descriptor
// in the reflection database
EnumDesc<Enum>::singleton();
}
public:
void dummy()
{
x++;
}
// The instantiation of this static member must be in a unit
// that is initialized in the main thread before any objects
// are created. Otherwise the reflection database
// can change at runtime, which would be a disaster
static EnumRegistrar registrar;
};
}
}
File diff suppressed because it is too large Load Diff
+108
View File
@@ -0,0 +1,108 @@
#pragma once
#include "reflection/type.h"
#include "security/securitycontext.h"
#include "reflection/member.h"
#include "util/G3DCore.h"
#include "util/Region3.h"
#include "util/Region3Int16.h"
struct lua_State;
namespace RBX
{
namespace Reflection
{
class Function;
class EnumDescriptor;
// Base that describes a Function
class RBXBaseClass FunctionDescriptor : public MemberDescriptor
{
public:
enum Kind
{
Kind_Default,
Kind_Custom
};
class RBXInterface Arguments
{
public:
Variant returnValue;
virtual size_t size() const = 0;
// Place the value for the requested parameter in "value".
//
// index: 1-based index into the argument list
// returns: true if the index contains a valid argument
// value: the value to set. the function returns false then value is unchanged
virtual bool getVariant(int index, Variant& value) const = 0;
virtual bool getBool(int index, bool& value) const = 0;
virtual bool getLong(int index, long& value) const = 0;
virtual bool getDouble(int index, double& value) const = 0;
virtual bool getString(int index, std::string& value) const = 0;
virtual bool getVector3int16(int index, Vector3int16& value) const = 0;
virtual bool getRegion3int16(int index, Region3int16& value) const = 0;
virtual bool getVector3(int index, Vector3& value) const = 0;
virtual bool getRegion3(int index, Region3& value) const = 0;
virtual bool getRect(int index, Rect2D& value) const = 0;
virtual bool getObject(int index, shared_ptr<DescribedBase>& value) const = 0;
virtual bool getEnum(int index, const EnumDescriptor& desc, int& value) const = 0;
};
typedef Function ConstMember;
typedef Function Member;
protected:
SignatureDescriptor signature;
Kind kind;
FunctionDescriptor(ClassDescriptor& classDescriptor, const char* name, Security::Permissions security, Attributes attributes);
public:
const SignatureDescriptor& getSignature() const { return signature; }
Kind getKind() const { return kind; }
virtual int executeCustom(DescribedBase* instance, lua_State*) const { return 0; }
virtual void execute(DescribedBase* instance, Arguments& arguments) const = 0;
};
// A light-weight convenience class that associates a FunctionDescriptor
// with a described object to create a "Function"
class Function
{
protected:
const FunctionDescriptor* descriptor;
DescribedBase* instance;
public:
inline Function(const FunctionDescriptor& descriptor, DescribedBase* instance)
:descriptor(&descriptor),instance(instance)
{}
inline Function(const Function& other)
:descriptor(other.descriptor),instance(other.instance)
{}
inline Function& operator =(const Function& other)
{
this->descriptor = other.descriptor;
this->instance = other.instance;
return *this;
}
inline const RBX::Name& getName() const {
return descriptor->name;
}
inline const FunctionDescriptor* getDescriptor() const {
return descriptor;
}
void execute(FunctionDescriptor::Arguments& arguments) const {
return descriptor->execute(const_cast<DescribedBase*>(instance), arguments);
}
};
}
}
+337
View File
@@ -0,0 +1,337 @@
#pragma once
#include "reflection/Property.h"
#include "reflection/Function.h"
#include "reflection/YieldFunction.h"
#include "Reflection/Event.h"
#include "reflection/Callback.h"
#include <vector>
#include "boost/crc.hpp"
namespace RBX
{
namespace Reflection
{
enum ReplicationLevel{
NEVER_REPLICATE = 0, //Never replicate this object
STANDARD_REPLICATE= 1, //Replicate to/from server according to standard rules
PLAYER_REPLICATE = 2, //Replicate changes to/from the "player" who owns this object
} ;
class ClassDescriptor
: public Descriptor
, public MemberDescriptorContainer<PropertyDescriptor>
, public MemberDescriptorContainer<EventDescriptor>
, public MemberDescriptorContainer<FunctionDescriptor>
, public MemberDescriptorContainer<YieldFunctionDescriptor>
, public MemberDescriptorContainer<CallbackDescriptor>
{
public:
typedef std::vector<ClassDescriptor*> ClassDescriptors;
enum Functionality{
PERSISTENT = 0x1 + 0x2 + 0x8 + 0x10, // isPublic, Replicate, canXmlWrite, isScriptable
PERSISTENT_PLAYER = 0x1 + 0x4 + 0x8 + 0x10, // isPublic, ReplicatePlayer, canXmlWrite, isScriptable
PERSISTENT_LOCAL = 0x1 + 0x0 + 0x8 + 0x10, // isPublic, canXmlWrite, isScriptable
RUNTIME = 0x1 + 0x2 + 0x0 + 0x10, // isPublic, Replicate, isScriptable
RUNTIME_PLAYER = 0x1 + 0x4 + 0x0 + 0x10, // isPublic, ReplicatePlayer, isScriptable
RUNTIME_LOCAL = 0x1 + 0x0 + 0x0 + 0x10, // isPublic, isScriptable
INTERNAL = 0x1 + 0x2 + 0x0 + 0x0, // isPublic, Replicate
INTERNAL_PLAYER = 0x1 + 0x4 + 0x0 + 0x0, // isPublic, ReplicatePlayer,
INTERNAL_LOCAL = 0x1 + 0x0 + 0x0 + 0x0, // isPublic
PERSISTENT_HIDDEN = 0x1 + 0x2 + 0x8 + 0x0, // isPublic, Replicate, canXmlWrite
PERSISTENT_LOCAL_INTERNAL = 0x1 + 0x0 + 0x8 + 0x0, // isPublic, canXmlWrite
};
struct Attributes : public Descriptor::Attributes
{
Functionality flags;
Attributes(Functionality flags):flags(flags) {}
static Attributes deprecated(Functionality flags, const ClassDescriptor* preferred);
};
const Security::Permissions security;
private:
ClassDescriptor();
static ClassDescriptors& allClasses();
ClassDescriptors derivedClasses;
ClassDescriptor* const base;
const unsigned bReplicateType : 2;
const unsigned bCanXmlWrite : 1;
const unsigned bIsScriptable : 1;
static int count;
public:
ClassDescriptor(ClassDescriptor& base, const char* name, Attributes attributes, Security::Permissions security);
~ClassDescriptor() { count--; }
const ClassDescriptor* getBase() const { return base; }
bool isBaseOf(const ClassDescriptor& child) const;
bool isA(const ClassDescriptor& test) const;
bool isBaseOf(const char* childName) const;
bool isA(const char* testName) const;
inline ReplicationLevel getReplicationLevel() const { return (ReplicationLevel)bReplicateType; }
inline bool isScriptCreatable() const { return bIsScriptable != 0; }
inline bool isSerializable() const { return bCanXmlWrite != 0; }
// The root ClassDescriptor of all other Descriptors
static ClassDescriptor& rootDescriptor()
{
static ClassDescriptor root;
return root;
}
/////////////////////////////////////////////////////////////////////////////////
// Class enumeration
static ClassDescriptors::const_iterator all_begin() {
return allClasses().begin();
}
static ClassDescriptors::const_iterator all_end() {
return allClasses().end();
}
static size_t all_size()
{
return allClasses().size();
}
static unsigned int checksum();
static unsigned int checksum(const PropertyDescriptor* t, boost::crc_32_type& result);
static unsigned int checksum(const EventDescriptor* t, boost::crc_32_type& result);
static unsigned int checksum(const ClassDescriptor* t, boost::crc_32_type& result);
static unsigned int checksum(const Type* t, boost::crc_32_type& result);
/////////////////////////////////////////////////////////////////////////////////
// Derived Class enumeration
ClassDescriptors::const_iterator derivedClasses_begin() const {
return derivedClasses.begin();
}
ClassDescriptors::const_iterator derivedClasses_end() const {
return derivedClasses.end();
}
/////////////////////////////////////////////////////////////////////////////////
// Convenience functions for enumerating and querying members of a Class
PropertyDescriptor* findPropertyDescriptor(const char* name) const
{
return MemberDescriptorContainer<PropertyDescriptor>::findDescriptor(name);
}
FunctionDescriptor* findFunctionDescriptor(const char* name) const
{
return MemberDescriptorContainer<FunctionDescriptor>::findDescriptor(name);
}
YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const
{
return MemberDescriptorContainer<YieldFunctionDescriptor>::findDescriptor(name);
}
EventDescriptor* findEventDescriptor(const char* name) const
{
return MemberDescriptorContainer<EventDescriptor>::findDescriptor(name);
}
CallbackDescriptor* findCallbackDescriptor(const char* name) const
{
return MemberDescriptorContainer<CallbackDescriptor>::findDescriptor(name);
}
template<class T>
typename MemberDescriptorContainer<T>::Collection::const_iterator begin() const {
return MemberDescriptorContainer<T>::descriptors_begin();
}
template<class T>
typename MemberDescriptorContainer<T>::Collection::const_iterator end() const {
return MemberDescriptorContainer<T>::descriptors_end();
}
bool operator==(const ClassDescriptor& other) const;
bool operator!=(const ClassDescriptor& other) const;
};
// Convenience typedefs:
typedef MemberDescriptorContainer<PropertyDescriptor>::ConstIterator ConstPropertyIterator;
typedef MemberDescriptorContainer<PropertyDescriptor>::Iterator PropertyIterator;
typedef MemberDescriptorContainer<FunctionDescriptor>::ConstIterator FunctionIterator;
typedef MemberDescriptorContainer<YieldFunctionDescriptor>::ConstIterator YieldFunctionIterator;
typedef MemberDescriptorContainer<EventDescriptor>::ConstIterator ConstSignalIterator;
typedef MemberDescriptorContainer<EventDescriptor>::Iterator SignalIterator;
typedef MemberDescriptorContainer<CallbackDescriptor>::Iterator CallbackIterator;
// The base class of any class that supports Reflection
class RBXBaseClass DescribedBase
: public EventSource
, public boost::enable_shared_from_this<DescribedBase>
{
protected:
// Each instance has a reference to it's most-specific ClassDescriptor:
const ClassDescriptor* descriptor;
boost::scoped_ptr<std::string> xmlId;
public:
// The ClassDescriptor for this base class
static ClassDescriptor& classDescriptor()
{
return ClassDescriptor::rootDescriptor();
}
DescribedBase()
{
Descriptor::lockedDown = true; // See Descriptor::checkLockedDown() for an explanation
// By default, each DescribedBase has a null ClassDescriptor
this->descriptor = &classDescriptor();
}
virtual ~DescribedBase()
{
}
inline const ClassDescriptor& getDescriptor() const { return *descriptor; };
template<class T>
inline bool isA() const
{
return getDescriptor().isA(T::classDescriptor());
}
template<class T>
static inline bool isA(const DescribedBase* instance)
{
return instance ? instance->getDescriptor().isA(T::classDescriptor()) : false;
}
// This function is slower than the others
bool isA(std::string className)
{
return getDescriptor().isA(className.c_str());
}
// Regular dynamic_casts are very slow. These faster versions uses our reflection framework to determine type then uses static_cast for speed.
// Use these functions to replace dynamic_casts for classes that derives from DescribedCreatable or DescribedNonCreatable.
template<class T>
inline T* fastDynamicCast()
{
return (getDescriptor().isA(T::classDescriptor())) ? static_cast<T*>(this) : NULL;
}
template<class T>
inline const T* fastDynamicCast() const
{
return (getDescriptor().isA(T::classDescriptor())) ? static_cast<const T*>(this) : NULL;
}
template<class T>
static inline T* fastDynamicCast(DescribedBase* instance)
{
return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast<T*>(instance) : NULL;
}
template<class T>
static inline const T* fastDynamicCast(const DescribedBase* instance)
{
return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast<const T*>(instance) : NULL;
}
// This function replaces shared_dynamic_cast for classes that derives from DescribedCreatable or DescribedNonCreatable.
template<class T, class U>
static inline shared_ptr<T> fastSharedDynamicCast(const shared_ptr<U>& instance)
{
return isA<T>(instance.get()) ? shared_static_cast<T>(instance) : shared_ptr<T>();
}
/////////////////////////////////////////////////////////////////////////////////
// Convenience functions for getting members of a described object
PropertyDescriptor* findPropertyDescriptor(const char* name)
{
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::findDescriptor(name);
}
ConstPropertyIterator properties_begin() const {
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_begin(this);
}
ConstPropertyIterator properties_end() const {
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_end(this);
}
PropertyIterator properties_begin() {
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_begin(this);
}
PropertyIterator properties_end() {
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_end(this);
}
FunctionDescriptor* findFunctionDescriptor(const char* name)
{
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::findDescriptor(name);
}
FunctionIterator functions_begin() const {
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::members_begin(this);
}
FunctionIterator functions_end() const {
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::members_end(this);
}
YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const
{
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::findDescriptor(name);
}
YieldFunctionIterator yield_functions_begin() const {
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::members_begin(this);
}
YieldFunctionIterator yield_functions_end() const {
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::members_end(this);
}
CallbackDescriptor* findCallbackDescriptor(const char* name)
{
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::findDescriptor(name);
}
CallbackIterator callbacks_begin() {
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::members_begin(this);
}
CallbackIterator callbacks_end() {
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::members_end(this);
}
EventDescriptor* findSignalDescriptor(const char* name) const
{
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::findDescriptor(name);
}
ConstSignalIterator signals_begin() const {
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_begin(this);
}
ConstSignalIterator signals_end() const {
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_end(this);
}
SignalIterator signals_begin() {
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_begin(this);
}
SignalIterator signals_end() {
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_end(this);
}
const std::string* getXmlId() const {
return xmlId.get();
}
void setXmlId(const std::string& newId) {
if (!xmlId)
{
xmlId.reset(new std::string(newId));
}
else
{
*xmlId = newId;
}
}
virtual const RBX::Name& getClassName() const = 0;
};
}
}
+491
View File
@@ -0,0 +1,491 @@
#pragma once
#include "reflection/member.h"
#include "reflection/enumconverter.h"
#include "reflection/type.h"
#include "v8xml/xmlelement.h"
#include "V8Xml/Reference.h" // TODO: Reflection namespace should not know about V8Tree
#include "boost/cast.hpp"
namespace RBX
{
namespace Reflection
{
class ConstProperty;
class Property;
typedef enum {
READONLY,
READWRITE
} Mutability;
// Base that describes a Property
class RBXBaseClass PropertyDescriptor : public MemberDescriptor
{
private:
unsigned bIsPublic : 1;
unsigned bIsEditable : 1;
unsigned bCanReplicate : 1;
unsigned bCanXmlRead : 1;
unsigned bCanXmlWrite : 1;
unsigned bIsScriptable : 1;
unsigned bAlwaysClone : 1;
public:
typedef ConstProperty ConstMember;
typedef Property Member;
public:
// Note: isPublic == PropertyUI shown, and Can BaseScript against. ToDO: possibly split?
enum Functionality {
STANDARD = 1 + 2 + 4 + 8 + 16, // isPublic, canReplicate, canXmlRead , canXmlWrite, isScriptable
NO_XML_WRITE = 1 + 2 + 4 + 0 + 16, // isPublic, canReplicate, canXmlRead , , isScriptable
UI = 1 + 0 +(4)+ 0 + 16, // isPublic, (canXmlRead), isScriptable //Remove canXmlRead from UI
SCRIPTING = 1 + 2 + 0 + 0 + 16, // isPublic, canReplicate, isScriptable
STREAMING = 0 + 2 + 4 + 8 + 0, // canReplicate, canXmlRead , canXmlWrite,
CLUSTER = 0 + 0 + 4 + 8 + 0, // canXmlRead , canXmlWrite,
LEGACY = 0 + 0 + 4 + 0 + 0, // canXmlRead ,
REPLICATE_ONLY = 0 + 2 + 0 + 0 + 0, // canReplicate
LEGACY_SCRIPTING = 0 + 0 + 4 + 0 + 16, // canXmlRead , isScriptable
HIDDEN_SCRIPTING = 0 + 0 + 0 + 0 + 16, // isScriptable
PUBLIC_SERIALIZED = 1 + 0 + 4 + 8 + 0, // isPublic, canXmlRead , canXmlWrite,
REPLICATE_CLONE = 0 + 2 + 0 + 0 + 0 + 32, // canReplicate alwaysClone
STANDARD_NO_REPLICATE = 1 + 0 + 4 + 8 + 16, // isPublic, canXmlRead , canXmlWrite, isScriptable
STANDARD_NO_SCRIPTING = 1 + 2 + 4 + 8 + 0, // isPublic, canReplicate, canXmlRead , canXmlWrite
PUBLIC_REPLICATE = 1 + 2 + 0 + 0 + 0, // isPublic, canReplicate
};
struct Attributes : public Descriptor::Attributes
{
Functionality flags;
Attributes():flags(STANDARD) {}
Attributes(Functionality flags):flags(flags) {}
static Attributes deprecated(const MemberDescriptor& preferred, Functionality flags = UI);
static Attributes deprecated(Functionality flags = UI);
};
const Type& type;
const bool bIsEnum;
protected:
PropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, Attributes attributes, Security::Permissions security, bool isEnum = false);
inline void checkFlags()
{
if (isWriteOnly())
{
bCanXmlWrite = 0;
bCanReplicate = 0;
}
if (isReadOnly())
{
bCanXmlRead = 0;
bCanReplicate = 0;
}
}
public:
inline bool isPublic() const { return bIsPublic != 0; }
inline bool isScriptable() const { return bIsScriptable != 0; }
void setEditable(bool editable) { bIsEditable = editable ? 1 : 0; }
inline bool isEditable() const { return bIsEditable != 0; }
virtual bool isReadOnly() const = 0;
virtual bool isWriteOnly() const = 0;
inline bool canXmlRead() const
{
RBXASSERT(bCanXmlRead == 0 || !isReadOnly());
return bCanXmlRead != 0;
}
inline bool canXmlWrite() const
{
RBXASSERT(bCanXmlWrite == 0 || !isWriteOnly());
return bCanXmlWrite != 0;
}
inline bool canReplicate() const
{
RBXASSERT(bCanReplicate == 0 || (!isReadOnly() && !isWriteOnly()));
return bCanReplicate != 0;
}
inline bool alwaysClone() const
{
return bAlwaysClone != 0;
}
bool operator==(const PropertyDescriptor& other) const {
return this == &other;
}
bool operator!=(const PropertyDescriptor& other) const {
return this != &other;
}
virtual bool equalValues(const DescribedBase* a, const DescribedBase* b) const = 0;
virtual void getVariant(const DescribedBase* instance, Variant& value) const = 0;
virtual void setVariant(DescribedBase* instance, const Variant& value) const = 0;
virtual void copyValue(const DescribedBase* source, DescribedBase* destination) const = 0;
virtual int getDataSize(const DescribedBase* instance) const = 0;
////////////////////////////////////////////////////////////////////////////////////////////////////
// String conversion interface
public:
virtual bool hasStringValue() const = 0;
virtual std::string getStringValue(const DescribedBase* instance) const {
if (hasStringValue())
debugAssertM(false, "you must implement getStringValue");
else
debugAssertM(false, "don't call getStringValue when hasStringValue()==false");
return "";
}
virtual bool setStringValue(DescribedBase* instance, const std::string& text) const {
if (hasStringValue())
debugAssertM(false, "you must implement setStringValue");
else
debugAssertM(false, "don't call setStringValue when hasStringValue()==false");
return false;
}
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
////////////////////////////////////////////////////////////////////////////////////////////////////
// Xml streaming interface
public:
XmlElement* write(const DescribedBase* instance, bool ignoreWriteProtection = false) const;
virtual void read(DescribedBase* instance, const XmlElement* element, RBX::IReferenceBinder& binder) const;
private:
virtual void writeValue(const DescribedBase* instance, XmlElement* element) const = 0;
virtual void readValue(DescribedBase* instance, const XmlElement* element, RBX::IReferenceBinder& binder) const = 0;
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
};
template <typename V>
class TypedPropertyDescriptor : public PropertyDescriptor
{
private:
typedef PropertyDescriptor Super;
public:
class RBXInterface GetSet
{
public:
virtual bool isReadOnly() const = 0;
virtual bool isWriteOnly() const = 0;
virtual V getValue(const DescribedBase* object) const = 0;
virtual void setValue(DescribedBase* object, const V& value) const = 0;
};
protected:
std::auto_ptr<GetSet> getset;
TypedPropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, std::auto_ptr<GetSet> getset, Attributes flags, Security::Permissions security)
:PropertyDescriptor(classDescriptor, type, name, category, flags, security),getset(getset)
{
if (this->getset.get())
this->checkFlags();
}
TypedPropertyDescriptor(ClassDescriptor& classDescriptor, const char* name, const char* category, std::auto_ptr<GetSet> getset, Attributes flags, Security::Permissions security)
:PropertyDescriptor(classDescriptor, Type::singleton<V>(), name, category, flags, security),getset(getset)
{
if (this->getset.get())
this->checkFlags();
}
public:
/*implement*/ V get(const DescribedBase* instance) const
{
return getset->getValue(instance);
}
/*implement*/ void set(DescribedBase* instance, const V& value) const
{
getset->setValue(instance, value);
}
/*implement*/ void getVariant(const DescribedBase* instance, Variant& value) const
{
value = getset->getValue(instance);
}
/*implement*/ void setVariant(DescribedBase* instance, const Variant& value) const
{
// TODO: This might be inefficient. How is the value stored in getset???
getset->setValue(instance, value.get<V>());
}
/*implement*/ void copyValue(const DescribedBase* source, DescribedBase* destination) const
{
set(destination, get(source));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variant interface
public:
virtual bool isReadOnly() const {
return getset->isReadOnly();
}
virtual bool isWriteOnly() const {
return getset->isWriteOnly();
}
V getValue(const DescribedBase* object) const {
return getset->getValue(object);
}
void setValue(DescribedBase* object, const V& value) const {
getset->setValue(object, value);
}
/*implement*/ bool equalValues(const DescribedBase* a, const DescribedBase* b) const {
return getValue(a) == getValue(b);
}
virtual int getDataSize(const DescribedBase* instance) const;
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
virtual bool hasStringValue() const;
virtual std::string getStringValue(const DescribedBase* instance) const;
virtual bool setStringValue(DescribedBase* instance, const std::string& text) const;
private:
virtual void readValue(DescribedBase* instance, const XmlElement* element, IReferenceBinder& binder) const;
virtual void writeValue(const DescribedBase* instance, XmlElement* element) const;
};
// A light-weight convenience class that associates a PropertyDescriptor
// with a described object to create a "Property"
class ConstProperty
{
protected:
const PropertyDescriptor* descriptor;
const DescribedBase* instance;
public:
inline ConstProperty():descriptor(0),instance(0) {}
inline ConstProperty(const PropertyDescriptor& descriptor, const DescribedBase* instance)
:descriptor(&descriptor),instance(instance)
{
RBXASSERT(!instance || descriptor.isMemberOf(instance));
}
inline ConstProperty(const ConstProperty& other)
:descriptor(other.descriptor),instance(other.instance)
{}
inline const DescribedBase* getInstance() const { return instance; }
inline const PropertyDescriptor& getDescriptor() const { return *descriptor; }
inline ConstProperty& operator =(const ConstProperty& other)
{
this->descriptor = other.descriptor;
this->instance = other.instance;
return *this;
}
inline bool operator ==(const ConstProperty& other) const
{
return (this->descriptor == other.descriptor) && (this->instance == other.instance);
}
inline const RBX::Name& getName() const {
return descriptor->name;
}
template<typename V>
inline bool isValueType() const
{
return descriptor->type==Type::singleton<V>();
}
template<typename V>
inline V getValue() const
{
RBXASSERT(isValueType<V>());
return static_cast<const TypedPropertyDescriptor<V>*>(descriptor)->getValue(instance);
}
inline bool hasStringValue() const
{
return descriptor->hasStringValue();
}
inline std::string getStringValue() const
{
return descriptor->getStringValue(instance);
}
inline XmlElement* write() const
{
return descriptor->write(instance);
}
};
// A light-weight convenience class that associates a PropertyDescriptor
// with a described object to create a "Property"
class Property : public ConstProperty
{
public:
inline Property(const PropertyDescriptor& descriptor, DescribedBase* instance)
:ConstProperty(descriptor, instance)
{}
inline Property(const Property& other)
:ConstProperty(*other.descriptor, other.instance)
{}
inline Property& operator =(const Property& other)
{
this->descriptor = other.descriptor;
this->instance = other.instance;
return *this;
}
inline bool operator ==(const Property& other) const
{
return this->descriptor==other.descriptor && this->instance==other.instance;
}
inline bool operator !=(const Property& other) const
{
return this->descriptor!=other.descriptor || this->instance!=other.instance;
}
DescribedBase* getInstance() const { return const_cast<DescribedBase*>(instance); }
template<typename V>
inline void setValue(const V& value)
{
RBXASSERT(isValueType<V>());
static_cast<const TypedPropertyDescriptor<V>*>(descriptor)->setValue(const_cast<DescribedBase*>(instance), value);
}
inline bool setStringValue(const std::string& text)
{
return descriptor->setStringValue(const_cast<DescribedBase*>(instance), text);
}
inline void read(const XmlElement* element, RBX::IReferenceBinder& binder)
{
descriptor->read(const_cast<DescribedBase*>(instance), element, binder);
}
};
std::size_t hash_value(const ConstProperty& prop);
// Interface
// maps enums to an index (Used by UIs like a property grid)
class RBXInterface EnumPropertyDescriptor : public PropertyDescriptor {
public:
const EnumDescriptor& enumDescriptor;
virtual size_t getIndexValue(const DescribedBase* instance) const = 0;
virtual bool setIndexValue(DescribedBase* instance, size_t value) const = 0; // throws an exception if value is illegal
virtual int getEnumValue(const DescribedBase* instance) const = 0;
virtual bool setEnumValue(DescribedBase* instance, int index) const = 0;
virtual const EnumDescriptor::Item* getEnumItem(const DescribedBase* instance) const = 0;
bool setEnumItem(DescribedBase* instance, const EnumDescriptor::Item& item) const {
if (item.owner!=enumDescriptor)
return false;
return setEnumValue(instance, item.value);
}
virtual int getDataSize(const DescribedBase* instance) const
{ return sizeof(int); }
protected:
EnumPropertyDescriptor(ClassDescriptor& classDescriptor, const EnumDescriptor& enumDescriptor, const char* name, const char* category, Attributes flags = STANDARD, Security::Permissions security=Security::None)
:PropertyDescriptor(classDescriptor, enumDescriptor, name, category, flags, security, true)
,enumDescriptor(enumDescriptor)
{}
};
class RBXBaseClass RefPropertyDescriptor : public PropertyDescriptor {
private:
typedef PropertyDescriptor Super;
public:
virtual DescribedBase* getRefValue(const DescribedBase* instance) const = 0;
virtual void setRefValue(DescribedBase* instance, DescribedBase* value) const = 0;
virtual void setRefValueUnsafe(DescribedBase* instance, DescribedBase* value) const = 0;
RefPropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, Attributes flags = STANDARD, Security::Permissions security=Security::None)
:PropertyDescriptor(classDescriptor, type, name, category, flags, security)
{}
virtual int getDataSize(const DescribedBase* instance) const
{ return 0; }
bool hasStringValue() const {
return false;
}
std::string getStringValue(const DescribedBase* instance) const{
return Super::getStringValue(instance);
}
bool setStringValue(DescribedBase* instance, const std::string& text) const {
return Super::setStringValue(instance, text);
}
static bool isRefPropertyDescriptor(const Reflection::Type& type)
{
static const RBX::Name& name = RBX::Name::lookup("Object");
return (type.name == name);
}
static bool isRefPropertyDescriptor(const PropertyDescriptor& descriptor)
{
// See RefType in reflection.h
bool result = isRefPropertyDescriptor(descriptor.type);
RBXASSERT(result == (0 != dynamic_cast<const Reflection::RefPropertyDescriptor*>(&descriptor)));
return result;
}
};
// A very useful class for binding Instance members to PropertyDescriptors
template<typename V, Mutability mutability = READWRITE>
class BoundProp : public Reflection::TypedPropertyDescriptor<V>
{
template<class Class>
class BoundPropGetSet : public TypedPropertyDescriptor<V>::GetSet
{
BoundProp& desc;
V Class::*member;
typedef void (Class::*ChangedMember)(const Reflection::PropertyDescriptor&);
ChangedMember changed;
public:
BoundPropGetSet(BoundProp& desc, V Class::*member, ChangedMember changed):desc(desc),member(member),changed(changed) {}
virtual bool isReadOnly() const {
return mutability == READONLY;
}
virtual bool isWriteOnly() const {
return false;
}
virtual V getValue(const Reflection::DescribedBase* object) const {
const Class* c = static_cast<const Class*>(object);
return c->*member;
}
virtual void setValue(Reflection::DescribedBase* object, const V& value) const {
if (mutability == READONLY)
throw std::runtime_error("can't set value");
Class* c = static_cast<Class*>(object);
if (c->*member != value)
{
c->*member = value;
if (changed)
(c->*changed)(desc);
c->raisePropertyChanged(desc);
}
}
};
public:
template<class Class>
BoundProp(const char* name, const char* category, V Class::*member, void (Class::*changed)(const Reflection::PropertyDescriptor&), typename PropertyDescriptor::Attributes flags = PropertyDescriptor::STANDARD, Security::Permissions security = Security::None)
:Reflection::TypedPropertyDescriptor<V>(Class::classDescriptor(), name, category, std::auto_ptr<typename TypedPropertyDescriptor<V>::GetSet>(), flags, security)
{
this->getset.reset(new BoundPropGetSet<Class>(*this, member, changed));
this->checkFlags();
}
template<class Class>
BoundProp(const char* name, const char* category, V Class::*member, typename PropertyDescriptor::Attributes flags = PropertyDescriptor::STANDARD, Security::Permissions security = Security::None)
:Reflection::TypedPropertyDescriptor<V>(Class::classDescriptor(), name, category, std::auto_ptr<typename TypedPropertyDescriptor<V>::GetSet>(), flags, security)
{
this->getset.reset(new BoundPropGetSet<Class>(*this, member, NULL));
this->checkFlags();
}
};
}
}
+323
View File
@@ -0,0 +1,323 @@
#pragma once
#include "reflection/Descriptor.h"
#include <boost/any.hpp>
#include <boost/static_assert.hpp>
#include <util/utilities.h>
#include <boost/unordered_map.hpp>
#include <list>
namespace RBX
{
namespace Reflection
{
template<typename T> class TypeRegistrar;
// Types supported by the Reflection framework
class Type : public Descriptor
{
template<class T>
friend class TypeRegistrar;
template<class T>
static const Type& getSingleton(); // Must be implemented for each type used
void addToAllTypes();
public:
const Name& tag;
const bool isFloat;
const bool isNumber;
const bool isEnum;
static const std::vector<const Type*>& getAllTypes();
template<class T>
static inline const Type& singleton()
{
return getSingleton<T>();
}
bool operator==(const Type& right) const {
return this==&right;
}
bool operator!=(const Type& right) const {
return this!=&right;
}
template<class T>
bool isType() const {
return this == &getSingleton<T>();
}
protected:
template<class T>
Type(const char* name, T* dummy)
:Descriptor(name, Descriptor::Attributes())
,tag(Name::lookup(name))
,isNumber(boost::is_arithmetic<T>::value)
,isFloat(boost::is_float<T>::value)
,isEnum(false)
{
*isOutdated = false;
*isReplicable = true;
RBXASSERT(!this->tag.empty());
addToAllTypes();
}
template<class T>
Type(const char* name, const char* tag, T* dummy)
:Descriptor(name, Descriptor::Attributes())
,tag(Name::declare(tag))
,isNumber(boost::is_arithmetic<T>::value)
,isFloat(boost::is_float<T>::value)
,isEnum(false)
{
RBXASSERT(!this->tag.empty());
addToAllTypes();
}
Type(const char* name, const char* tag, bool isNumber, bool isFloat, bool isEnum)
:Descriptor(name, Descriptor::Attributes())
,tag(Name::declare(tag))
,isNumber(isNumber)
,isFloat(isFloat)
,isEnum(isEnum)
{
RBXASSERT(!this->tag.empty());
addToAllTypes();
}
};
std::ostream& operator<<(std::ostream& os, const RBX::Reflection::Type& type);
// Handy macro for registering a type
#define RBX_REGISTER_TYPE(mType) template<> RBX::Reflection::TypeRegistrar<mType> RBX::Reflection::TypeRegistrar<mType>::registrar(0)
// This class is designed to prevent clients of the library
// from forgetting to initialize their class descriptors
template<class T>
class TypeRegistrar : boost::noncopyable
{
int x;
//// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
TypeRegistrar(int i):x(i)
{
// This assertion is added to catch a nasty implicit use of boost::any with Variant objects.
// If you get a tricky link error, add your own assertion here
BOOST_STATIC_ASSERT((!boost::is_same<T, boost::any>::value));
// This call registers the Type descriptor
// in the reflection database
Type::getSingleton<T>();
}
public:
// The instantiation of this static member must be in a unit
// that is initialized in the main thread before any objects
// are created. Otherwise the reflection database
// can change at runtime, which would be a disaster
static TypeRegistrar registrar;
};
// Helper class
template<typename T>
class TType : public Type
{
friend class Type;
protected:
TType(const char* name)
:Type(name, (T*)NULL)
{
}
TType(const char* name, const char* tag)
:Type(name, tag, (T*)NULL)
{
}
};
class Variant
{
struct Storage
{
char data[96];
};
const Type* _type;
rbx::placement_any<Storage> value;
public:
inline Variant()
: _type(&Type::singleton<void>())
, value()
{}
inline Variant(const Variant& other)
: _type(other._type)
, value(other.value)
{}
inline Variant& operator=(const Variant& rhs)
{
_type = rhs._type;
value = rhs.value;
return *this;
}
template<typename ValueType>
inline Variant(const ValueType& value)
: _type(&Type::singleton<ValueType>())
, value(value)
{
}
template<typename ValueType>
inline Variant& operator=(const ValueType& rhs)
{
_type = &Type::singleton<ValueType>();
value = rhs;
return *this;
}
inline const Type& type() const {
return *_type;
}
inline bool isVoid() const
{
return *_type==Type::singleton<void>();
}
inline bool isFloat() const { return type().isFloat; }
inline bool isNumber() const { return type().isNumber; }
inline bool isString() const { return isType<std::string>();}
template<class ValueType>
inline bool isType() const {
return _type->isType<ValueType>();
}
// throws an exception if unable to convert
template<typename ValueType>
ValueType& convert();
// throws an exception if unable to convert
template<typename ValueType>
inline ValueType get() const
{
if (isType<ValueType>())
return cast<ValueType>();
else
{
// Create a non-const copy to extract the value from
Variant v(*this);
return v.convert<ValueType>();
}
}
template<typename T>
inline const T& cast() const {
if (!isType<T>())
throw std::runtime_error("Variant cast failed");
return *reinterpret_cast<const T*>(value.getData());
}
template<typename T>
inline T& cast() {
if (!isType<T>())
throw std::runtime_error("Variant cast failed");
return *reinterpret_cast<T*>(value.getData());
}
template<typename T>
inline const T* tryCast() const {
if (!isType<T>())
return NULL;
return reinterpret_cast<const T*>(value.getData());
}
template<typename T>
inline T* tryCast() {
if (!isType<T>())
return NULL;
return reinterpret_cast<T*>(value.getData());
}
private:
template<class ValueType>
ValueType& genericConvert();
};
// Equivalent to an array in Lua
typedef std::vector<Variant> ValueArray;
// A limited table in Lua (keys must be strings for now)
typedef boost::unordered_map<std::string, Variant> ValueTable;
struct Tuple
{
ValueArray values;
Tuple() {}
Tuple(size_t count):values(count) {}
Tuple(const Tuple& other):values(other.values) {}
//Tuple(const ValueArray& values):values(values) {}
Variant& at(size_t i) { return values[i]; }
const Variant& at(size_t i) const { return values[i]; }
};
// The same as a ValueTable for now, but will always have a string key.
// TODO: Use boost::unordered_map<> or vector<> instead?
typedef std::map<std::string, Variant> ValueMap;
// Describes a function's signature
class SignatureDescriptor
{
public:
struct Item {
friend class SignatureDescriptor;
public:
Item(const RBX::Name* name, const Type* type, const Variant& defaultValue);
Item(const RBX::Name* name, const Type* type);
const RBX::Name* name;
const Type* type;
const Variant defaultValue;
bool hasDefaultValue() const
{
return defaultValue.type() == *type;
}
};
// TODO: Would vector be more efficient?
typedef std::list<Item> Arguments;
const Type* resultType;
Arguments arguments;
void addArgument(const RBX::Name& name, const Type& type);
void addArgument(const RBX::Name& name, const Type& type, const Variant& defaultValue);
SignatureDescriptor();
};
template<class ValueType>
ValueType& RBX::Reflection::Variant::genericConvert()
{
ValueType* id = tryCast<ValueType>();
if (id!=NULL)
return *id;
if (_type->isType<std::string>())
{
ValueType v;
if (StringConverter<ValueType>::convertToValue(cast<std::string>(), v))
{
value = v;
_type = &Type::singleton<ValueType>();
return cast<ValueType>();
}
}
throw RBX::runtime_error("Unable to cast %s to %s", _type->tag.c_str(), Type::singleton<ValueType>().tag.c_str() );
}
}
}
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#include "Reflection/Function.h"
#include <boost/function.hpp>
namespace RBX
{
namespace Reflection
{
class YieldFunction;
// Base that describes a YieldFunction
class RBXBaseClass YieldFunctionDescriptor : public MemberDescriptor
{
public:
typedef YieldFunction ConstMember;
typedef YieldFunction Member;
protected:
SignatureDescriptor signature;
YieldFunctionDescriptor(ClassDescriptor& classDescriptor, const char* name, Security::Permissions security, Attributes attributes);
public:
const SignatureDescriptor& getSignature() const { return signature; }
virtual void execute(DescribedBase* instance, FunctionDescriptor::Arguments& arguments, boost::function<void(Variant)> resumeFunction, boost::function<void(std::string)> errorFunction) const = 0;
};
// A light-weight convenience class that associates a FunctionDescriptor
// with a described object to create a "Function"
class YieldFunction
{
protected:
const YieldFunctionDescriptor* descriptor;
DescribedBase* instance;
public:
inline YieldFunction(const YieldFunctionDescriptor& descriptor, DescribedBase* instance)
:descriptor(&descriptor),instance(instance)
{}
inline YieldFunction(const YieldFunction& other)
:descriptor(other.descriptor),instance(other.instance)
{}
inline YieldFunction& operator =(const YieldFunction& other)
{
this->descriptor = other.descriptor;
this->instance = other.instance;
return *this;
}
inline const RBX::Name& getName() const {
return descriptor->name;
}
inline const YieldFunctionDescriptor* getDescriptor() const {
return descriptor;
}
void execute(FunctionDescriptor::Arguments& arguments, boost::function<void(Variant)> resumeFunction, boost::function<void(std::string)> errorFunction) const {
return descriptor->execute(const_cast<DescribedBase*>(instance), arguments, resumeFunction, errorFunction);
}
};
}
}
+353
View File
@@ -0,0 +1,353 @@
#pragma once
#include "reflection/Descriptor.h"
#include "util/Exception.h"
#include <vector>
#include "security/SecurityContext.h"
#include "rbx/DenseHash.h"
namespace RBX
{
namespace Reflection
{
class ClassDescriptor;
class DescribedBase;
struct StringHashPredicate
{
size_t operator()(const char* s) const;
};
struct StringEqualPredicate
{
bool operator()(const char* lhs, const char* rhs) const
{
return strcmp(lhs, rhs) == 0;
}
};
// Base class of describing a described object's member: (Member, Event, etc.)
class RBXBaseClass MemberDescriptor : public Descriptor
{
public:
static void (*memberHidingHook)(MemberDescriptor*, MemberDescriptor*);
// Category is a name used to group properties in the UI
const RBX::Name& category;
const ClassDescriptor& owner;
const Security::Permissions security;
protected:
MemberDescriptor(const ClassDescriptor& owner, const char* name, const char* category, Attributes attributes, Security::Permissions security)
:Descriptor(name, attributes)
,owner(owner)
,category(RBX::Name::declare(category))
,security(security)
{
}
virtual ~MemberDescriptor() {}
public:
bool isMemberOf(const ClassDescriptor& classDescriptor) const;
bool isMemberOf(const DescribedBase* instance) const;
};
class MemberException : public std::runtime_error
{
public:
const MemberDescriptor& desc;
MemberException(const MemberDescriptor& desc, const std::string& _Message)
:std::runtime_error(_Message)
,desc(desc)
{
}
};
template<class MemberDescriptorType>
class MemberDescriptorContainer
{
// Used for sorting
static bool compare(const MemberDescriptorType* a, const MemberDescriptorType* b)
{
return a->name < b->name;
}
public:
class Collection : public std::vector<MemberDescriptorType*>
{
};
typedef DenseHashMap<const char*, MemberDescriptorType*, StringHashPredicate, StringEqualPredicate> DescriptorLookup;
typedef typename MemberDescriptorType::ConstMember ConstMemberType;
typedef typename MemberDescriptorType::Member MemberType;
class ConstIterator : public std::iterator<std::forward_iterator_tag, MemberType, void, MemberType>
{
friend class ClassDescriptor;
const DescribedBase* instance;
typename Collection::const_iterator iter;
public:
ConstIterator(const typename Collection::const_iterator& iter, const DescribedBase* instance)
:iter(iter),instance(instance)
{}
ConstMemberType operator*() const
{ // return designated object
return ConstMemberType(**iter, instance);
}
bool operator==(const ConstIterator& other) const { return iter==other.iter; }
bool operator!=(const ConstIterator& other) const { return iter!=other.iter; }
ConstIterator& operator++()
{ // preincrement
++iter;
return (*this);
}
ConstIterator operator++(int)
{ // postincrement
ConstIterator _Tmp = *this;
++*this;
return (_Tmp);
}
const MemberDescriptorType& getDescriptor() const { return **iter; }
};
class Iterator : public std::iterator<std::forward_iterator_tag, MemberType, void, MemberType>
{
friend class ClassDescriptor;
DescribedBase* instance;
// iter is a const iterator, since we never modifiy the collection of descriptors
typename Collection::const_iterator iter;
public:
Iterator(const typename Collection::const_iterator& iter, DescribedBase* instance)
:iter(iter),instance(instance)
{}
MemberType operator*() const
{ // return designated object
return MemberType(**iter, instance);
}
bool operator==(const Iterator& other) const { return iter==other.iter; }
bool operator!=(const Iterator& other) const { return iter!=other.iter; }
Iterator& operator++()
{ // preincrement
++iter;
return (*this);
}
Iterator operator++(int)
{ // postincrement
Iterator _Tmp = *this;
++*this;
return (_Tmp);
}
};
protected:
Collection descriptors;
DescriptorLookup descriptorLookup;
private:
static Collection& staticData()
{
static Collection result;
return result;
}
static void initStaticData()
{
staticData();
}
static Collection& allDescriptors()
{
static boost::once_flag flag = BOOST_ONCE_INIT;
boost::call_once(&initStaticData, flag);
return staticData();
}
protected:
// This is a list of "subclasses"
std::vector<MemberDescriptorContainer*> derivedContainers;
MemberDescriptorContainer* const base;
protected:
MemberDescriptorContainer(MemberDescriptorContainer* base)
:base(base), descriptorLookup("")
{
if (base!=NULL)
{
// Grab base members that have already been declared
mergeMembers(base);
// Subsequent members declared in a base class will be pushed down in the declare() function
base->derivedContainers.push_back(this);
}
}
void declareSub(MemberDescriptorType* descriptor, MemberDescriptorType* replaceable)
{
RBXASSERT(replaceable != descriptor);
{
typename Collection::iterator iter = std::lower_bound(descriptors.begin(), descriptors.end(), descriptor, compare);
if (iter == descriptors.end())
{
descriptors.insert(iter, descriptor);
descriptorLookup[descriptor->name.c_str()] = descriptor;
}
else
{
RBXASSERT(*iter != descriptor);
if (*iter == replaceable)
{
// Replace it
*iter = descriptor;
descriptorLookup[descriptor->name.c_str()] = descriptor;
}
else if ((*iter)->name != descriptor->name)
{
descriptors.insert(iter, descriptor);
descriptorLookup[descriptor->name.c_str()] = descriptor;
}
else
{
// We've hit upon a member that will hide this member
if (MemberDescriptor::memberHidingHook)
(*MemberDescriptor::memberHidingHook)(descriptor, replaceable);
return; // No need to continue
}
}
}
// recurse:
for (typename std::vector<MemberDescriptorContainer*>::iterator iter = derivedContainers.begin(); iter != derivedContainers.end(); ++iter)
(*iter)->declareSub(descriptor, replaceable);
}
public:
void declare(MemberDescriptorType* descriptor)
{
MemberDescriptorType* replaceable = NULL;
{
typename Collection::iterator iter = std::lower_bound(descriptors.begin(), descriptors.end(), descriptor, compare);
if (iter == descriptors.end())
{
// add a new one
descriptors.insert(iter, descriptor);
descriptorLookup[descriptor->name.c_str()] = descriptor;
}
else if (*iter == descriptor)
{
// drop out if we've been here before
return;
}
else if ((*iter)->name != descriptor->name)
{
// add a new one
descriptors.insert(iter, descriptor);
descriptorLookup[descriptor->name.c_str()] = descriptor;
}
else
{
// hide a member of a base class
// TODO: Eventually we'd like to nuke this feature, but it is
// required for some legacy things, like BoolValue
replaceable = *iter;
*iter = descriptor;
descriptorLookup[descriptor->name.c_str()] = descriptor;
if (MemberDescriptor::memberHidingHook)
(*MemberDescriptor::memberHidingHook)(descriptor, replaceable);
}
}
// Also declare this member in sub-classes
for (typename std::vector<MemberDescriptorContainer*>::iterator iter = derivedContainers.begin(); iter != derivedContainers.end(); ++iter)
(*iter)->declareSub(descriptor, replaceable);
// Add this to allDescriptors (in a determanistic order)
{
typename Collection::iterator iter = allDescriptors().begin();
while (iter!=allDescriptors().end())
{
MemberDescriptorType* desc = *iter;
if (desc==descriptor)
goto SKIP;
int compare = RBX::Name::compare(descriptor->name, desc->name);
if (compare<0)
break;
if (compare==0)
{
// This descriptor name already exists in a different class
compare = RBX::Name::compare(descriptor->owner.name, desc->owner.name);
// Enforce order using class name
if (compare<0)
break;
}
++iter;
}
allDescriptors().insert(iter, descriptor);
SKIP: ;
}
}
/////////////////////////////////////////////////////////////////
// Type info enumeration
typename Collection::const_iterator descriptors_begin() const {
return descriptors.begin();
}
typename Collection::const_iterator descriptors_end() const {
return descriptors.end();
}
size_t descriptor_size() const
{
return descriptors.size();
}
/////////////////////////////////////////////////////////////////
// Enumeration of all descriptors
static typename Collection::const_iterator all_begin() {
return allDescriptors().begin();
}
static typename Collection::const_iterator all_end() {
return allDescriptors().end();
}
/////////////////////////////////////////////////////////////////
// Type info query
MemberDescriptorType* findDescriptor(const char* name) const
{
MemberDescriptorType* const * item = descriptorLookup.find(name);
return item ? *item : NULL;
}
/////////////////////////////////////////////////////////////////
// Member enumeration
ConstIterator members_begin(const DescribedBase* instance) const {
return ConstIterator(descriptors.begin(), instance);
}
ConstIterator members_end(const DescribedBase* instance) const {
return ConstIterator(descriptors.end(), instance);
}
Iterator members_begin(DescribedBase* instance) const {
return Iterator(descriptors.begin(), instance);
}
Iterator members_end(DescribedBase* instance) const {
return Iterator(descriptors.end(), instance);
}
protected:
void mergeMembers(const MemberDescriptorContainer* source)
{
for (typename Collection::const_iterator iter = source->descriptors.begin(); iter != source->descriptors.end(); ++iter)
declare(*iter);
// Recursively merge parent members as well
if (source->base!=NULL)
mergeMembers(source->base);
}
};
}
}
File diff suppressed because it is too large Load Diff