diff --git a/CMakeLists.txt b/CMakeLists.txt index b58cd2b..934c676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,15 +8,13 @@ project( ) # User options -option(CPPPROPERTIES_BUILD_EXAMPLES "Whether to build examples." ON) -option(CPPPROPERTIES_BUILD_TESTS "Whether to build tests." ON) -option(CPPPROPERTIES_ENABLE_BOOST "Whether to enable built-in support for common boost types." OFF) -option(CPPPROPERTIES_ENABLE_QT "Whether to enable built-in support for Qt types." OFF) -option(CPPPROPERTIES_ENABLE_QT_WIDGETS "Whether to enable built-in support for Qt widgets." OFF) -option(CPPPROPERTIES_ENABLE_JSON "Whether to enable JSON (de)serialization." ON) -option(CPPPROPERTIES_ENABLE_XML "Whether to enable XML (de)serialization." ON) -option(CPPPROPERTIES_ENABLE_GPDS "Whether to enable GPDS (de)serialization." OFF) -option(CPPPROPERTIES_PERFORM_CPPCHECK "Whether to run cppcheck." OFF) +option(CPPPROPERTIES_BUILD_EXAMPLES "Whether to build examples." ON) +option(CPPPROPERTIES_BUILD_TESTS "Whether to build tests." ON) +option(CPPPROPERTIES_ENABLE_BOOST "Whether to enable built-in support for common boost types." OFF) +option(CPPPROPERTIES_ENABLE_QT "Whether to enable built-in support for Qt types." OFF) +option(CPPPROPERTIES_ENABLE_QT_WIDGETS "Whether to enable built-in support for Qt widgets." OFF) +option(CPPPROPERTIES_ENABLE_SERIALIZATION "Whether to enable (de)serialization." OFF) +option(CPPPROPERTIES_PERFORM_CPPCHECK "Whether to run cppcheck." OFF) # Include examples (if supposed to) if (CPPPROPERTIES_BUILD_EXAMPLES) @@ -59,9 +57,7 @@ message(STATUS " Boost : " ${CPPPROPERTIES_ENABLE_BOOST}) message(STATUS " Qt : " ${CPPPROPERTIES_ENABLE_QT}) message(STATUS "") message(STATUS "Serialization:") -message(STATUS " JSON : " ${CPPPROPERTIES_ENABLE_JSON}) -message(STATUS " XML : " ${CPPPROPERTIES_ENABLE_XML}) -message(STATUS " GPDS : " ${CPPPROPERTIES_ENABLE_GPDS}) +message(STATUS " GPDS : " ${CPPPROPERTIES_ENABLE_SERIALIZATION}) message(STATUS "") message(STATUS "GUI Elements:") message(STATUS " Qt : " ${CPPPROPERTIES_ENABLE_QT_WIDGETS}) diff --git a/cppproperties/CMakeLists.txt b/cppproperties/CMakeLists.txt index 08f9e44..68b35e5 100644 --- a/cppproperties/CMakeLists.txt +++ b/cppproperties/CMakeLists.txt @@ -6,10 +6,6 @@ set(TARGET cppproperties) # List of public headers set(HEADERS_PUBLIC - archiver.hpp - $<$:${CMAKE_CURRENT_LIST_DIR}/archiver_json.hpp> - $<$:${CMAKE_CURRENT_LIST_DIR}/archiver_xml.hpp> - $<$:${CMAKE_CURRENT_LIST_DIR}/archiver_gpds.hpp> exceptions.hpp properties.hpp property.hpp @@ -18,6 +14,7 @@ set(HEADERS_PUBLIC property_ex_cpp_modern.hpp $<$:${CMAKE_CURRENT_LIST_DIR}/property_ex_boost.hpp> $<$:${CMAKE_CURRENT_LIST_DIR}/property_ex_qt.hpp> + $<$:${CMAKE_CURRENT_LIST_DIR}/serialization.hpp> ) set(HEADERS_QT_WIDGETS_PUBLIC @@ -41,9 +38,7 @@ target_compile_definitions( $<$:CPPPROPERTIES_ENABLE_BOOST> $<$:CPPPROPERTIES_ENABLE_QT> $<$:CPPPROPERTIES_ENABLE_QT_WIDGETS> - $<$:CPPPROPERTIES_ENABLE_JSON> - $<$:CPPPROPERTIES_ENABLE_XML> - $<$:CPPPROPERTIES_ENABLE_GPDS> + $<$:CPPPROPERTIES_ENABLE_SERIALIZATION> ) target_sources( @@ -58,9 +53,7 @@ target_link_libraries( INTERFACE $<$:Boost::headers> $<$:Qt::Core> - $<$:gpds::gpds-shared> - $<$:nlohmann_json::nlohmann_json> - $<$:tinyxml2::tinyxml2> + $<$:gpds::gpds-shared> $<$:Qt::Gui> $<$:Qt::Widgets> ) diff --git a/cppproperties/archiver.hpp b/cppproperties/archiver.hpp deleted file mode 100644 index d59eeb0..0000000 --- a/cppproperties/archiver.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace tct::properties -{ - - class properties; - - /** - * Archiver interface for (de)serialization of properties. - * - * Implementing this interface allows adding support for (de)serialization - * using any suitable format. For example, there are built-in archivers (by - * implementing this interface) for JSON and XML (de)serialization. - */ - struct archiver - { - public: - /** - * Serialize properties to string. - * - * @param p The properties to serialize. - * @return The serialized properties. - */ - [[nodiscard]] - virtual - std::string - save(const properties& p) const = 0; - - /** - * Deserialize properties from string. - * - * @param p The target properties. - * @param str The serialized properties. - * @return `true` on success, `false` on failure with optional error message. - */ - virtual - std::pair - load(properties& p, const std::string& str) const = 0; - - /** - * Serialize properties to a file. - * - * @param p The properties to serialize to a file. - * @param path The path of the output file. - * @return `true` on success, `false` on failure with optional error message. - */ - [[nodiscard("file i/o might fail")]] - std::pair - save(const properties& p, const std::filesystem::path& path) const - { - // Prepare file - std::ofstream file; - file.open(path, std::ios::out | std::ios::trunc); - if (not file.is_open()) - return { false, "Could not open file for writing at path " + path.string() }; - - // Write to file - file << save(p); - - // Close file - file.close(); - - return { true, "" }; - } - - /** - * Deserialize properties from a file. - * - * @param p The target properties. - * @param path The path of the input file. - * @return `true` on success, `false` on failure with optional error message. - */ - [[nodiscard("file i/o might fail")]] - std::pair - load(properties& p, const std::filesystem::path& path) const - { - // Prepare file - std::ifstream file; - file.open(path, std::ios::in); - if (not file.is_open()) - return { false, "Could not open file for reading at path " + path.string() }; - - // Read from file - std::stringstream ss; - ss << file.rdbuf(); - - // Close the file - file.close(); - - // Load from string - return load(p, ss.str()); - } - }; - -} diff --git a/cppproperties/archiver_json.hpp b/cppproperties/archiver_json.hpp deleted file mode 100644 index 2307798..0000000 --- a/cppproperties/archiver_json.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "archiver.hpp" - -namespace tct::properties -{ - - class properties; - - /** - * Built-in archiver for (de)serialization to/from JSON. - * - * @details This implementation uses `nlohmann::json`. - */ - class archiver_json : - public archiver - { - public: - [[nodiscard]] - std::string - save(const properties& p) const override; - - std::pair - load(properties& p, const std::string& str) const override; - - private: - static - void - write_recursively(); - - static - void - read_recursively(); - }; - -} - - -#include - -#include "properties.hpp" - -namespace tct::properties -{ - - inline - std::string - archiver_json::save(const properties& p) const - { - nlohmann::json json; - - for (const auto& [key, value] : p) { - json[key] = value->to_string(); - } - - return json.dump(4); - } - - inline - std::pair - archiver_json::load(properties& p, const std::string& str) const - { - nlohmann::json json(str); - - return { true, "success" }; - } - -} diff --git a/cppproperties/archiver_xml.hpp b/cppproperties/archiver_xml.hpp deleted file mode 100644 index 0e957a2..0000000 --- a/cppproperties/archiver_xml.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#pragma once - -#include "archiver.hpp" - -namespace tinyxml2 -{ - class XMLElement; - class XMLDocument; -} - -namespace tct::properties -{ - - class properties; - - /** - * Built-in archiver for (de)serialization to/from XML. - * - * @details This implementation uses the tinyxml2 library. - */ - class archiver_xml : - public archiver - { - public: - [[nodiscard]] - std::string - save(const properties& p) const override; - - std::pair - load(properties& p, const std::string& str) const override; - - private: - static - void - write_recursively(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement& root, const ::tct::properties::properties& p); - - static - void - read_recursively(tinyxml2::XMLElement& root, ::tct::properties::properties& p); - }; - -} - -#include - -#include - -#include "properties.hpp" - -namespace tct::properties -{ - - inline - std::string - archiver_xml::save(const properties& p) const - { - // Create document - tinyxml2::XMLDocument doc; - - // Add the root node - tinyxml2::XMLElement* root = doc.NewElement("properties"); - doc.InsertEndChild(root); - - // Iterate properties - write_recursively(doc, *root, p); - - // Print to string - tinyxml2::XMLPrinter printer; - doc.Print(&printer); - std::string str = printer.CStr(); - - // Free up memory - doc.Clear(); - - return str; - } - - inline - std::pair - archiver_xml::load(properties& p, const std::string& str) const - { - // Create document - tinyxml2::XMLDocument doc; - doc.Parse(str.data()); - - // Retrieve the root node - tinyxml2::XMLElement* root = doc.FirstChildElement("properties"); - if (!root) - return { false, "Could not find root node \"properties\"" }; - - // Iterate properties - read_recursively(*root, p); - - return { true, "" }; - } - - inline - void - archiver_xml::write_recursively(tinyxml2::XMLDocument& doc, tinyxml2::XMLElement& root, const ::tct::properties::properties& p) - { - for (const auto& [key, value] : p) { - assert(!key.empty()); - assert(value); - - // Attributes - for (const auto& [attr_key, attr_value] : p.attributes()) - root.SetAttribute(attr_key.c_str(), attr_value.c_str()); - - // Create new element - tinyxml2::XMLElement* element = doc.NewElement(key.c_str()); - if (!element) - throw std::runtime_error("Could not create new tinyxml::XMLElement object"); - - // Check if nested - const properties* nested = dynamic_cast(value); - if (nested) - write_recursively(doc, *element, *nested); - - // Not nested - else { - assert(value->to_string); - - // Value - element->SetText(value->to_string().c_str()); - - // Attributes - for (const auto& [attr_key, attr_value] : value->attributes()) - element->SetAttribute(attr_key.c_str(), attr_value.c_str()); - } - - root.InsertEndChild(element); - } - } - - inline - void - archiver_xml::read_recursively(tinyxml2::XMLElement& root, ::tct::properties::properties& p) - { - // Attributes - for (const tinyxml2::XMLAttribute* attribute = root.FirstAttribute(); attribute; attribute = attribute->Next()) - p.set_attribute(attribute->Name(), attribute->Value()); - - // Iterate properties - for (auto& [key, value] : p) { - tinyxml2::XMLElement* element = root.FirstChildElement(key.c_str()); - if (!element) - continue; - - // Check if nested - if (!element->GetText()) { - // Find the nested properties - properties* nested = p.get_nested_properties(key); - if (!nested) - throw std::runtime_error("Could not retrieve nested property \"" + key + "\"."); - - read_recursively(*element, *nested); - } - - // Not nested - else { - if (element->GetText()) { - const std::string value_str(element->GetText()); - assert(value); - value->from_string(element->GetText()); - } - - // Attributes - for (const tinyxml2::XMLAttribute* attribute = element->FirstAttribute(); attribute; attribute = attribute->Next()) - value->set_attribute(attribute->Name(), attribute->Value()); - } - } - } - -} diff --git a/cppproperties/external.cmake b/cppproperties/external.cmake index 91d8a54..6ef1107 100644 --- a/cppproperties/external.cmake +++ b/cppproperties/external.cmake @@ -28,25 +28,9 @@ if (CPPPROPERTIES_ENABLE_BOOST) endif() # GPDS -if (CPPPROPERTIES_ENABLE_GPDS) +if (CPPPROPERTIES_ENABLE_SERIALIZATION) find_package( gpds REQUIRED ) endif() - -# JSON -if (CPPPROPERTIES_ENABLE_JSON) - find_package( - nlohmann_json - REQUIRED - ) -endif() - -# XML -if (CPPPROPERTIES_ENABLE_XML) - find_package( - tinyxml2 - REQUIRED - ) -endif() diff --git a/cppproperties/properties.hpp b/cppproperties/properties.hpp index 8dee0ed..4b4c96f 100644 --- a/cppproperties/properties.hpp +++ b/cppproperties/properties.hpp @@ -7,7 +7,6 @@ #include #include -#include "archiver.hpp" #include "exceptions.hpp" #define MAKE_PROPERTY(name, type) \ @@ -249,59 +248,6 @@ namespace tct::properties return dynamic_cast(it->second); } - /** - * Serialize properties to string. - * - * @param ar The archiver to use. - * @return The serialized string. - */ - [[nodiscard]] - std::string - save(const archiver& ar) const - { - return ar.save(*this); - } - - /** - * Serialize properties to file. - * - * @param ar The archiver to use. - * @param path The file path. - * @return @p true if successful, @p false otherwise with optional error message. - */ - [[nodiscard("file i/o might fail")]] - std::pair - save(const archiver& ar, const std::filesystem::path& path) - { - return ar.save(*this, path); - } - - /** - * Deserialize properties from string. - * - * @param ar The archiver to use. - * @param str The string to deserialize. - */ - void - load(const archiver& ar, const std::string& str) - { - ar.load(*this, str); - } - - /** - * Deserialize properties from file. - * - * @param ar The archiver to use. - * @path The file path. - * @return @p true on success, @p false otherwise with optional error message. - */ - [[nodiscard("file i/o might fail")]] - std::pair - load(const archiver& ar, const std::filesystem::path& path) - { - return ar.load(*this, path); - } - private: std::map m_properties; }; diff --git a/cppproperties/qt_widgets/nested.hpp b/cppproperties/qt_widgets/nested.hpp index e009ce9..08b87d2 100644 --- a/cppproperties/qt_widgets/nested.hpp +++ b/cppproperties/qt_widgets/nested.hpp @@ -8,13 +8,19 @@ namespace tct::properties::qt_widgets { class nested : - public QGroupBox + public QGroupBox, + public widget_base { Q_OBJECT Q_DISABLE_COPY_MOVE(nested) public: - nested() = default; + explicit + nested(tct::properties::property& p) : + widget_base(p) + { + } + ~nested() override = default; }; diff --git a/cppproperties/archiver_gpds.hpp b/cppproperties/serialization.hpp similarity index 100% rename from cppproperties/archiver_gpds.hpp rename to cppproperties/serialization.hpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4e784c6..5ceeccc 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,19 +1,12 @@ add_subdirectory(basic) add_subdirectory(custom_types) -if (CPPPROPERTIES_ENABLE_GPDS) - add_subdirectory(gpds) -endif() -if (CPPPROPERTIES_ENABLE_JSON) - add_subdirectory(json) -endif() -if (CPPPROPERTIES_ENABLE_XML) - add_subdirectory(xml) -endif() add_subdirectory(linked_properties) add_subdirectory(linked_property_functions) add_subdirectory(nested) add_subdirectory(notification) +if (CPPPROPERTIES_ENABLE_SERIALIZATION) + add_subdirectory(serialization) +endif() if (CPPPROPERTIES_ENABLE_QT_WIDGETS) add_subdirectory(qt_widgets) endif() -add_subdirectory(serialization) diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp index 8f4641d..2b070f1 100644 --- a/examples/basic/main.cpp +++ b/examples/basic/main.cpp @@ -1,7 +1,6 @@ #include #include "cppproperties/properties.hpp" -#include "cppproperties/archiver_xml.hpp" struct shape : tct::properties::properties @@ -29,9 +28,5 @@ int main() std::cout << "name = " << s.name << "\n"; std::cout << std::endl; - // Print properties automatically - std::cout << "Properties:\n"; - std::cout << s.save(tct::properties::archiver_xml()) << std::endl; - return 0; } diff --git a/examples/gpds/CMakeLists.txt b/examples/gpds/CMakeLists.txt deleted file mode 100644 index 9b526dd..0000000 --- a/examples/gpds/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -include(../../cppproperties/external.cmake) - -set(TARGET example-gpds) - -add_executable(${TARGET}) - -target_sources( - ${TARGET} - PRIVATE - main.cpp -) - -target_include_directories( - ${TARGET} - PRIVATE - ${CMAKE_CURRENT_LIST_DIR}/../.. -) - -target_link_libraries( - ${TARGET} - PRIVATE - cppproperties -) diff --git a/examples/gpds/main.cpp b/examples/gpds/main.cpp deleted file mode 100644 index be2927d..0000000 --- a/examples/gpds/main.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include - -#include -#include - -#include "cppproperties/properties.hpp" -#include "cppproperties/archiver_gpds.hpp" - -struct shape : - tct::properties::properties -{ - MAKE_PROPERTY(locked, bool); - MAKE_PROPERTY(x, int); - MAKE_PROPERTY(y, int); - MAKE_PROPERTY(name, std::string); -}; - -int main() -{ - shape s; - s.locked = false; - s.x = 24; - s.y = 48; - s.name = "My Shape"; - s.set_attribute("foobar", "zbar"); - s.name.set_attribute("name-attr", "test1234"); - - tct::properties::archiver_gpds ar; - const gpds::container& c = ar.save(s); - - std::stringstream ss; - gpds::archiver_xml gpds_ar; - gpds_ar.save(ss, c, "properties"); - - gpds::container gpds_c; - gpds_ar.load(ss, gpds_c, "properties"); - shape s2; - ar.load(s2, gpds_c); - - std::cout << s2.locked << "\n"; - std::cout << s2.x << "\n"; - std::cout << s2.y << "\n"; - std::cout << s2.name << "\n"; - - return 0; -} diff --git a/examples/json/CMakeLists.txt b/examples/json/CMakeLists.txt deleted file mode 100644 index 09da2e6..0000000 --- a/examples/json/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -include(../../cppproperties/external.cmake) - -set(TARGET example-json) - -add_executable(${TARGET}) - -target_sources( - ${TARGET} - PRIVATE - main.cpp -) - -target_include_directories( - ${TARGET} - PRIVATE - ${CMAKE_CURRENT_LIST_DIR}/../.. -) - -target_link_libraries( - ${TARGET} - PRIVATE - cppproperties -) diff --git a/examples/json/main.cpp b/examples/json/main.cpp deleted file mode 100644 index 46a02af..0000000 --- a/examples/json/main.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#include "cppproperties/properties.hpp" -#include "cppproperties/archiver_json.hpp" - -struct shape : - tct::properties::properties -{ - MAKE_PROPERTY(locked, bool); - MAKE_PROPERTY(x, int); - MAKE_PROPERTY(y, int); - MAKE_PROPERTY(name, std::string); -}; - -int main() -{ - shape s; - s.locked = false; - s.x = 24; - s.y = 48; - s.name = "My Shape"; - s.set_attribute("foobar", "zbar"); - s.name.set_attribute("name-attr", "test1234"); - - tct::properties::archiver_json ar; - std::string json_str = ar.save(s); - - std::cout << json_str << "\n"; - - return 0; -} diff --git a/examples/qt_widgets/main.cpp b/examples/qt_widgets/main.cpp index cf189c6..3ea75cb 100644 --- a/examples/qt_widgets/main.cpp +++ b/examples/qt_widgets/main.cpp @@ -6,12 +6,34 @@ #include "cppproperties/properties.hpp" #include "cppproperties/qt_widgets/factory.hpp" +struct color : + tct::properties::properties +{ + MAKE_PROPERTY(red, int); + MAKE_PROPERTY(green, int); + MAKE_PROPERTY(blue, int); + + void set(const std::string& rgb_string) + { + if (rgb_string.size() != 6) + throw std::runtime_error(R"(RGB string is malformed. Needs to be of format "rrggbb" in hex format.)"); + + int hex = std::stoi(rgb_string, nullptr, 16); + this->red = (hex / 0x10000); + this->green = (hex / 0x100) % 0x100; + this->blue = (hex % 0x100); + } +}; + + struct shape : tct::properties::properties { MAKE_PROPERTY(enabled, bool); MAKE_PROPERTY(x, int); MAKE_PROPERTY(y, int); + MAKE_NESTED_PROPERTY(fg_color, color); + MAKE_NESTED_PROPERTY(bg_color, color); shape() { diff --git a/examples/serialization/main.cpp b/examples/serialization/main.cpp index 7ee6787..cfe9e9a 100644 --- a/examples/serialization/main.cpp +++ b/examples/serialization/main.cpp @@ -1,11 +1,16 @@ #include #include "cppproperties/properties.hpp" -#include "cppproperties/archiver_xml.hpp" +#include "cppproperties/serialization.hpp" + +#include +#include struct shape : tct::properties::properties { + static constexpr const char* gpds_name = "shape"; + MAKE_PROPERTY(x, int); MAKE_PROPERTY(y, int); MAKE_PROPERTY(name, std::string); @@ -13,9 +18,6 @@ struct shape : int main() { - // Create an XML archiver - tct::properties::archiver_xml ar; - // Create object shape s1; s1.set_attribute("something", "something else"); @@ -25,11 +27,16 @@ int main() s1.y.set_attribute("units", "px"); s1.name = "My Shape"; - // Serialize to XML file + // + // Note: The GPDS library allows to (de)serialize to and from various formats and sources/sinks. + // Here we only show some of those. + // + + // To XML file { - const auto& [success, message] = s1.save(ar, "shape.xml"); - if (not success) { - std::cout << "Could not save to file: " << message << std::endl; + const auto& [success, message] = gpds::to_file("shape.xml", s1); + if (!success) { + std::cerr << "Could not save to XML file: " << message << std::endl; return EXIT_FAILURE; } } @@ -37,18 +44,18 @@ int main() // Create another object shape s2; - // Deserialize from XML file + // From XML file { - const auto& [success, message] = s2.load(ar, std::filesystem::path{"shape.xml"}); - if (not success) { - std::cout << "Could not save to file: " << message << std::endl; + const auto& [success, message] = gpds::from_file("shape.xml", s2); + if (!success) { + std::cerr << "Could not save to file: " << message << std::endl; return EXIT_FAILURE; } } // Print both s1 and s2 as XML strings - std::cout << s1.save(ar) << "\n"; - std::cout << s2.save(ar) << "\n"; + //std::cout << s1.save(ar) << "\n"; + //std::cout << s2.save(ar) << "\n"; return 0; } diff --git a/examples/xml/CMakeLists.txt b/examples/xml/CMakeLists.txt deleted file mode 100644 index 3f804f2..0000000 --- a/examples/xml/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -include(../../cppproperties/external.cmake) - -set(TARGET example-xml) - -add_executable(${TARGET}) - -target_sources( - ${TARGET} - PRIVATE - main.cpp -) - -target_include_directories( - ${TARGET} - PRIVATE - ${CMAKE_CURRENT_LIST_DIR}/../.. -) - -target_link_libraries( - ${TARGET} - PRIVATE - cppproperties -) diff --git a/examples/xml/main.cpp b/examples/xml/main.cpp deleted file mode 100644 index e56927c..0000000 --- a/examples/xml/main.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#include "cppproperties/properties.hpp" -#include "cppproperties/archiver_xml.hpp" - -struct shape : - tct::properties::properties -{ - MAKE_PROPERTY(locked, bool); - MAKE_PROPERTY(x, int); - MAKE_PROPERTY(y, int); - MAKE_PROPERTY(name, std::string); -}; - -int main() -{ - shape s; - s.locked = false; - s.x = 24; - s.y = 48; - s.name = "My Shape"; - s.set_attribute("foobar", "zbar"); - s.name.set_attribute("name-attr", "test1234"); - - tct::properties::archiver_xml ar; - std::string xml_str = ar.save(s); - - std::cout << xml_str << "\n"; - - return 0; -} diff --git a/readme.md b/readme.md index d550913..3753a6d 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ The library is built with the following aspects in mind: - Easy to use - Providing "raw access" to the properties just as if they were regular class members. - Easy registration of custom property types. -- Easy integration of optional (de)serialization (XML & JSON already optionally built-in). +- Optional (de)serialization via [GPDS](https://github.com/simulton/gpds). - Observer interface for property change notifications. - Support for linked properties (properties in a base class not implementing this library). - GUI generator (Qt widgets) @@ -26,9 +26,6 @@ A couple of things to be aware of when using this library: # License This library is MIT licensed. -- If JSON (de)serialization is enabled, [nlohmann::json](https://github.com/nlohmann/json) is used for JSON serialization. The json library itself is MIT licensed. -- If XML (de)serialization is enabled, [tinyxml2](https://github.com/leethomason/tinyxml2) is used for XML serialization. The tinyxml2 library itself is zlib licensed. - # Support types Any type can be registered as a property type using the `REGISTER_PROPERTY` macro. For convenience, a set of built-in types are already registered: @@ -146,7 +143,8 @@ int main() ``` ## Serialization -The library comes with built-in support for (de)serialization. Classes can be easily (de)serialization to/from XML: +Properties can be (de)serialized via [GPDS](https://github.com/simulton/gpds) to and from various formats such as XML and YAML. +For (de)serialization options, check the GPDS documentation. ```cpp struct shape : tct::properties::properties