From 834d7022ca133be16d8d8b579b5dcc77c26c00a7 Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Sun, 24 Nov 2019 15:02:37 +0300 Subject: [PATCH] Implemented attribute setters ``` builder.element("example") .setter("value", &Example::setValue); ``` --- src/imvue_element.h | 115 ++++++++++++++++++++++++++++++++++++++++-- tests/unit/parser.cpp | 10 ++++ 2 files changed, 120 insertions(+), 5 deletions(-) diff --git a/src/imvue_element.h b/src/imvue_element.h index e45369c..512fbfc 100644 --- a/src/imvue_element.h +++ b/src/imvue_element.h @@ -754,7 +754,6 @@ namespace ImVue { if(!success && required) { IMVUE_EXCEPTION(ElementError, "failed to read required attribute %s", attribute); - return; } } @@ -768,6 +767,93 @@ namespace ImVue { D C::* mMemPtr; }; + /** + * Setter implementation of attribute reader + */ + template + class AttributeSetter : public Attribute { + public: + + typedef void(C::*SetterFunc)(Type); + + AttributeSetter(SetterFunc func, bool required = false) + : Attribute(required) + , mSetter(func) + { + static_assert(std::is_trivially_constructible::value, "setter can only be used with trivially constructible types"); + } + + void read(const char* attribute, const char* str, Element* element, ScriptState* scriptState, int flags = 0, ScriptState::Fields* fields = 0) const + { + Type value; + bool success = false; + if(scriptState) { + if(flags & SCRIPT) { + Object object = scriptState->getObject(str, fields, element->getContext()); + if(!object.valid()) { + IMVUE_EXCEPTION(ScriptError, "failed to evaluate data %s", str); + return; + } + success = detail::read(object, &value); + } else if(flags & TEMPLATED_STRING) { + std::string retval; + std::stringstream result; + std::stringstream ss; + bool evaluation = false; + + for(int i = 0;;i++) { + if(str[i] == '\0') { + break; + } + + if(evaluation && std::strncmp(&str[i], "}}", 2) == 0) { + Object object = scriptState->getObject(&ss.str()[0], fields, element->getContext()); + ss = std::stringstream(); + evaluation = false; + result << object.as().c_str(); + i++; + continue; + } + + if(!evaluation && std::strncmp(&str[i], "{{", 2) == 0) { + evaluation = true; + i++; + continue; + } + + if(evaluation) { + ss << str[i]; + } else { + result << str[i]; + } + } + + success = detail::read(&result.str()[0], &value); + } + } + + if(!success) { + success = detail::read(str, &value); + } + + if(success) { + (static_cast(element)->*mSetter)(value); + } else if(required) { + IMVUE_EXCEPTION(ElementError, "failed to read required attribute %s", attribute); + } + } + + bool copy(Element* element, Object& dest) const + { + (void)element; + (void)dest; + return false; + } + + private: + SetterFunc mSetter; + }; + /** * Handler factory interface */ @@ -899,16 +985,16 @@ namespace ImVue { } /** - * Register attribute reader + * Register attribute * * @param name attribute name * @param memPtr destination to read into (&Element::variable) * @param required property is required */ - template - ElementBuilderImpl& attribute(const char* name, D C::* memPtr, bool required = false) + template + ElementBuilderImpl& attribute(const char* name, Type C::* memPtr, bool required = false) { - mAttributes[name] = new AttributeMemPtr(memPtr, required); + mAttributes[name] = new AttributeMemPtr(memPtr, required); mAttributes[name]->owner = this; if(required) { mRequiredAttrs.push_back(name); @@ -916,6 +1002,25 @@ namespace ImVue { return *this; } + /** + * Register attribute setter + * + * @param name attribute name + * @param func setter function to use (&Element::setValue) + * @param required property is required + */ + template + ElementBuilderImpl& setter(const char* name, void(C::*func)(Type), bool required = false) + { + mAttributes[name] = new AttributeSetter(func, required); + mAttributes[name]->owner = this; + if(required) { + mRequiredAttrs.push_back(name); + } + return *this; + } + + /** * Register text reader * diff --git a/tests/unit/parser.cpp b/tests/unit/parser.cpp index c6d86b0..3434d83 100644 --- a/tests/unit/parser.cpp +++ b/tests/unit/parser.cpp @@ -120,6 +120,11 @@ class Validator : public ImVue::Element { } + void useSetter(int value) + { + fromSetter = value; + } + bool flag; float fl; double dbl; @@ -134,6 +139,7 @@ class Validator : public ImVue::Element char* ch; int arrFixed[3]; int* arrVariadic; + int fromSetter; #if defined(WITH_LUA) ImVue::Object object; #endif @@ -179,6 +185,7 @@ TEST_P(ReadTypesTest, ParseTypes) .attribute("vec4", &Validator::vec4, true) .attribute("arr-fixed", &Validator::arrFixed, true) .attribute("arr-variadic", &Validator::arrVariadic, true) + .setter("setter", &Validator::useSetter, true) #if defined(WITH_LUA) .attribute("object", &Validator::object) #endif @@ -205,6 +212,7 @@ TEST_P(ReadTypesTest, ParseTypes) EXPECT_EQ(el->i16, -32765); EXPECT_EQ(el->i32, -65536); EXPECT_EQ(el->i64, -1073741823); + EXPECT_EQ(el->fromSetter, 100); EXPECT_FLOAT_EQ(el->vec2.x, 2); EXPECT_FLOAT_EQ(el->vec2.y, 2); @@ -242,6 +250,7 @@ const char* dataStatic = ""; @@ -255,6 +264,7 @@ const char* dataBind = "" "