Pārlūkot izejas kodu

Clean up data binding API

Michael Ragazzon 5 gadi atpakaļ
vecāks
revīzija
acce5f1346

+ 19 - 16
Include/RmlUi/Core/DataModel.h

@@ -36,6 +36,7 @@
 #include "DataView.h"
 #include "DataController.h"
 #include "DataVariable.h"
+#include <unordered_map>
 
 namespace Rml {
 namespace Core {
@@ -45,7 +46,7 @@ class Element;
 
 class RMLUICORE_API DataModel : NonCopyMoveable {
 public:
-	bool Bind(String name, void* ptr, VariableDefinition* variable, VariableType type);
+	bool Bind(const String& name, void* ptr, VariableDefinition* variable);
 
 	Variable GetVariable(const String& address_str) const;
 	Variable GetVariable(const Address& address) const;
@@ -108,24 +109,26 @@ public:
 		model->DirtyVariable(variable_name);
 	}
 
-	template<typename T> bool BindScalar(String name, T* ptr) {
-		static_assert(is_valid_scalar<T>::value, "Provided type is not a valid scalar type.");
-		return model->Bind(name, ptr, type_register->GetOrAddScalar<T>(), VariableType::Scalar);
+	// Bind a data variable.
+	// Note: For non-scalar types make sure they first have been registered with the appropriate 'Register...()' functions.
+	template<typename T> bool Bind(const String& name, T* ptr) {
+		return model->Bind(name, ptr, type_register->GetOrAddScalar<T>());
 	}
-	template<typename T> bool BindScalar(String name, T* ptr, MemberGetFunc<T> get_func, MemberSetFunc<T> set_func) {
-		RMLUI_ASSERT(get_func || set_func);
-		return model->Bind(name, ptr, type_register->RegisterMemberFunc<T>(get_func, set_func), VariableType::Scalar);
-	}
-	template<typename T> bool BindStruct(String name, T* ptr) {
-		return model->Bind(name, ptr, type_register->Get<T>(), VariableType::Struct);
+	// Bind a get/set function pair.
+	bool BindFunc(const String& name, DataGetFunc get_func, DataSetFunc set_func = {}) {
+		VariableDefinition* func_definition = type_register->RegisterFunc(std::move(get_func), std::move(set_func));
+		bool result = model->Bind(name, nullptr, func_definition);
+		return result;
 	}
-	template<typename T> bool BindArray(String name, T* ptr) {
-		return model->Bind(name, ptr, type_register->Get<T>(), VariableType::Array);
+
+	template<typename T>
+	StructHandle<T> RegisterStruct() {
+		return type_register->RegisterStruct<T>();
 	}
-	bool BindFunction(String name, DataGetFunc get_func, DataSetFunc set_func = {}) {
-		FuncHandle func_handle = type_register->RegisterFunc(std::move(get_func), std::move(set_func));
-		bool result = model->Bind(name, nullptr, func_handle.GetDefinition(), VariableType::Function);
-		return result;
+
+	template<typename Container>
+	bool RegisterArray() {
+		return type_register->RegisterArray<Container>();
 	}
 
 

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

@@ -289,73 +289,25 @@ private:
 
 class DataTypeRegister;
 
-class DefinitionHandle {
-public:
-	explicit operator bool() const { return type_register && GetDefinition(); }
-	virtual VariableDefinition* GetDefinition() const = 0;
-protected:
-	DefinitionHandle(DataTypeRegister* type_register) : type_register(type_register) {}
-	DataTypeRegister* type_register;
-};
-
-template <typename T>
-class ScalarHandle : public DefinitionHandle {
-public:
-	ScalarHandle(DataTypeRegister* type_register) : DefinitionHandle(type_register) {}
-	VariableDefinition* GetDefinition() const override;
-};
-
-class FuncHandle : public DefinitionHandle {
-public:
-	FuncHandle() : DefinitionHandle(nullptr), definition(nullptr), handle(DataFunctionHandle(0)) {}
-	FuncHandle(DataTypeRegister* type_register, FuncDefinition* definition, DataFunctionHandle handle) : DefinitionHandle(type_register), definition(definition), handle(handle) {}
-	VariableDefinition* GetDefinition() const override { return definition; }
-	DataFunctionHandle GetHandle() const { return handle; }
-private:
-	FuncDefinition* definition;
-	DataFunctionHandle handle;
-};
-
 template<typename Object>
-class StructHandle final : public DefinitionHandle {
+class StructHandle {
 public:
-	StructHandle(DataTypeRegister* type_register, StructDefinition* struct_definition) : DefinitionHandle(type_register), struct_definition(struct_definition) {}
-
-	// Register scalar member type 
+	StructHandle(DataTypeRegister* type_register, StructDefinition* struct_definition) : type_register(type_register), struct_definition(struct_definition) {}
+	
 	template <typename MemberType>
-	StructHandle<Object>& RegisterMember(const String& name, MemberType Object::* member_ptr) {
-		static_assert(is_valid_scalar<MemberType>::value, "Not a valid scalar member type. Did you mean to add a struct or array member? If so, provide its handle.");
-		return RegisterMember(name, member_ptr, ScalarHandle<MemberType>(type_register));
-	}
+	StructHandle<Object>& AddMember(const String& name, MemberType Object::* member_ptr);
 
-	// Register struct or array member type
-	template <typename MemberType>
-	StructHandle<Object>& RegisterMember(const String& name, MemberType Object::* member_ptr, const DefinitionHandle& member_handle);
+	StructHandle<Object>& AddMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func = nullptr);
 
-	// Register member function
-	StructHandle<Object>& RegisterMember(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func = nullptr);
-
-	VariableDefinition* GetDefinition() const override {
-		return struct_definition;
+	explicit operator bool() const {
+		return type_register && struct_definition;
 	}
 
 private:
+	DataTypeRegister* type_register;
 	StructDefinition* struct_definition;
 };
 
-template<typename Container>
-class ArrayHandle final : public DefinitionHandle {
-public:
-	ArrayHandle(DataTypeRegister* type_register, ArrayDefinition<Container>* array_definition) : DefinitionHandle(type_register), array_definition(array_definition) {}
-
-	VariableDefinition* GetDefinition() const override {
-		return array_definition;
-	}
-
-private:
-	ArrayDefinition<Container>* array_definition;
-};
-
 
 
 class DataTypeRegister : NonCopyMoveable {
@@ -379,33 +331,32 @@ public:
 		return StructHandle<T>(this, struct_variable_raw);
 	}
 
-	// Register array of scalars
 	template<typename Container>
-	ArrayHandle<Container> RegisterArray()
+	bool RegisterArray()
 	{
 		using value_type = typename Container::value_type;
-		static_assert(is_valid_scalar<value_type>::value, "Underlying value type of array is not a valid scalar type. Provide the type handle if adding an array of structs or arrays.");
 		VariableDefinition* value_variable = GetOrAddScalar<value_type>();
-		return RegisterArray<Container>(value_variable);
-	}
+		RMLUI_ASSERTMSG(value_variable, "Underlying value type of array has not been registered.");
+		if (!value_variable)
+			return false;
 
-	// Register array of structs or arrays
-	template<typename Container>
-	ArrayHandle<Container> RegisterArray(const DefinitionHandle& type_handle)
-	{
-		using value_type = typename Container::value_type;
-		VariableDefinition* value_variable = Get<value_type>();
-		bool correct_handle = (type_handle.GetDefinition() == value_variable);
+		FamilyId container_id = Family<Container>::Id();
 
-		RMLUI_ASSERTMSG(value_variable, "Underlying value type of array has not been registered.");
-		RMLUI_ASSERTMSG(correct_handle, "Improper type handle provided.");
-		if (!value_variable || !correct_handle)
-			return ArrayHandle<Container>(nullptr, nullptr);
+		auto array_variable = std::make_unique<ArrayDefinition<Container>>(value_variable);
+		ArrayDefinition<Container>* array_variable_raw = array_variable.get();
 
-		return RegisterArray<Container>(value_variable);
+		bool inserted = type_register.emplace(container_id, std::move(array_variable)).second;
+		if (!inserted)
+		{
+			RMLUI_ERRORMSG("Array type already declared.");
+			return false;
+		}
+
+		return true;
 	}
 
-	FuncHandle RegisterFunc(DataGetFunc get_func, DataSetFunc set_func)
+
+	VariableDefinition* RegisterFunc(DataGetFunc get_func, DataSetFunc set_func)
 	{
 		static DataFunctionHandle current_handle = DataFunctionHandle(0);
 		current_handle = DataFunctionHandle(int(current_handle) + 1);
@@ -417,7 +368,7 @@ public:
 
 		it->second = std::make_unique<FuncDefinition>(std::move(get_func), std::move(set_func));
 
-		return FuncHandle(this, it->second.get(), current_handle);
+		return it->second.get();
 	}
 
 	template<typename T>
@@ -435,31 +386,35 @@ public:
 		return it->second.get();
 	}
 
-	template<typename T>
+	template<typename T, typename std::enable_if<is_valid_scalar<T>::value, int>::type = 0>
 	VariableDefinition* GetOrAddScalar()
 	{
 		FamilyId id = Family<T>::Id();
 
 		auto result = type_register.emplace(id, nullptr);
-		auto& it = result.first;
 		bool inserted = result.second;
+		UniquePtr<VariableDefinition>& definition = result.first->second;
 
 		if (inserted)
-		{
-			it->second = std::make_unique<ScalarDefinition<T>>();
-		}
+			definition = std::make_unique<ScalarDefinition<T>>();
 
-		return it->second.get();
+		return definition.get();
+	}
+
+	template<typename T, typename std::enable_if<!is_valid_scalar<T>::value, int>::type = 0>
+	VariableDefinition* GetOrAddScalar()
+	{
+		return Get<T>();
 	}
 
 	template<typename T>
-	VariableDefinition* Get() const
+	VariableDefinition* Get()
 	{
 		FamilyId id = Family<T>::Id();
 		auto it = type_register.find(id);
 		if (it == type_register.end())
 		{
-			RMLUI_ERRORMSG("Desired data type not registered with the type register.")
+			RMLUI_ERRORMSG("Desired data type T not registered with the type register, please use the 'Register...()' functions before binding values, adding members, or registering arrays of non-scalar types.")
 			return nullptr;
 		}
 
@@ -467,24 +422,6 @@ public:
 	}
 
 private:
-	template<typename Container>
-	ArrayHandle<Container> RegisterArray(VariableDefinition* value_variable)
-	{
-		FamilyId container_id = Family<Container>::Id();
-
-		auto array_variable = std::make_unique<ArrayDefinition<Container>>(value_variable);
-		ArrayDefinition<Container>* array_variable_raw = array_variable.get();
-
-		bool inserted = type_register.emplace(container_id, std::move(array_variable)).second;
-		if (!inserted)
-		{
-			RMLUI_ERRORMSG("Array type already declared.");
-			return ArrayHandle<Container>(nullptr, nullptr);
-		}
-
-		return ArrayHandle<Container>(this, array_variable_raw);
-	}
-
 	UnorderedMap<DataFunctionHandle, UniquePtr<FuncDefinition>> functions;
 
 	UnorderedMap<FamilyId, UniquePtr<VariableDefinition>> type_register;
@@ -492,21 +429,15 @@ private:
 
 
 
-
-template<typename T>
-inline VariableDefinition* ScalarHandle<T>::GetDefinition() const {
-	return type_register->GetOrAddScalar<T>();
-}
-
 template<typename Object>
 template<typename MemberType>
-inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, MemberType Object::* member_ptr, const DefinitionHandle& member_handle) {
-	RMLUI_ASSERTMSG(member_handle.GetDefinition() == type_register->Get<MemberType>(), "Mismatch between member type and provided type handle.");
-	struct_definition->AddMember(name, std::make_unique<StructMemberDefault<Object, MemberType>>(member_handle.GetDefinition(), member_ptr));
+inline StructHandle<Object>& StructHandle<Object>::AddMember(const String& name, MemberType Object::* member_ptr) {
+	VariableDefinition* member_type = type_register->GetOrAddScalar<MemberType>();
+	struct_definition->AddMember(name, std::make_unique<StructMemberDefault<Object, MemberType>>(member_type, member_ptr));
 	return *this;
 }
 template<typename Object>
-inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func) {
+inline StructHandle<Object>& StructHandle<Object>::AddMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func) {
 	VariableDefinition* definition = type_register->RegisterMemberFunc<Object>(get_func, set_func);
 	struct_definition->AddMember(name, std::make_unique<StructMemberFunc>(definition));
 	return *this;

+ 16 - 16
Samples/basic/databinding/src/main.cpp

@@ -145,29 +145,29 @@ bool SetupDataBinding(Rml::Core::Context* context)
 	if (!my_model)
 		return false;
 
-	my_model.BindScalar("hello_world", &my_data.hello_world);
-	my_model.BindScalar("rating", &my_data.rating);
-	my_model.BindFunction("good_rating", &HasGoodRating);
-	my_model.BindFunction("great_rating", [](Rml::Core::Variant& variant) {
+	my_model.Bind("hello_world", &my_data.hello_world);
+	my_model.Bind("rating", &my_data.rating);
+	my_model.BindFunc("good_rating", &HasGoodRating);
+	my_model.BindFunc("great_rating", [](Rml::Core::Variant& variant) {
 		variant = int(my_data.rating > 80);
 	});
 
-	Rml::Core::DataTypeRegister& types = Rml::Core::GetDataTypeRegister();
+	my_model.RegisterArray<std::vector<int>>();
 
-	auto vector_int_handle = types.RegisterArray<std::vector<int>>();
-
-	auto invader_handle = types.RegisterStruct<Invader>();
-	invader_handle.RegisterMember("name", &Invader::name);
-	invader_handle.RegisterMember("sprite", &Invader::sprite);
-	invader_handle.RegisterMember("color", &Invader::GetColor);
-	invader_handle.RegisterMember("numbers", &Invader::numbers, vector_int_handle);
+	if(auto invader_handle = my_model.RegisterStruct<Invader>())
+	{
+		invader_handle.AddMember("name", &Invader::name);
+		invader_handle.AddMember("sprite", &Invader::sprite);
+		invader_handle.AddMember("numbers", &Invader::numbers);
+		invader_handle.AddMemberFunc("color", &Invader::GetColor);
+	}
 
-	my_model.BindStruct("delightful_invader", &my_data.delightful_invader);
+	my_model.Bind("delightful_invader", &my_data.delightful_invader);
 
-	auto vector_invader_handle = types.RegisterArray<std::vector<Invader>>(invader_handle);
+	my_model.RegisterArray<std::vector<Invader>>();
 
-	my_model.BindArray("indices", &my_data.indices);
-	my_model.BindArray("invaders", &my_data.invaders);
+	my_model.Bind("indices", &my_data.indices);
+	my_model.Bind("invaders", &my_data.invaders);
 
 	return true;
 }

+ 17 - 25
Source/Core/DataModel.cpp

@@ -72,7 +72,7 @@ static Address ParseAddress(const String& address_str)
 	return address;
 };
 
-bool DataModel::Bind(String name, void* ptr, VariableDefinition* variable, VariableType type)
+bool DataModel::Bind(const String& name, void* ptr, VariableDefinition* variable)
 {
 	if (!variable)
 	{
@@ -81,12 +81,6 @@ bool DataModel::Bind(String name, void* ptr, VariableDefinition* variable, Varia
 	}
 	RMLUI_ASSERT(ptr || variable->Type() == VariableType::Function);
 
-	if (variable->Type() != type)
-	{
-		Log::Message(Log::LT_WARNING, "The registered type does not match the given type for the data variable '%s'.", name.c_str());
-		return false;
-	}
-
 	bool inserted = variables.emplace(name, Variable(variable, ptr)).second;
 	if (!inserted)
 	{
@@ -216,7 +210,7 @@ bool DataModel::InsertAlias(Element* element, const String& alias_name, Address
 	auto& map = aliases.emplace(element, SmallUnorderedMap<String, Address>()).first->second;
 	
 	auto it = map.find(alias_name);
-	if(it != map.end())
+	if (it != map.end())
 		Log::Message(Log::LT_WARNING, "Alias name '%s' in data model already exists, replaced.", alias_name.c_str());
 
 	map[alias_name] = std::move(replace_with_address);
@@ -265,37 +259,35 @@ static struct TestDataVariables {
 			FunArray more_fun;
 		};
 
+		DataModel model;
 		DataTypeRegister types;
 
+		DataModelHandle handle(&model, &types);
+
 		{
-			auto int_vector_handle = types.RegisterArray<IntVector>();
+			handle.RegisterArray<IntVector>();
 
-			auto fun_handle = types.RegisterStruct<FunData>();
-			if (fun_handle)
+			if (auto fun_handle = handle.RegisterStruct<FunData>())
 			{
-				fun_handle.RegisterMember("i", &FunData::i);
-				fun_handle.RegisterMember("x", &FunData::x);
-				fun_handle.RegisterMember("magic", &FunData::magic, int_vector_handle);
+				fun_handle.AddMember("i", &FunData::i);
+				fun_handle.AddMember("x", &FunData::x);
+				fun_handle.AddMember("magic", &FunData::magic);
 			}
 
-			auto fun_array_handle = types.RegisterArray<FunArray>(fun_handle);
+			handle.RegisterArray<FunArray>();
 
-			auto smart_handle = types.RegisterStruct<SmartData>();
-			if (smart_handle)
+			if (auto smart_handle = handle.RegisterStruct<SmartData>())
 			{
-				smart_handle.RegisterMember("valid", &SmartData::valid);
-				smart_handle.RegisterMember("fun", &SmartData::fun, fun_handle);
-				smart_handle.RegisterMember("more_fun", &SmartData::more_fun, fun_array_handle);
+				smart_handle.AddMember("valid", &SmartData::valid);
+				smart_handle.AddMember("fun", &SmartData::fun);
+				smart_handle.AddMember("more_fun", &SmartData::more_fun);
 			}
 		}
 
-		DataModel model;
-		DataModelHandle handle(&model, &types);
-
 		SmartData data;
 		data.fun.x = "Hello, we're in SmartData!";
-
-		handle.BindStruct("data", &data);
+		
+		handle.Bind("data", &data);
 
 		{
 			std::vector<String> test_addresses = { "data.more_fun[1].magic[3]", "data.fun.x", "data.valid" };