From 8344a9977873551418ececdd2cfb7c80a5a63bf0 Mon Sep 17 00:00:00 2001 From: Martchus Date: Wed, 18 Oct 2017 23:07:17 +0200 Subject: [PATCH] Add project basic project structure * Implement simple RapidJSON wrapper * Add skeleton for code generator to play around with LibTooling and LibClang --- .gitignore | 41 +++++ CMakeLists.txt | 34 ++++ LICENSE | 339 +++++++++++++++++++++++++++++++++++ README.md | 3 + lib/CMakeLists.txt | 34 ++++ lib/README.md | 1 + lib/global.h | 27 +++ lib/reflect.cpp | 10 ++ lib/reflect.h | 308 +++++++++++++++++++++++++++++++ lib/reflectable.h | 56 ++++++ lib/someclass.cpp | 10 ++ lib/someclass.h | 14 ++ lib/tests/cppunit.cpp | 1 + lib/tests/reflector.cpp | 318 ++++++++++++++++++++++++++++++++ moc/CMakeLists.txt | 45 +++++ moc/LICENSE | 339 +++++++++++++++++++++++++++++++++++ moc/README.md | 1 + moc/generator.cpp | 94 ++++++++++ moc/generator.h | 12 ++ moc/main.cpp | 67 +++++++ moc/testfiles/some_structs.h | 29 +++ moc/tests/cppunit.cpp | 1 + moc/tests/overall.cpp | 67 +++++++ 23 files changed, 1851 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 lib/CMakeLists.txt create mode 120000 lib/README.md create mode 100644 lib/global.h create mode 100644 lib/reflect.cpp create mode 100644 lib/reflect.h create mode 100644 lib/reflectable.h create mode 100644 lib/someclass.cpp create mode 100644 lib/someclass.h create mode 100644 lib/tests/cppunit.cpp create mode 100644 lib/tests/reflector.cpp create mode 100644 moc/CMakeLists.txt create mode 100644 moc/LICENSE create mode 100644 moc/README.md create mode 100644 moc/generator.cpp create mode 100644 moc/generator.h create mode 100644 moc/main.cpp create mode 100644 moc/testfiles/some_structs.h create mode 100644 moc/tests/cppunit.cpp create mode 100644 moc/tests/overall.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e6de9e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# C++ objects and libs +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es +/.qmake.cache +/.qmake.stash +*.pro.user +*.txt.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +qrc_*.cpp +ui_*.h +Makefile* +*-build-* + +# QtCreator +*.autosave + +#QtCtreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# Dolphin +.directory + +# tests +testfiles/workingdir/ + +# clang-format +.clang-format diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e29fcf2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) + +# metadata +set(META_PROJECT_NAME reflective_rapidjson) +set(META_APP_NAME "Reflection for RapidJSON") +set(META_APP_AUTHOR "Martchus") +set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") +set(META_APP_DESCRIPTION "Reflection for serializing/deserializing with RapidJSON") +set(META_APP_CATEGORIES "Utility;") +set(META_GUI_OPTIONAL false) +set(META_VERSION_MAJOR 0) +set(META_VERSION_MINOR 0) +set(META_VERSION_PATCH 1) +set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}) + +# set project name for IDEs like Qt Creator +project(${META_PROJECT_NAME}) + +# allow bundling c++utilities +set(BUNDLED_CPP_UTILITIES_PATH OFF CACHE FILEPATH "specifies the (relative) path to the c++utilities sources for building it together with ${META_PROJECT_NAME}") +if(NOT BUNDLED_CPP_UTILITIES_PATH) + message(STATUS "Using system c++utilities") +elseif(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${BUNDLED_CPP_UTILITIES_PATH}" OR IS_DIRECTORY "${BUNDLED_CPP_UTILITIES_PATH}") + add_subdirectory("${BUNDLED_CPP_UTILITIES_PATH}" c++utilities) + list(APPEND CMAKE_MODULE_PATH ${CPP_UTILITIES_SOURCE_DIR}/cmake/modules) +else() + message(FATAL_ERROR "Specified directory for c++utilities sources \"${BUNDLED_CPP_UTILITIES_PATH}\" does not exist.") +endif() + +# add helper library for using RapidJSON +add_subdirectory(lib) + +# add code generator +add_subdirectory(moc) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..23cb790 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6b58a7c --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# reflective-rapidjson + +Code generator for serializing/deserializing C++ objects to/from JSON using Clang and RapidJSON diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..5a8e4de --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) + +# metadata +set(META_PROJECT_TYPE library) + +# add project files +set(HEADER_FILES + reflect.h + reflectable.h +) +set(SRC_FILES + reflect.cpp +) +set(TEST_HEADER_FILES +) +set(TEST_SRC_FILES + tests/cppunit.cpp + tests/reflector.cpp +) +set(DOC_FILES + README.md +) + +# find c++utilities +find_package(c++utilities 4.6.0 REQUIRED) +use_cpp_utilities() + +# include modules to apply configuration +include(BasicConfig) +include(WindowsResources) +include(LibraryTarget) +include(TestTarget) +include(Doxygen) +include(ConfigHeader) diff --git a/lib/README.md b/lib/README.md new file mode 120000 index 0000000..32d46ee --- /dev/null +++ b/lib/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/lib/global.h b/lib/global.h new file mode 100644 index 0000000..8ce1e5f --- /dev/null +++ b/lib/global.h @@ -0,0 +1,27 @@ +// Created via CMake from template global.h.in +// WARNING! Any changes to this file will be overwritten by the next CMake run! + +#ifndef REFLECTIVE_RAPIDJSON_GLOBAL +#define REFLECTIVE_RAPIDJSON_GLOBAL + +#include + +#ifdef REFLECTIVE_RAPIDJSON_STATIC +#define REFLECTIVE_RAPIDJSON_EXPORT +#define REFLECTIVE_RAPIDJSON_IMPORT +#else +#define REFLECTIVE_RAPIDJSON_EXPORT LIB_EXPORT +#define REFLECTIVE_RAPIDJSON_IMPORT LIB_IMPORT +#endif + +/*! + * \def REFLECTIVE_RAPIDJSON_EXPORT + * \brief Marks the symbol to be exported by the reflective_rapidjson library. + */ + +/*! + * \def REFLECTIVE_RAPIDJSON_IMPORT + * \brief Marks the symbol to be imported from the reflective_rapidjson library. + */ + +#endif // REFLECTIVE_RAPIDJSON_GLOBAL diff --git a/lib/reflect.cpp b/lib/reflect.cpp new file mode 100644 index 0000000..3cf03e2 --- /dev/null +++ b/lib/reflect.cpp @@ -0,0 +1,10 @@ +#include "./reflect.h" + +using namespace RAPIDJSON_NAMESPACE; + +namespace ReflectiveRapidJSON { + +namespace Reflector { +} + +} // namespace ReflectiveRapidJSON diff --git a/lib/reflect.h b/lib/reflect.h new file mode 100644 index 0000000..7034d40 --- /dev/null +++ b/lib/reflect.h @@ -0,0 +1,308 @@ +#ifndef REFLECTIVE_RAPIDJSON_REFLECT_H +#define REFLECTIVE_RAPIDJSON_REFLECT_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace ReflectiveRapidJSON { + +enum class ErrorFlags : unsigned char { TypeMismatch, MemberMissing }; + +constexpr ErrorFlags operator&(ErrorFlags lhs, ErrorFlags rhs) +{ + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +constexpr ErrorFlags operator|(ErrorFlags lhs, ErrorFlags rhs) +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +template struct Reflectable; + +inline RAPIDJSON_NAMESPACE::StringBuffer documentToString(RAPIDJSON_NAMESPACE::Document &document) +{ + RAPIDJSON_NAMESPACE::StringBuffer buffer; + RAPIDJSON_NAMESPACE::Writer writer(buffer); + document.Accept(writer); + return buffer; +} + +namespace Reflector { + +// define functions to "push" values to a RapidJSON array or object + +template , std::is_floating_point, std::is_pointer, + Traits::All, Traits::Not>>>...> +void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); + +template , std::is_floating_point, std::is_pointer, + Traits::All, Traits::Not>>>...> +void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); + +template , std::is_floating_point, std::is_pointer>...> +inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.PushBack(reflectable, allocator); +} + +template <> +inline void push( + const char *reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); +} + +template <> +inline void push( + const std::string &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator); +} + +template <> +inline void push( + const char *const &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.PushBack(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); +} + +template , Traits::Not>>...> +void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + RAPIDJSON_NAMESPACE::Value arrayValue(RAPIDJSON_NAMESPACE::kArrayType); + RAPIDJSON_NAMESPACE::Value::Array array(arrayValue.GetArray()); + array.Reserve(reflectable.size(), allocator); + for (const auto &item : reflectable) { + push(item, array, allocator); + } + value.PushBack(array, allocator); +} + +template , std::is_floating_point, std::is_pointer, + Traits::All, Traits::Not>>>...> +inline void push( + const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType); + RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject()); + push(reflectable, object, allocator); + value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), object, allocator); +} + +template , std::is_floating_point, std::is_pointer>...> +inline void push( + Type reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), reflectable, allocator); +} + +template <> +inline void push(const std::string &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, + RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator); +} + +template <> +inline void push( + const char *reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); +} + +template <> +inline void push(const char *const &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, + RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator); +} + +template , Traits::Not>>...> +void push( + const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + RAPIDJSON_NAMESPACE::Value arrayValue(RAPIDJSON_NAMESPACE::kArrayType); + RAPIDJSON_NAMESPACE::Value::Array array(arrayValue.GetArray()); + array.Reserve(reflectable.size(), allocator); + for (const auto &item : reflectable) { + push(item, array, allocator); + } + value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), array, allocator); +} + +template , std::is_floating_point, std::is_pointer, + Traits::All, Traits::Not>>>...> +void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator) +{ + RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType); + RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject()); + push(reflectable, object, allocator); + value.PushBack(objectValue, allocator); +} + +// define functions to "pull" values from a RapidJSON array or object + +template , std::is_floating_point, std::is_pointer, + Traits::All, Traits::Not>>>...> +void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue>::ValueIterator &value); + +template , std::is_floating_point, std::is_pointer, + Traits::All, Traits::Not>>>...> +void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue>::ConstObject &value); + +template , std::is_floating_point, std::is_pointer, + Traits::All, Traits::Not>>>...> +void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value) +{ + pull(reflectable, value.GetObject()); +} + +template , std::is_floating_point, std::is_pointer>...> +inline void pull(Type &reflectable, RAPIDJSON_NAMESPACE::GenericValue>::ValueIterator &value) +{ + reflectable = value->Get(); + ++value; +} + +template , std::is_floating_point, std::is_pointer>...> +inline void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value) +{ + reflectable = value.Get(); +} + +template <> +inline void pull(std::string &reflectable, RAPIDJSON_NAMESPACE::GenericValue>::ValueIterator &value) +{ + reflectable = value->GetString(); + ++value; +} + +template <> inline void pull(std::string &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value) +{ + reflectable = value.GetString(); +} + +template , Traits::Not>>...> +void pull(Type &reflectable, rapidjson::GenericValue>::ValueIterator &value) +{ + for (const auto &item : value->GetArray()) { + reflectable.emplace_back(); + pull(reflectable.back(), item); + } + ++value; +} + +template , Traits::Not>>...> +void pull(Type &reflectable, const rapidjson::GenericValue> &value) +{ + for (const auto &item : value.GetArray()) { + reflectable.emplace_back(); + pull(reflectable.back(), item); + } +} + +template +inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue>::ConstObject &value) +{ + pull(reflectable, value.FindMember(name)->value); +} + +// define functions providing high-level JSON serialization + +template , Type>>...> +RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); + RAPIDJSON_NAMESPACE::Document::Object object(document.GetObject()); + push(reflectable, object, document.GetAllocator()); + return documentToString(document); +} + +template , std::is_floating_point>...> +RAPIDJSON_NAMESPACE::StringBuffer toJson(Type reflectable) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kNumberType); + document.Set(reflectable, document.GetAllocator()); + return documentToString(document); +} + +template >...> +RAPIDJSON_NAMESPACE::StringBuffer toJson(const std::string &reflectable) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType); + document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator()); + return documentToString(document); +} + +template >...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const char *reflectable) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType); + document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator()); + return documentToString(document); +} + +// define functions providing high-level JSON deserialization + +template , Type>>...> Type fromJson(const char *json, std::size_t jsonSize) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); + document.Parse(json, jsonSize); + Type res; + pull(res, document.GetObject()); + return res; +} + +template , std::is_floating_point>...> +Type fromJson(const char *json, std::size_t jsonSize) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); + document.Parse(json, jsonSize); + return document.Get(); +} + +template >...> Type fromJson(const char *json, std::size_t jsonSize) +{ + RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType); + document.Parse(json, jsonSize); + return document.GetString(); +} + +template Type fromJson(const std::string &json) +{ + return fromJson(json.data(), json.size()); +} + +} // namespace Reflector + +} // namespace ReflectiveRapidJSON + +#define REFLECT(Type) \ + namespace Reflector { \ + template <> \ + void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); \ + template <> \ + void add( \ + const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); \ + template <> std::string toJson(const Type &reflectable); \ + template <> Type fromJson(const char *json, std::size_t jsonSize); \ + template <> Type fromJson(const std::string &json); \ + } + +#endif // REFLECTIVE_RAPIDJSON_REFLECT_H diff --git a/lib/reflectable.h b/lib/reflectable.h new file mode 100644 index 0000000..1ab1561 --- /dev/null +++ b/lib/reflectable.h @@ -0,0 +1,56 @@ +#ifndef REFLECTIVE_RAPIDJSON_REFLECTABLE_H +#define REFLECTIVE_RAPIDJSON_REFLECTABLE_H + +#include "./reflect.h" + +#include + +#include + +namespace ReflectiveRapidJSON { + +template struct Reflectable { + // RapidJSON-level API + void push(RAPIDJSON_NAMESPACE::Value &container); + void push(RAPIDJSON_NAMESPACE::Value &container, const char *name); + + // high-level API + RAPIDJSON_NAMESPACE::StringBuffer toJson() const; + static Type fromJson(const char *json, std::size_t jsonSize); + static Type fromJson(const char *json); + static Type fromJson(const std::string &json); +}; + +template void Reflectable::push(RAPIDJSON_NAMESPACE::Value &container) +{ + return Reflector::push(*this, container); +} + +template void Reflectable::push(RAPIDJSON_NAMESPACE::Value &container, const char *name) +{ + return Reflector::push(*this, name, container); +} + +template RAPIDJSON_NAMESPACE::StringBuffer Reflectable::toJson() const +{ + return Reflector::toJson(static_cast(*this)); +} + +template Type Reflectable::fromJson(const char *json, std::size_t jsonSize) +{ + return Reflector::fromJson(json, jsonSize); +} + +template Type Reflectable::fromJson(const char *json) +{ + return Reflector::fromJson(json, std::strlen(json)); +} + +template Type Reflectable::fromJson(const std::string &json) +{ + return Reflector::fromJson(json.data(), json.size()); +} + +} // namespace ReflectiveRapidJSON + +#endif // REFLECTIVE_RAPIDJSON_REFLECTABLE_H diff --git a/lib/someclass.cpp b/lib/someclass.cpp new file mode 100644 index 0000000..37e5033 --- /dev/null +++ b/lib/someclass.cpp @@ -0,0 +1,10 @@ +#include "./someclass.h" + +using namespace std; + +namespace Ns { + + + +} + diff --git a/lib/someclass.h b/lib/someclass.h new file mode 100644 index 0000000..3953c53 --- /dev/null +++ b/lib/someclass.h @@ -0,0 +1,14 @@ +#ifndef SOME_CLASS_H +#define SOME_CLASS_H + +namespace Ns { + +class SomeClass +{ +public: + SomeClass(); +}; + +} + +#endif // SOME_CLASS_H diff --git a/lib/tests/cppunit.cpp b/lib/tests/cppunit.cpp new file mode 100644 index 0000000..67aaee6 --- /dev/null +++ b/lib/tests/cppunit.cpp @@ -0,0 +1 @@ +#include diff --git a/lib/tests/reflector.cpp b/lib/tests/reflector.cpp new file mode 100644 index 0000000..33a1cd4 --- /dev/null +++ b/lib/tests/reflector.cpp @@ -0,0 +1,318 @@ +#include "../reflectable.h" + +#include "resources/config.h" + +#include +#include +#include +#include + +using TestUtilities::operator<<; // must be visible prior to the call site +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace CPPUNIT_NS; +using namespace RAPIDJSON_NAMESPACE; +using namespace IoUtilities; +using namespace ConversionUtilities; +using namespace TestUtilities; +using namespace TestUtilities::Literals; +using namespace ReflectiveRapidJSON; + +/// \cond + +// define some structs for testing serialization +struct TestObject : public Reflectable { + int number; + double number2; + vector numbers; + string text; + bool boolean; +}; + +struct NestingObject : public Reflectable { + string name; + TestObject testObj; +}; + +struct NestingArray : public Reflectable { + string name; + vector testObjects; +}; + +// pretend serialization code for structs has been generated +namespace ReflectiveRapidJSON { +namespace Reflector { + +template <> inline void push(const TestObject &reflectable, Value::Object &value, Document::AllocatorType &allocator) +{ + push(reflectable.number, "number", value, allocator); + push(reflectable.number2, "number2", value, allocator); + push(reflectable.numbers, "numbers", value, allocator); + push(reflectable.text, "text", value, allocator); + push(reflectable.boolean, "boolean", value, allocator); +} + +template <> inline void push(const NestingObject &reflectable, Value::Object &value, Document::AllocatorType &allocator) +{ + push(reflectable.name, "name", value, allocator); + push(reflectable.testObj, "testObj", value, allocator); +} + +template <> inline void push(const NestingArray &reflectable, Value::Object &value, Document::AllocatorType &allocator) +{ + push(reflectable.name, "name", value, allocator); + push(reflectable.testObjects, "testObjects", value, allocator); +} + +template <> inline void pull(TestObject &reflectable, const GenericValue>::ConstObject &value) +{ + pull(reflectable.number, "number", value); + pull(reflectable.number2, "number2", value); + pull(reflectable.numbers, "numbers", value); + pull(reflectable.text, "text", value); + pull(reflectable.boolean, "boolean", value); +} + +template <> inline void pull(NestingObject &reflectable, const GenericValue>::ConstObject &value) +{ + pull(reflectable.name, "name", value); + pull(reflectable.testObj, "testObj", value); +} + +template <> inline void pull(NestingArray &reflectable, const GenericValue>::ConstObject &value) +{ + pull(reflectable.name, "name", value); + pull(reflectable.testObjects, "testObjects", value); +} + +} // namespace Reflector +} // namespace ReflectiveRapidJSON + +/// \endcond + +/*! + * \brief The ReflectorTests class tests RapidJSON wrapper which is used to ease code generation. + * \remarks In this tests, no reflection or code generation is involved yet. + */ +class ReflectorTests : public TestFixture { + CPPUNIT_TEST_SUITE(ReflectorTests); + CPPUNIT_TEST(experiment); + CPPUNIT_TEST(testSerializePrimitives); + CPPUNIT_TEST(testSerializeSimpleObjects); + CPPUNIT_TEST(testSerializeNestedObjects); + CPPUNIT_TEST(testDeserializePrimitives); + CPPUNIT_TEST(testDeserializeSimpleObjects); + CPPUNIT_TEST(testDeserializeNestedObjects); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void experiment(); + void testSerializePrimitives(); + void testSerializeSimpleObjects(); + void testSerializeNestedObjects(); + void testDeserializePrimitives(); + void testDeserializeSimpleObjects(); + void testDeserializeNestedObjects(); + +private: +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ReflectorTests); + +void ReflectorTests::setUp() +{ +} + +void ReflectorTests::tearDown() +{ +} + +/*! + * \brief Not a real test, just some assertions for experimenting with the RapidJSON library. + */ +void ReflectorTests::experiment() +{ + Document doc(kArrayType); + Document::AllocatorType &alloc = doc.GetAllocator(); + + /* + doc.PushBack(25, alloc); + doc.PushBack(26, alloc); + doc.SetObject(); + doc.AddMember(StringRef("test"), 27, alloc); + + StringBuffer strbuf; + Writer jsonWriter(strbuf); + doc.Accept(jsonWriter); + */ + + doc.Parse("[\"a\", 5, \"test\", \"7\"]"); + GenericValue>::Array a = doc.GetArray(); + CPPUNIT_ASSERT_EQUAL("a"s, string(a[0].GetString())); + CPPUNIT_ASSERT_EQUAL(5, a[1].GetInt()); + //CPPUNIT_ASSERT_EQUAL(5, a[2].GetInt()); + //CPPUNIT_ASSERT_EQUAL(7, a[3].GetInt()); +} + +/*! + * \brief Tests serializing strings, numbers, arrays and boolean. + */ +void ReflectorTests::testSerializePrimitives() +{ + Document doc(kArrayType); + Document::AllocatorType &alloc = doc.GetAllocator(); + doc.SetArray(); + Document::Array array(doc.GetArray()); + + // string + Reflector::push("foo"s, array, alloc); + Reflector::push("bar", array, alloc); + // number + Reflector::push(25, array, alloc); + Reflector::push(12.5, array, alloc); + // array + Reflector::push>({ "foo1", "bar1" }, array, alloc); + Reflector::push>({ "foo2", "bar2" }, array, alloc); + Reflector::push>({ "foo3", "bar3" }, array, alloc); + // boolean + Reflector::push(true, array, alloc); + Reflector::push(false, array, alloc); + + StringBuffer strbuf; + Writer jsonWriter(strbuf); + doc.Accept(jsonWriter); + CPPUNIT_ASSERT_EQUAL( + "[\"foo\",\"bar\",25,12.5,[\"foo1\",\"bar1\"],[\"foo2\",\"bar2\"],[\"foo3\",\"bar3\"],true,false]"s, string(strbuf.GetString())); +} + +/*! + * \brief Tests serializing objects. + */ +void ReflectorTests::testSerializeSimpleObjects() +{ + TestObject testObj; + testObj.number = 42; + testObj.number2 = 3.141592653589793; + testObj.numbers = { 1, 2, 3, 4 }; + testObj.text = "test"; + testObj.boolean = false; + CPPUNIT_ASSERT_EQUAL("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}"s, + string(testObj.toJson().GetString())); +} + +/*! + * \brief Tests serializing nested object and arrays. + */ +void ReflectorTests::testSerializeNestedObjects() +{ + NestingObject nestingObj; + nestingObj.name = "nesting"; + TestObject &testObj = nestingObj.testObj; + testObj.number = 42; + testObj.number2 = 3.141592653589793; + testObj.numbers = { 1, 2, 3, 4 }; + testObj.text = "test"; + testObj.boolean = false; + CPPUNIT_ASSERT_EQUAL( + "{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}"s, + string(nestingObj.toJson().GetString())); + NestingArray nestingArray; + nestingArray.name = "nesting2"; + nestingArray.testObjects.emplace_back(testObj); + nestingArray.testObjects.emplace_back(testObj); + nestingArray.testObjects.back().number = 43; + CPPUNIT_ASSERT_EQUAL( + "{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}"s, + string(nestingArray.toJson().GetString())); +} + +/*! + * \brief Tests deserializing strings, numbers (int, float, double) and boolean. + */ +void ReflectorTests::testDeserializePrimitives() +{ + Document doc(kArrayType); + + doc.Parse("[\"a\", 5, 5e6, \"test\", true, 4.125, false]"); + auto array = doc.GetArray().begin(); + + string str1, str2; + int int1 = 0; + bool bool1 = false, bool2 = true; + float float1 = 0.0; + double double1 = 0.0; + Reflector::pull(str1, array); + Reflector::pull(int1, array); + Reflector::pull(float1, array); + Reflector::pull(str2, array); + Reflector::pull(bool1, array); + Reflector::pull(double1, array); + Reflector::pull(bool2, array); + + CPPUNIT_ASSERT_EQUAL("a"s, str1); + CPPUNIT_ASSERT_EQUAL(5, int1); + CPPUNIT_ASSERT_EQUAL(5e6f, float1); + CPPUNIT_ASSERT_EQUAL("test"s, str2); + CPPUNIT_ASSERT_EQUAL(true, bool1); + CPPUNIT_ASSERT_EQUAL(4.125, double1); + CPPUNIT_ASSERT_EQUAL(false, bool2); +} + +/*! + * \brief Tests deserializing simple objects. + */ +void ReflectorTests::testDeserializeSimpleObjects() +{ + const TestObject testObj( + TestObject::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}")); + + CPPUNIT_ASSERT_EQUAL(42, testObj.number); + CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2); + CPPUNIT_ASSERT_EQUAL(vector({ 1, 2, 3, 4 }), testObj.numbers); + CPPUNIT_ASSERT_EQUAL("test"s, testObj.text); + CPPUNIT_ASSERT_EQUAL(false, testObj.boolean); +} + +/*! + * \brief Tests deserializing nested objects and arrays. + */ +void ReflectorTests::testDeserializeNestedObjects() +{ + const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793," + "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}")); + const TestObject &testObj = nestingObj.testObj; + CPPUNIT_ASSERT_EQUAL("nesting"s, nestingObj.name); + CPPUNIT_ASSERT_EQUAL(42, testObj.number); + CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2); + CPPUNIT_ASSERT_EQUAL(vector({ 1, 2, 3, 4 }), testObj.numbers); + CPPUNIT_ASSERT_EQUAL("test"s, testObj.text); + CPPUNIT_ASSERT_EQUAL(false, testObj.boolean); + + const NestingArray nestingArray(NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793," + "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3." + "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}")); + const vector &testObjects = nestingArray.testObjects; + CPPUNIT_ASSERT_EQUAL("nesting2"s, nestingArray.name); + CPPUNIT_ASSERT_EQUAL(2_st, testObjects.size()); + CPPUNIT_ASSERT_EQUAL(42, testObjects[0].number); + CPPUNIT_ASSERT_EQUAL(43, testObjects[1].number); + for (const TestObject &testObj : testObjects) { + CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2); + CPPUNIT_ASSERT_EQUAL(vector({ 1, 2, 3, 4 }), testObj.numbers); + CPPUNIT_ASSERT_EQUAL("test"s, testObj.text); + CPPUNIT_ASSERT_EQUAL(false, testObj.boolean); + } +} diff --git a/moc/CMakeLists.txt b/moc/CMakeLists.txt new file mode 100644 index 0000000..841b960 --- /dev/null +++ b/moc/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) + +# metadata +set(META_PROJECT_NAME reflective_rapidjson_moc) +set(META_PROJECT_TYPE application) +set(LINK_TESTS_AGAINST_APP_TARGET ON) + +# add project files +set(HEADER_FILES + generator.h +) +set(SRC_FILES + generator.cpp + main.cpp +) +set(TEST_HEADER_FILES +) +set(TEST_SRC_FILES + tests/cppunit.cpp + tests/overall.cpp +) + +# find c++utilities +find_package(c++utilities 4.11.0 REQUIRED) +use_cpp_utilities() + +# find libclang +find_package(Clang REQUIRED) +list(APPEND PRIVATE_LIBRARIES libclang) +#list(APPEND PRIVATE_LIBRARIES clangFrontend clangLex clangAST) +if(STATIC_LINKAGE) + #list(APPEND PRIVATE_LIBRARIES clangAST) +else() + #list(APPEND PRIVATE_LIBRARIES libclang) +endif() +list(APPEND PRIVATE_LIBRARIES reflective_rapidjson) + +# include modules to apply configuration +include(BasicConfig) +include(WindowsResources) +include(AppTarget) +include(TestTarget) +include(ShellCompletion) +include(ConfigHeader) + diff --git a/moc/LICENSE b/moc/LICENSE new file mode 100644 index 0000000..23cb790 --- /dev/null +++ b/moc/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/moc/README.md b/moc/README.md new file mode 100644 index 0000000..df9d6c1 --- /dev/null +++ b/moc/README.md @@ -0,0 +1 @@ +# skel diff --git a/moc/generator.cpp b/moc/generator.cpp new file mode 100644 index 0000000..87e0b27 --- /dev/null +++ b/moc/generator.cpp @@ -0,0 +1,94 @@ +#include "./generator.h" + +#include +#include + +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +//#include +//#include + +//#include +//#include +//#include + +#include + +#include +#include + +using namespace std; +using namespace ConversionUtilities; + +namespace ReflectiveRapidJSON { + +ostream &operator<<(ostream &stream, const CXString &str) +{ + stream << clang_getCString(str); + clang_disposeString(str); + return stream; +} + +struct Struct { + string ns; + string name; + vector members; +}; + +bool generateReflectionCode(const vector &sourceFiles, ostream &os) +{ + bool noErrors = true; + + for (const char *sourceFile : sourceFiles) { + CXIndex index = clang_createIndex(0, 0); + const char *const args[] = { "-x", "c++" }; + CXTranslationUnit unit = nullptr; + CXErrorCode parseRes = clang_parseTranslationUnit2(index, sourceFile, args, 2, nullptr, 0, CXTranslationUnit_None, &unit); + if (!unit && parseRes != CXError_Success) { + clang_disposeIndex(index); + throw runtime_error(argsToString("Unable to parse translation unit: ", sourceFile)); + } + + CXCursor cursor = clang_getTranslationUnitCursor(unit); + clang_visitChildren(cursor, + [](CXCursor c, CXCursor parent, CXClientData client_data) { + VAR_UNUSED(parent) + auto &os = *reinterpret_cast(client_data); + os << "Cursor kind '" << clang_getCursorKindSpelling(clang_getCursorKind(c)) << "\' "; + os << clang_getCursorSpelling(c) << '\n'; + os << "type: " << clang_getTypeSpelling(clang_getCursorType(c)) << '\n'; + return CXChildVisit_Recurse; + }, + &os); + os.flush(); + + for (unsigned int index = 0, diagnosticCount = clang_getNumDiagnostics(unit); index != diagnosticCount; ++index) { + noErrors = false; + CXDiagnostic diagnostic = clang_getDiagnostic(unit, index); + clang_getDiagnosticCategory(diagnostic); + + CXString diagnosticSpelling = clang_formatDiagnostic( + diagnostic, CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges); + cerr << clang_getCString(diagnosticSpelling) << '\n'; + clang_disposeString(diagnosticSpelling); + clang_disposeDiagnostic(diagnostic); + } + cerr.flush(); + + clang_disposeTranslationUnit(unit); + clang_disposeIndex(index); + } + + return noErrors; +} + +} // namespace ReflectiveRapidJSON diff --git a/moc/generator.h b/moc/generator.h new file mode 100644 index 0000000..2502562 --- /dev/null +++ b/moc/generator.h @@ -0,0 +1,12 @@ +#ifndef REFLECTIVE_RAPIDJSON_GENERATOR_H +#define REFLECTIVE_RAPIDJSON_GENERATOR_H + +#include +#include + +namespace ReflectiveRapidJSON { + +bool generateReflectionCode(const std::vector &sourceFiles, std::ostream &os); +} + +#endif // REFLECTIVE_RAPIDJSON_GENERATOR_H diff --git a/moc/main.cpp b/moc/main.cpp new file mode 100644 index 0000000..bda7bc2 --- /dev/null +++ b/moc/main.cpp @@ -0,0 +1,67 @@ +#include "./generator.h" + +#include "resources/config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace ApplicationUtilities; +using namespace EscapeCodes; +using namespace IoUtilities; +using namespace ReflectiveRapidJSON; + +int main(int argc, char *argv[]) +{ + SET_APPLICATION_INFO; + CMD_UTILS_CONVERT_ARGS_TO_UTF8; + + // setup argument parser + ArgumentParser parser; + Argument inputFilesArg("input-files", 'i', "specifies the input files"); + inputFilesArg.setValueNames({ "path" }); + inputFilesArg.setRequiredValueCount(Argument::varValueCount); + Argument outputFileArg("output-file", 'o', "specifies the output file"); + outputFileArg.setValueNames({ "path" }); + outputFileArg.setRequiredValueCount(1); + outputFileArg.setCombinable(true); + HelpArgument helpArg(parser); + NoColorArgument noColorArg; + parser.setMainArguments({ &inputFilesArg, &outputFileArg, &noColorArg, &helpArg }); + + // parse arguments + parser.parseArgsOrExit(argc, argv); + if (!helpArg.isPresent() && !inputFilesArg.isPresent()) { + cerr << Phrases::Error << "No input file specified." << Phrases::EndFlush; + return -2; + } + + // setup output stream + try { + ostream *os; + ofstream outputFile; + if (outputFileArg.isPresent()) { + outputFile.exceptions(ios_base::badbit | ios_base::failbit); + outputFile.open(outputFileArg.values(0).front(), ios_base::out | ios_base::binary); + os = &outputFile; + } else { + os = &cout; + } + + // process input files + return generateReflectionCode(inputFilesArg.values(0), *os) ? 0 : 1; + } catch (...) { + catchIoFailure(); + cerr << Phrases::Error << "An IO error occured." << Phrases::EndFlush; + return -3; + } + + return 0; +} diff --git a/moc/testfiles/some_structs.h b/moc/testfiles/some_structs.h new file mode 100644 index 0000000..8d182e3 --- /dev/null +++ b/moc/testfiles/some_structs.h @@ -0,0 +1,29 @@ +#ifndef SOME_STRUCTS_H +#define SOME_STRUCTS_H + +//#include + +namespace TestNamespace1 { + +#define SOME_MACRO + +struct Reflectable +{ + +}; + +struct Person : public Reflectable +{ + SOME_MACRO + //std::string name; + int age; + bool alive; +}; + +} + +namespace TestNamespace2 { + +} + +#endif // SOME_STRUCTS_H diff --git a/moc/tests/cppunit.cpp b/moc/tests/cppunit.cpp new file mode 100644 index 0000000..67aaee6 --- /dev/null +++ b/moc/tests/cppunit.cpp @@ -0,0 +1 @@ +#include diff --git a/moc/tests/overall.cpp b/moc/tests/overall.cpp new file mode 100644 index 0000000..3d7c11d --- /dev/null +++ b/moc/tests/overall.cpp @@ -0,0 +1,67 @@ +#include "../generator.h" + +#include "resources/config.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace CPPUNIT_NS; +using namespace IoUtilities; +using namespace ConversionUtilities; +using namespace TestUtilities; +using namespace ReflectiveRapidJSON; + +class OverallTests : public TestFixture { + CPPUNIT_TEST_SUITE(OverallTests); + CPPUNIT_TEST(testGenerator); + CPPUNIT_TEST(testCLI); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testGenerator(); + void testCLI(); + +private: +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(OverallTests); + +void OverallTests::setUp() +{ +} + +void OverallTests::tearDown() +{ +} + +void OverallTests::testGenerator() +{ + const string inputFilePath(testFilePath("some_structs.h")); + stringstream buffer; + generateReflectionCode({ inputFilePath.data() }, buffer); + CPPUNIT_ASSERT_EQUAL("test"s, buffer.str()); +} + +void OverallTests::testCLI() +{ +#ifdef PLATFORM_UNIX + const string inputFilePath(testFilePath("some_structs.h")); + string stdout, stderr; + const char *const args1[] = { PROJECT_NAME, "-i", inputFilePath.data(), nullptr }; + TESTUTILS_ASSERT_EXEC(args1); + CPPUNIT_ASSERT_EQUAL("test"s, stdout); +#endif +}