瀏覽代碼

Trying to implement const support in data bindings (WIP)

Co-authored-by: Omegapl <[email protected]>
Michael Ragazzon 4 年之前
父節點
當前提交
d5f215b5cb

+ 1 - 1
Include/RmlUi/Core/DataModelHandle.h

@@ -72,7 +72,7 @@ public:
 	template<typename T>
 	bool Bind(const String& name, T* ptr) {
 		RMLUI_ASSERTMSG(ptr, "Invalid pointer to data variable");
-		return BindVariable(name, DataVariable(type_register->GetDefinition<T>(), static_cast<void*>(ptr)));
+		return BindVariable(name, DataVariable(type_register->GetDefinition<T>(), DataPointer(ptr)));
 	}
 	
 	// Bind a get/set function pair.

+ 0 - 1
Include/RmlUi/Core/DataStructHandle.h

@@ -144,7 +144,6 @@ bool StructHandle<Object>::CreateMemberObjectDefinition(const String& name, Memb
 
 	// If the member function signature doesn't match the getter function signature, it will end up calling this function. Emit a compile error in that case.
 	static_assert(!std::is_member_function_pointer<MemberObjectPtr>::value, "Illegal data member getter function signature. Make sure it takes no arguments and is not const qualified.");
-	static_assert(!std::is_const<MemberType>::value, "Data member objects cannot be const qualified.");
 
 	VariableDefinition* underlying_definition = type_register->GetDefinition<MemberType>();
 	if (!underlying_definition)

+ 0 - 2
Include/RmlUi/Core/DataTypeRegister.h

@@ -82,7 +82,6 @@ private:
 	template<typename T, typename std::enable_if<!PointerTraits<T>::is_pointer::value && is_builtin_data_scalar<T>::value, int>::type = 0>
 	VariableDefinition* GetDefinitionDetail()
 	{
-		static_assert(!std::is_const<T>::value, "Data binding variables cannot point to constant variables.");
 		FamilyId id = Family<T>::Id();
 
 		auto result = type_register.emplace(id, nullptr);
@@ -120,7 +119,6 @@ private:
 
 		using UnderlyingType = typename PointerTraits<T>::element_type;
 		static_assert(!PointerTraits<UnderlyingType>::is_pointer::value, "Recursive pointer types (pointer to pointer) to data variables are disallowed.");
-		static_assert(!std::is_const<UnderlyingType>::value, "Pointer to a const data variable is not supported.");
 
 		// Get the underlying definition.
 		VariableDefinition* underlying_definition = GetDefinitionDetail<UnderlyingType>();

+ 28 - 9
Include/RmlUi/Core/DataTypes.h

@@ -65,36 +65,55 @@ struct DataAddressEntry {
 };
 using DataAddress = Vector<DataAddressEntry>;
 
+// DataPointer is a wrapper around void* which preserves the constness of the underlying object.
+class DataPointer {
+public:
+	DataPointer(std::nullptr_t) : ptr(nullptr), cptr(nullptr) {};
+	DataPointer(void* p) : ptr(p), cptr(p) {};
+	DataPointer(const void* p) : ptr(nullptr), cptr(p) {};
+
+	template<typename T, typename std::enable_if<!std::is_const<typename std::remove_pointer<T>::type>::value, int>::type = 0>
+	T Get() {
+		return static_cast<T>(ptr);
+	}
+	template<typename T, typename std::enable_if<std::is_const<typename std::remove_pointer<T>::type>::value, int>::type = 0>
+	T Get() {
+		return static_cast<T>(cptr);
+	}
+
+private:
+	void* ptr = nullptr;
+	const void* cptr = nullptr;
+};
+
 template<class T>
 struct PointerTraits {
 	using is_pointer = std::false_type;
 	using element_type = T;
-	static void* Dereference(void* ptr) {
-		return ptr;
-	}
+	// Dereference() function intentionally missing.
 };
 template<class T>
 struct PointerTraits<T*> {
 	using is_pointer = std::true_type;
 	using element_type = T;
-	static void* Dereference(void* ptr) {
-		return static_cast<void*>(*static_cast<T**>(ptr));
+	static DataPointer Dereference(DataPointer ptr) {
+		return DataPointer(*ptr.Get<T**>());
 	}
 };
 template<class T>
 struct PointerTraits<UniquePtr<T>> {
 	using is_pointer = std::true_type;
 	using element_type = T;
-	static void* Dereference(void* ptr) {
-		return static_cast<void*>(static_cast<UniquePtr<T>*>(ptr)->get());
+	static DataPointer Dereference(DataPointer ptr) {
+		return DataPointer(ptr.Get<UniquePtr<T>*>()->get());
 	}
 };
 template<class T>
 struct PointerTraits<SharedPtr<T>> {
 	using is_pointer = std::true_type;
 	using element_type = T;
-	static void* Dereference(void* ptr) {
-		return static_cast<void*>(static_cast<SharedPtr<T>*>(ptr)->get());
+	static DataPointer Dereference(DataPointer ptr) {
+		return DataPointer(ptr.Get<SharedPtr<T>*>()->get());
 	}
 };
 

+ 42 - 43
Include/RmlUi/Core/DataVariable.h

@@ -50,7 +50,7 @@ enum class DataVariableType { Scalar, Array, Struct };
 class RMLUICORE_API DataVariable {
 public:
 	DataVariable() {}
-	DataVariable(VariableDefinition* definition, void* ptr) : definition(definition), ptr(ptr) {}
+	DataVariable(VariableDefinition* definition, DataPointer ptr) : definition(definition), ptr(ptr) {}
 
 	explicit operator bool() const { return definition; }
 
@@ -62,7 +62,7 @@ public:
 
 private:
 	VariableDefinition* definition = nullptr;
-	void* ptr = nullptr;
+	DataPointer ptr = nullptr;
 };
 
 
@@ -77,11 +77,11 @@ public:
 	virtual ~VariableDefinition() = default;
 	DataVariableType Type() const { return type; }
 
-	virtual bool Get(void* ptr, Variant& variant);
-	virtual bool Set(void* ptr, const Variant& variant);
+	virtual bool Get(DataPointer ptr, Variant& variant);
+	virtual bool Set(DataPointer ptr, const Variant& variant);
 
-	virtual int Size(void* ptr);
-	virtual DataVariable Child(void* ptr, const DataAddressEntry& address);
+	virtual int Size(DataPointer ptr);
+	virtual DataVariable Child(DataPointer ptr, const DataAddressEntry& address);
 
 protected:
 	VariableDefinition(DataVariableType type) : type(type) {}
@@ -99,14 +99,14 @@ class ScalarDefinition final : public VariableDefinition {
 public:
 	ScalarDefinition() : VariableDefinition(DataVariableType::Scalar) {}
 
-	bool Get(void* ptr, Variant& variant) override
+	bool Get(DataPointer ptr, Variant& variant) override
 	{
-		variant = *static_cast<const T*>(ptr);
+		variant = *ptr.Get<T*>();
 		return true;
 	}
-	bool Set(void* ptr, const Variant& variant) override
+	bool Set(DataPointer ptr, const Variant& variant) override
 	{
-		return variant.GetInto<T>(*static_cast<T*>(ptr));
+		return variant.GetInto<T>(*ptr.Get<T*>());
 	}
 };
 
@@ -115,8 +115,8 @@ class RMLUICORE_API FuncDefinition final : public VariableDefinition {
 public:
 	FuncDefinition(DataGetFunc get, DataSetFunc set);
 
-	bool Get(void* ptr, Variant& variant) override;
-	bool Set(void* ptr, const Variant& variant) override;
+	bool Get(DataPointer ptr, Variant& variant) override;
+	bool Set(DataPointer ptr, const Variant& variant) override;
 
 private:
 	DataGetFunc get;
@@ -129,18 +129,18 @@ class ScalarFuncDefinition final : public VariableDefinition {
 public:
 	ScalarFuncDefinition(DataTypeGetFunc<T> get, DataTypeSetFunc<T> set) : VariableDefinition(DataVariableType::Scalar), get(get), set(set) {}
 
-	bool Get(void* ptr, Variant& variant) override
+	bool Get(DataPointer ptr, Variant& variant) override
 	{
 		if (!get)
 			return false;
-		get(*static_cast<const T*>(ptr), variant);
+		get(*ptr.Get<T*>(), variant);
 		return true;
 	}
-	bool Set(void* ptr, const Variant& variant) override
+	bool Set(DataPointer ptr, const Variant& variant) override
 	{
 		if (!set)
 			return false;
-		set(*static_cast<T*>(ptr), variant);
+		set(*ptr.Get<T*>(), variant);
 		return true;
 	}
 
@@ -154,7 +154,7 @@ class RMLUICORE_API StructDefinition final : public VariableDefinition {
 public:
 	StructDefinition();
 
-	DataVariable Child(void* ptr, const DataAddressEntry& address) override;
+	DataVariable Child(DataPointer ptr, const DataAddressEntry& address) override;
 
 	void AddMember(const String& name, UniquePtr<VariableDefinition> member);
 
@@ -168,14 +168,14 @@ class ArrayDefinition final : public VariableDefinition {
 public:
 	ArrayDefinition(VariableDefinition* underlying_definition) : VariableDefinition(DataVariableType::Array) , underlying_definition(underlying_definition) {}
 
-	int Size(void* ptr) override {
-		return int(static_cast<Container*>(ptr)->size());
+	int Size(DataPointer ptr) override {
+		return int(ptr.Get<Container*>()->size());
 	}
 
 protected:
-	DataVariable Child(void* void_ptr, const DataAddressEntry& address) override
+	DataVariable Child(DataPointer void_ptr, const DataAddressEntry& address) override
 	{
-		Container* ptr = static_cast<Container*>(void_ptr);
+		Container* ptr = void_ptr.Get<Container*>();
 		const int index = address.index;
 
 		const int container_size = int(ptr->size());
@@ -191,7 +191,7 @@ protected:
 		auto it = ptr->begin();
 		std::advance(it, index);
 
-		void* next_ptr = &(*it);
+		DataPointer next_ptr = &(*it);
 		return DataVariable(underlying_definition, next_ptr);
 	}
 
@@ -204,13 +204,13 @@ class RMLUICORE_API BasePointerDefinition : public VariableDefinition {
 public:
 	BasePointerDefinition(VariableDefinition* underlying_definition);
 
-	bool Get(void* ptr, Variant& variant) override;
-	bool Set(void* ptr, const Variant& variant) override;
-	int Size(void* ptr) override;
-	DataVariable Child(void* ptr, const DataAddressEntry& address) override;
+	bool Get(DataPointer ptr, Variant& variant) override;
+	bool Set(DataPointer ptr, const Variant& variant) override;
+	int Size(DataPointer ptr) override;
+	DataVariable Child(DataPointer ptr, const DataAddressEntry& address) override;
 
 protected:
-	virtual void* DereferencePointer(void* ptr) = 0;
+	virtual DataPointer DereferencePointer(DataPointer ptr) = 0;
 
 private:
 	VariableDefinition* underlying_definition;
@@ -222,7 +222,7 @@ public:
 	PointerDefinition(VariableDefinition* underlying_definition) : BasePointerDefinition(underlying_definition) {}
 
 protected:
-	void* DereferencePointer(void* ptr) override {
+	DataPointer DereferencePointer(DataPointer ptr) override {
 		return PointerTraits<T>::Dereference(ptr);
 	}
 };
@@ -233,8 +233,8 @@ public:
 	MemberObjectDefinition(VariableDefinition* underlying_definition, MemberType Object::* member_ptr) : BasePointerDefinition(underlying_definition), member_ptr(member_ptr) {}
 
 protected:
-	void* DereferencePointer(void* base_ptr) override {
-		return &(static_cast<Object*>(base_ptr)->*member_ptr);
+	DataPointer DereferencePointer(DataPointer base_ptr) override {
+		return &(base_ptr.Get<Object*>()->*member_ptr);
 	}
 
 private:
@@ -245,14 +245,13 @@ private:
 template<typename Object, typename MemberType, typename BasicReturnType>
 class MemberGetFuncDefinition final : public BasePointerDefinition {
 public:
-
 	MemberGetFuncDefinition(VariableDefinition* underlying_definition, MemberType Object::* member_get_func_ptr)
 		: BasePointerDefinition(underlying_definition), member_get_func_ptr(member_get_func_ptr)
 	{}
 
 protected:
-	void* DereferencePointer(void* base_ptr) override {
-		return static_cast<void*>(Extract((static_cast<Object*>(base_ptr)->*member_get_func_ptr)()));
+	DataPointer DereferencePointer(DataPointer base_ptr) override {
+		return DataPointer(Extract((base_ptr.Get<Object*>()->*member_get_func_ptr)()));
 	}
 
 private:
@@ -274,46 +273,46 @@ public:
 		: VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition), member_get_func_ptr(member_get_func_ptr), member_set_func_ptr(member_set_func_ptr)
 	{}
 
-	bool Get(void* ptr, Variant& variant) override {
+	bool Get(DataPointer ptr, Variant& variant) override {
 		return GetDetail(ptr, variant);
 	}
-	bool Set(void* ptr, const Variant& variant) override {
+	bool Set(DataPointer ptr, const Variant& variant) override {
 		return SetDetail(ptr, variant);
 	}
 
 private:
 	template<typename T = MemberGetType, typename std::enable_if<IsVoidMemberFunc<T>::value, int>::type = 0>
-	bool GetDetail(void* /*ptr*/, Variant& /*variant*/)
+	bool GetDetail(DataPointer /*ptr*/, Variant& /*variant*/)
 	{
 		return false;
 	}
 
 	template<typename T = MemberGetType, typename std::enable_if<!IsVoidMemberFunc<T>::value, int>::type = 0>
-	bool GetDetail(void* ptr, Variant& variant)
+	bool GetDetail(DataPointer ptr, Variant& variant)
 	{
 		RMLUI_ASSERT(member_get_func_ptr);
 
-		auto&& value = (static_cast<Object*>(ptr)->*member_get_func_ptr)();
-		bool result = underlying_definition->Get(static_cast<void*>(&value), variant);
+		auto&& value = (ptr.Get<Object*>()->*member_get_func_ptr)();
+		bool result = underlying_definition->Get(DataPointer(&value), variant);
 		return result;
 	}
 
 	template<typename T = MemberSetType, typename std::enable_if<IsVoidMemberFunc<T>::value, int>::type = 0>
-	bool SetDetail(void* /*ptr*/, const Variant& /*variant*/)
+	bool SetDetail(DataPointer /*ptr*/, const Variant& /*variant*/)
 	{
 		return false;
 	}
 
 	template<typename T = MemberSetType, typename std::enable_if<!IsVoidMemberFunc<T>::value, int>::type = 0>
-	bool SetDetail(void* ptr, const Variant& variant)
+	bool SetDetail(DataPointer ptr, const Variant& variant)
 	{
 		RMLUI_ASSERT(member_set_func_ptr);
 
 		UnderlyingType result;
-		if (!underlying_definition->Set(static_cast<void*>(&result), variant))
+		if (!underlying_definition->Set(DataPointer(&result), variant))
 			return false;
 
-		(static_cast<Object*>(ptr)->*member_set_func_ptr)(result);
+		(ptr.Get<Object*>()->*member_set_func_ptr)(result);
 
 		return true;
 	}

+ 14 - 14
Source/Core/DataVariable.cpp

@@ -51,19 +51,19 @@ DataVariableType DataVariable::Type() {
 }
 
 
-bool VariableDefinition::Get(void* /*ptr*/, Variant& /*variant*/) {
+bool VariableDefinition::Get(DataPointer /*ptr*/, Variant& /*variant*/) {
     Log::Message(Log::LT_WARNING, "Values can only be retrieved from scalar data types.");
     return false;
 }
-bool VariableDefinition::Set(void* /*ptr*/, const Variant& /*variant*/) {
+bool VariableDefinition::Set(DataPointer /*ptr*/, const Variant& /*variant*/) {
     Log::Message(Log::LT_WARNING, "Values can only be assigned to scalar data types.");
     return false;
 }
-int VariableDefinition::Size(void* /*ptr*/) {
+int VariableDefinition::Size(DataPointer /*ptr*/) {
     Log::Message(Log::LT_WARNING, "Tried to get the size from a non-array data type.");
     return 0;
 }
-DataVariable VariableDefinition::Child(void* /*ptr*/, const DataAddressEntry& /*address*/) {
+DataVariable VariableDefinition::Child(DataPointer /*ptr*/, const DataAddressEntry& /*address*/) {
     Log::Message(Log::LT_WARNING, "Tried to get the child of a scalar type.");
     return DataVariable();
 }
@@ -72,9 +72,9 @@ class LiteralIntDefinition final : public VariableDefinition {
 public:
     LiteralIntDefinition() : VariableDefinition(DataVariableType::Scalar) {}
 
-    bool Get(void* ptr, Variant& variant) override
+    bool Get(DataPointer ptr, Variant& variant) override
     {
-        variant = static_cast<int>(reinterpret_cast<intptr_t>(ptr));
+        variant = static_cast<int>(reinterpret_cast<intptr_t>(ptr.Get<const void*>()));
         return true;
     }
 };
@@ -82,13 +82,13 @@ public:
 DataVariable MakeLiteralIntVariable(int value)
 {
     static LiteralIntDefinition literal_int_definition;
-    return DataVariable(&literal_int_definition, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
+    return DataVariable(&literal_int_definition, reinterpret_cast<const void*>(static_cast<intptr_t>(value)));
 }
 
 StructDefinition::StructDefinition() : VariableDefinition(DataVariableType::Struct)
 {}
 
-DataVariable StructDefinition::Child(void* ptr, const DataAddressEntry& address)
+DataVariable StructDefinition::Child(DataPointer ptr, const DataAddressEntry& address)
 {
     const String& name = address.name;
     if (name.empty())
@@ -120,7 +120,7 @@ void StructDefinition::AddMember(const String& name, UniquePtr<VariableDefinitio
 FuncDefinition::FuncDefinition(DataGetFunc get, DataSetFunc set)
     : VariableDefinition(DataVariableType::Scalar), get(std::move(get)), set(std::move(set)) {}
 
-bool FuncDefinition::Get(void* /*ptr*/, Variant& variant)
+bool FuncDefinition::Get(DataPointer /*ptr*/, Variant& variant)
 {
     if (!get)
         return false;
@@ -128,7 +128,7 @@ bool FuncDefinition::Get(void* /*ptr*/, Variant& variant)
     return true;
 }
 
-bool FuncDefinition::Set(void* /*ptr*/, const Variant& variant)
+bool FuncDefinition::Set(DataPointer /*ptr*/, const Variant& variant)
 {
     if (!set)
         return false;
@@ -139,22 +139,22 @@ bool FuncDefinition::Set(void* /*ptr*/, const Variant& variant)
 BasePointerDefinition::BasePointerDefinition(VariableDefinition* underlying_definition)
     : VariableDefinition(underlying_definition->Type()), underlying_definition(underlying_definition) {}
 
-bool BasePointerDefinition::Get(void* ptr, Variant& variant)
+bool BasePointerDefinition::Get(DataPointer ptr, Variant& variant)
 {
     return underlying_definition->Get(DereferencePointer(ptr), variant);
 }
 
-bool BasePointerDefinition::Set(void* ptr, const Variant& variant)
+bool BasePointerDefinition::Set(DataPointer ptr, const Variant& variant)
 {
     return underlying_definition->Set(DereferencePointer(ptr), variant);
 }
 
-int BasePointerDefinition::Size(void* ptr)
+int BasePointerDefinition::Size(DataPointer ptr)
 {
     return underlying_definition->Size(DereferencePointer(ptr));
 }
 
-DataVariable BasePointerDefinition::Child(void* ptr, const DataAddressEntry& address)
+DataVariable BasePointerDefinition::Child(DataPointer ptr, const DataAddressEntry& address)
 {
     return underlying_definition->Child(DereferencePointer(ptr), address);
 }

+ 75 - 6
Tests/Source/UnitTests/DataBinding.cpp

@@ -67,13 +67,14 @@ static const String document_rml = R"(
 <body template="window">
 <div data-model="basics">
 
-<input type="text" data-value="i0"/>
+<input type="text" data-value="arrays.x0[1]"/>
 
 <h1>Globals</h1>
 <p>{{ i0 }}</p>
 <p>{{ i1 }}</p>
 <p>{{ i2 }}</p>
 <p>{{ i3 }}</p>
+<p>{{ x1 }}</p>
 
 <p>{{ s0 }}</p>
 <p>{{ s1 }}</p>
@@ -109,6 +110,11 @@ static const String document_rml = R"(
 <p><span data-for="arrays.d">{{ it.val }} </span></p>
 <p><span data-for="arrays.e">{{ it.val }} </span></p>
 
+<p><span data-for="arrays.x0">{{ it }} </span></p>
+
+<p>The next line crashes the program:</p>
+<!-- <p><span data-for="arrays.x2">{{ it }} </span></p> -->
+
 </div>
 </body>
 </rml>
@@ -280,11 +286,13 @@ struct Arrays
 	Vector<StringWrap> c = { StringWrap("c1"), StringWrap("c2"), StringWrap("c3") };
 	Vector<StringWrap*> d = { new StringWrap("d1"), new StringWrap("d2"), new StringWrap("d3") };
 	Vector<StringWrapPtr> e;
-	
+
 	// Invalid: const pointer
 	Vector<const int*> x0 = { new int(30), new int(31), new int(32) };
 	// Invalid: const pointer
 	Vector<UniquePtr<const StringWrap>> x1;
+	// Invalid: const object
+	const Vector<int*> x2 = { new int(20), new int(21), new int(22) };
 	
 	Arrays() {
 		e.emplace_back(MakeUnique<StringWrap>("e1"));
@@ -299,6 +307,65 @@ struct Arrays
 DataModelHandle model_handle;
 
 
+TEST_CASE("databinding.types")
+{
+	static_assert(!PointerTraits<int>::is_pointer::value, "");
+	static_assert(!PointerTraits<int&>::is_pointer::value, "");
+	static_assert(PointerTraits<int*>::is_pointer::value, "");
+	static_assert(PointerTraits<UniquePtr<int>>::is_pointer::value, "");
+	static_assert(PointerTraits<UniquePtr<const int>>::is_pointer::value, "");
+	static_assert(PointerTraits<SharedPtr<int>>::is_pointer::value, "");
+	static_assert(PointerTraits<SharedPtr<const int>>::is_pointer::value, "");
+
+	static_assert(std::is_same<int,       PointerTraits<int>::element_type>::value, "");
+	static_assert(std::is_same<const int, PointerTraits<const int>::element_type>::value, "");
+	static_assert(std::is_same<int&,      PointerTraits<int&>::element_type>::value, "");
+
+	static_assert(std::is_same<int,  PointerTraits<int*>::element_type>::value, "");
+	static_assert(std::is_same<int,  PointerTraits<UniquePtr<int>>::element_type>::value, "");
+	static_assert(std::is_same<int,  PointerTraits<SharedPtr<int>>::element_type>::value, "");
+	static_assert(std::is_same<int,  PointerTraits<SharedPtr<int>>::element_type>::value, "");
+	static_assert(std::is_same<int*, PointerTraits<int**>::element_type>::value, "");
+
+
+	{
+		int x = 10;
+		DataPointer ptr(&x);
+		*ptr.Get<int*>() += 5;
+
+		CHECK(x == 15);
+		CHECK(x == *ptr.Get<int*>());
+	}
+
+	{
+		UniquePtr<int> u = MakeUnique<int>(20);
+		DataPointer ptr(&u);
+		CHECK(ptr.Get<UniquePtr<int>*>() == &u);
+
+		DataPointer ptr_underlying = PointerTraits< UniquePtr<int> >::Dereference(ptr);
+		CHECK(ptr_underlying.Get<int*>() == u.get());
+
+		int u_out = *ptr_underlying.Get<int*>();
+		CHECK(*u == u_out);
+
+		*ptr_underlying.Get<int*>() += 5;
+		CHECK(*u == 25);
+	}
+
+	{
+		UniquePtr<const int> u = MakeUnique<const int>(20);
+		DataPointer ptr(&u);
+		CHECK(ptr.Get<UniquePtr<const int>*>() == &u);
+
+		DataPointer ptr_underlying = PointerTraits< UniquePtr<const int> >::Dereference(ptr);
+		CHECK(ptr_underlying.Get<const int*>() == u.get());
+		CHECK(ptr_underlying.Get<int*>() == nullptr);
+
+		int u_out = *ptr_underlying.Get<const int*>();
+		CHECK(*u == u_out);
+	}
+}
+
 
 bool InitializeDataBindings(Context* context)
 {
@@ -326,8 +393,8 @@ bool InitializeDataBindings(Context* context)
 		constructor.Bind("s5", &globals.s5);
 
 		// Invalid: Each of the following should give a compile-time failure.
-		//constructor.Bind("x0", &globals.x0);
-		//constructor.Bind("x1", &globals.x1);
+		constructor.Bind("x0", &globals.x0);
+		constructor.Bind("x1", &globals.x1);
 		//constructor.Bind("x2", &globals.x2);
 		//constructor.Bind("x3", &globals.x3);
 		//constructor.Bind("x4", &globals.x4);
@@ -382,8 +449,9 @@ bool InitializeDataBindings(Context* context)
 	constructor.RegisterArray<decltype(Arrays::d)>();
 	constructor.RegisterArray<decltype(Arrays::e)>();
 
-	//constructor.RegisterArray<decltype(Arrays::x0)>();
+	constructor.RegisterArray<decltype(Arrays::x0)>();
 	//constructor.RegisterArray<decltype(Arrays::x1)>();
+	constructor.RegisterArray<decltype(Arrays::x2)>();
 
 	if (auto handle = constructor.RegisterStruct<Arrays>())
 	{
@@ -393,8 +461,9 @@ bool InitializeDataBindings(Context* context)
 		handle.RegisterMember("d", &Arrays::d);
 		handle.RegisterMember("e", &Arrays::e);
 
-		//handle.RegisterMember("x0", &Arrays::x0);
+		handle.RegisterMember("x0", &Arrays::x0);
 		//handle.RegisterMember("x1", &Arrays::x1);
+		handle.RegisterMember("x2", &Arrays::x2);
 	}
 	constructor.Bind("arrays", new Arrays);