/*! @file piparsehelper.h * @brief Helper class to automate structs receive */ /* PIP - Platform Independent Primitives Helper class to automate structs receive Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIPARSEHELPER_H #define PIPARSEHELPER_H #include "pip_io_utils_export.h" #include "piobject.h" /** \class PIParseHelper * @brief Helper class to automate structs receive * * * \section PIParseHelper_synopsis Synopsis * This class helps to deserialize and invoke neccessarily methods. * * Data packets with header and various data types can be automated by this class. * Every key value mapped to event handler or lambda-function. * * This class can remove \b switch-case with deserialization code and * replace it with several \a assign() calls, binded to ready-to-use event handlers. * Moreover data type automatic takes from event handler or lambda argument. One should * only make \"PIByteArray & operator <<()\" with used types, deserialization will be * performed by %PIParseHelper. * * * \section PIParseHelper_usage Usage * There are two variants: subclassing and aggregating. * * ### Subclass * * Inherit your class from %PIParseHelper and construct it with \b this. * * In \a assign() methods you can use event handlers with 0 or 1 arguments, * using HANDLER() macro. * * ### Aggregate * * Create instance of %PIParseHelper and construct it with target object. * * In \a assign() methods you can use event handlers with 0 or 1 arguments, * using HANDLER() macro in target object namespace (e.g. \"o.HANDLER(slot)\"). * * * \section PIParseHelper_lambda Lambda-functions * Assign methods that receive lambda-functions can`t accept direct lambda (\"[](){}\") * with template type deducation because of C++ specific. E.g. * \code assign(1, [this](SomeStruct s){}) \endcode * doesn`t compile, but these variants allowed: * \code assign(1, std::function([this](SomeStruct s){})) \endcode * \code assign(1, [this](SomeStruct s){}) \endcode * * * \section PIParseHelper_examples Examples * First example describes subclass variant. As one can see, it`s a single place to change * type of received data - event handler argument. * \snippet piparsehelper.cpp 0 * * Second example show separate variant: * \snippet piparsehelper.cpp 1 * **/ template class PIParseHelper { public: //! @brief Construct %PIParseHelper with target object \"p\" PIParseHelper(PIObject * p): parent(p) {} //! @brief Assign key \"key\" to event handler \"handler\" with 1 argument template void assign(Key key, Ret(*handler)(void*,T)) { if (!parent) return; auto mf = PIObject::__meta_data().value(parent->classNameID()); auto it = mf.eh_func.makeIterator(); while (it.hasNext()) { it.next(); if (it.value().addr == handler) { void * addr = it.value().addr; auto func = [addr](PIObject * o, PIByteArray data){ T v; data >> v; ((void(*)(void*, T))addr)(o, v); }; functions[key] << func; break; } } } //! @brief Assign key \"key\" to event handler \"handler\" without arguments template void assign(Key key, Ret(*handler)(void*)) { if (!parent) return; auto mf = PIObject::__meta_data().value(parent->classNameID()); auto it = mf.eh_func.makeIterator(); while (it.hasNext()) { it.next(); if (it.value().addr == handler) { void * addr = it.value().addr; auto func = [addr](PIObject * o, PIByteArray ){ ((void(*)(void*))addr)(o); }; functions[key] << func; break; } } } //! @brief Assign key \"key\" to lambda-function \"func\" with 1 argument //! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda template void assign(Key key, std::function func) { if (!parent) return; auto lf = [func](PIObject * , PIByteArray data){ if (!data.isEmpty()) { T v; data >> v; func(v); } }; functions[key] << lf; } //! @brief Assign key \"key\" to lambda-function \"func\" without arguments //! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda void assign(Key key, std::function func) { if (!parent) return; auto lf = [func](PIObject * , PIByteArray ){ func(); }; functions[key] << lf; } //! @brief Deserialize data and invoke assigned to \"key\" methods void parse(Key key, PIByteArray ba) { if (!parent) return; auto fl = functions.value(key); for (auto f: fl) f(parent, ba); } private: PIMap>> functions; PIObject * parent; }; #endif // PIPARSEHELPER_H