├── Makefile.extra.in ├── docSource ├── deploy ├── _version ├── .gitignore ├── script │ └── Notes ├── layout │ └── Notes ├── public │ └── Notes ├── source │ ├── favicon.ico │ ├── group │ │ ├── 1 │ │ ├── impl.md │ │ ├── intro.md │ │ ├── internal.md │ │ ├── usage.md │ │ ├── api.md │ │ ├── implTraitsValue.md │ │ ├── apiExporter.md │ │ ├── apiImporter.md │ │ ├── usageDeclarations.md │ │ ├── usageSerializingStrictness.md │ │ ├── implTraitsSerialize.md │ │ ├── apiJSON.md │ │ ├── apiYAML.md │ │ ├── apiBinary.md │ │ ├── usageSerializingFormat.md │ │ ├── usageSerializingExceptions.md │ │ ├── usageDeclarationsValue.md │ │ ├── implTraitsEnum.md │ │ ├── usageDeclarationsStandardContainers.md │ │ ├── usageDeclarationsEnum.md │ │ ├── implTraitsPointer.md │ │ ├── usageDeclarationsStandardTypes.md │ │ ├── usageSerializing.md │ │ ├── implTraits.md │ │ ├── implTraitsArray.md │ │ ├── apiMacros.md │ │ ├── implTraitsMap.md │ │ ├── usageDeclarationsPointers.md │ │ └── usageDeclarationsStructure.md │ ├── package │ │ ├── ThorBinaryRep.md │ │ ├── ThorSerialize.md │ │ └── ThorSerialize-api.md │ ├── function │ │ ├── ThorSerialize.BinaryThor.binExport.md │ │ ├── ThorSerialize.BinaryThor.binImport.md │ │ ├── ThorSerialize.JsonThor.jsonExport.md │ │ ├── ThorSerialize.YamlThor.yamlExport.md │ │ ├── ThorSerialize.JsonThor.jsonImport.md │ │ └── ThorSerialize.YamlThor.yamlImport.md │ └── posts │ │ └── 2018-03-14-Test-Article.html └── config.json ├── Notes ├── apps ├── Mug ├── ThorsMug ├── NisseHTTP ├── NisseLib ├── TestExtra ├── ThorsSlack ├── NisseServer └── Makefile ├── Makefile.extra.am ├── .gitattributes ├── codecov.yml ├── src ├── ThorsMongo ├── Serialize ├── ThorsCrypto ├── ThorsIOUtil ├── ThorsSocket ├── fast_float ├── ThorsLogging ├── ThorsStorage └── Makefile ├── docs ├── Notes ├── favicon.ico ├── images │ ├── logo.png │ └── navbar.png ├── posts │ └── 2018-03-14-Test-Article.html ├── stylesheet │ ├── style.css │ ├── prism.css │ ├── print.css │ └── screen.css ├── group │ └── 1 └── javascripts │ └── prism.js ├── img ├── avatar.jpg ├── stream.jpg └── thorsanvil.jpg ├── brew └── init ├── doc ├── example7.json ├── example0.cpp ├── exampleE.cpp ├── example0.md ├── objective.md ├── example8.cpp ├── exampleE.md ├── example4.cpp ├── example6.cpp ├── example7.cpp ├── example1.cpp ├── example3.cpp ├── example2.cpp ├── example7.md ├── example6.md ├── example1.md ├── building.md ├── example2.md ├── example3.md ├── example8.md ├── usage.md └── full.md ├── .gitignore ├── Makefile.config.in ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── build.yml ├── Makefile ├── COPYRIGHT ├── .gitmodules ├── configure.ac ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── config.h.in ├── conanfile.py ├── README.md └── .clang-format /Makefile.extra.in: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docSource/deploy: -------------------------------------------------------------------------------- 1 | ../docs -------------------------------------------------------------------------------- /Notes: -------------------------------------------------------------------------------- 1 | build/autotools/Notes -------------------------------------------------------------------------------- /apps/Mug: -------------------------------------------------------------------------------- 1 | ../third/Mug/src/Mug -------------------------------------------------------------------------------- /docSource/_version: -------------------------------------------------------------------------------- 1 | 0.00.4 -------------------------------------------------------------------------------- /Makefile.extra.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | -------------------------------------------------------------------------------- /apps/ThorsMug: -------------------------------------------------------------------------------- 1 | ../third/Mug/src/ThorsMug -------------------------------------------------------------------------------- /apps/NisseHTTP: -------------------------------------------------------------------------------- 1 | ../third/Nisse/src/NisseHTTP -------------------------------------------------------------------------------- /apps/NisseLib: -------------------------------------------------------------------------------- 1 | ../third/Nisse/src/NisseLib -------------------------------------------------------------------------------- /apps/TestExtra: -------------------------------------------------------------------------------- 1 | ../third/Mug/src/TestExtra -------------------------------------------------------------------------------- /apps/ThorsSlack: -------------------------------------------------------------------------------- 1 | ../third/Mug/src/ThorsSlack -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.* linguist-language=C++ 2 | -------------------------------------------------------------------------------- /apps/NisseServer: -------------------------------------------------------------------------------- 1 | ../third/Nisse/src/NisseServer -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "**/test/*" 3 | -------------------------------------------------------------------------------- /docSource/.gitignore: -------------------------------------------------------------------------------- 1 | public 2 | docSource 3 | -------------------------------------------------------------------------------- /src/ThorsMongo: -------------------------------------------------------------------------------- 1 | ../third/ThorsMongo/src/ThorsMongo -------------------------------------------------------------------------------- /docs/Notes: -------------------------------------------------------------------------------- 1 | Site will be generated into this direcory -------------------------------------------------------------------------------- /src/Serialize: -------------------------------------------------------------------------------- 1 | ../third/ThorsSerializer/src/Serialize -------------------------------------------------------------------------------- /src/ThorsCrypto: -------------------------------------------------------------------------------- 1 | ../third/ThorsCrypto/src/ThorsCrypto -------------------------------------------------------------------------------- /src/ThorsIOUtil: -------------------------------------------------------------------------------- 1 | ../third/ThorsIOUtil/src/ThorsIOUtil -------------------------------------------------------------------------------- /src/ThorsSocket: -------------------------------------------------------------------------------- 1 | ../third/ThorsSocket/src/ThorsSocket -------------------------------------------------------------------------------- /src/fast_float: -------------------------------------------------------------------------------- 1 | ../third/ThorsSerializer/src/fast_float -------------------------------------------------------------------------------- /docSource/script/Notes: -------------------------------------------------------------------------------- 1 | Contains Site specific functionality -------------------------------------------------------------------------------- /src/ThorsLogging: -------------------------------------------------------------------------------- 1 | ../third/ThorsLogging/src/ThorsLogging -------------------------------------------------------------------------------- /src/ThorsStorage: -------------------------------------------------------------------------------- 1 | ../third/ThorsStorage/src/ThorsStorage -------------------------------------------------------------------------------- /docSource/layout/Notes: -------------------------------------------------------------------------------- 1 | Contains Site overrides of themes/layout/ -------------------------------------------------------------------------------- /docSource/public/Notes: -------------------------------------------------------------------------------- 1 | Site will be generated into this direcory -------------------------------------------------------------------------------- /img/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Loki-Astari/ThorsAnvil/HEAD/img/avatar.jpg -------------------------------------------------------------------------------- /img/stream.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Loki-Astari/ThorsAnvil/HEAD/img/stream.jpg -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Loki-Astari/ThorsAnvil/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Loki-Astari/ThorsAnvil/HEAD/docs/images/logo.png -------------------------------------------------------------------------------- /img/thorsanvil.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Loki-Astari/ThorsAnvil/HEAD/img/thorsanvil.jpg -------------------------------------------------------------------------------- /docs/images/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Loki-Astari/ThorsAnvil/HEAD/docs/images/navbar.png -------------------------------------------------------------------------------- /docSource/source/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Loki-Astari/ThorsAnvil/HEAD/docSource/source/favicon.ico -------------------------------------------------------------------------------- /docSource/source/group/impl.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | children: 5 | - name: Traits 6 | value: implTraits.md 7 | --- 8 | -------------------------------------------------------------------------------- /brew/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if command -v apt-get ; then 4 | sudo apt-get update -y && sudo apt-get install lsb-release -y && sudo apt-get clean all 5 | fi 6 | 7 | -------------------------------------------------------------------------------- /docSource/source/package/ThorBinaryRep.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: 5 | headers: 6 | base: ThorBinaryRep 7 | files: [] 8 | children: [] 9 | --- 10 | -------------------------------------------------------------------------------- /docSource/source/group/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | 6 | [ThorsSerializer](https://github.com/Loki-Astari/ThorsSerializer) A modern declarative C++ serialization library. 7 | 8 | -------------------------------------------------------------------------------- /docSource/source/package/ThorSerialize.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: ThorsAnvil::Serialize 5 | headers: 6 | base: ThorSerialize 7 | files: 8 | children: [] 9 | --- 10 | -------------------------------------------------------------------------------- /apps/Makefile: -------------------------------------------------------------------------------- 1 | 2 | THORSANVIL_ROOT = $(realpath ../) 3 | 4 | TARGET = NisseServer NisseHTTP NisseLib ThorsMug ThorsSlack TestExtra Mug 5 | 6 | include $(THORSANVIL_ROOT)/build/tools/Project.Makefile 7 | 8 | 9 | -------------------------------------------------------------------------------- /docSource/source/group/internal.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | children: 5 | - name: ThorSerialize 6 | value: ThorSerialize.md 7 | - name: ThorBinaryRep 8 | value: ThorBinaryRep.md 9 | --- 10 | -------------------------------------------------------------------------------- /docSource/source/group/usage.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | children: 5 | - name: Serializing 6 | value: usageSerializing.md 7 | - name: Declarations 8 | value: usageDeclarations.md 9 | --- 10 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | THORSANVIL_ROOT = $(realpath ../) 3 | 4 | TARGET = ThorsLogging ThorsIOUtil fast_float Serialize ThorsCrypto ThorsStorage ThorsSocket ThorsMongo 5 | 6 | include $(THORSANVIL_ROOT)/build/tools/Project.Makefile 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /doc/example7.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": [ 3 | { 4 | "type": "mesh", 5 | "axis": ["x","y","z"] 6 | } 7 | ] 8 | } 9 | { 10 | "components": [ 11 | { 12 | "type": "mesh", 13 | "axis": ["x","y",z] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /doc/example0.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ThorSerialize/JsonThor.h" 4 | 5 | int main() 6 | { 7 | std::vector data; 8 | using ThorsAnvil::Serialize::jsonImporter; 9 | using ThorsAnvil::Serialize::jsonExporter; 10 | 11 | std::cin >> jsonImporter(data); 12 | std::cout << jsonExporter(data) << "\n"; 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lex.cpp 3 | *.lex.h 4 | .*.swp 5 | *.gcov 6 | 7 | unittest 8 | coverage/ 9 | debug/ 10 | release/ 11 | profile/ 12 | report/ 13 | makedependency/ 14 | vera/ 15 | makefile_tmp 16 | Makefile.extra 17 | Makefile.config 18 | localConfigSummary.h 19 | 20 | aclocal.m4 21 | autom4te.cache/ 22 | config.log 23 | config.status 24 | libtool 25 | stamp-h[0-9] 26 | confdefs.h 27 | config.h 28 | 29 | build 30 | -------------------------------------------------------------------------------- /docSource/source/group/api.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | children: 5 | - name: JSON 6 | value: apiJSON.md 7 | - name: YAML 8 | value: apiYAML.md 9 | - name: Binary 10 | value: apiBinary.md 11 | - name: Macros 12 | value: apiMacros.md 13 | - name: Exporter 14 | value: apiExporter.md 15 | - name: Importer 16 | value: apiImporter.md 17 | --- 18 | -------------------------------------------------------------------------------- /docSource/source/group/implTraitsValue.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | template<> 7 | class Traits 8 | { 9 | public: 10 | static constexpr TraitType type = TraitType::Value; 11 | }; 12 | ```` 13 | This is used for all the fundamental types. These types use the `ParserInterface` and `PrinterInterface` to serialize/de-serialize. You should only use this value if your value can be parsed via: `ParserInterface::getValue()` and printed via `PrinterInterface::addValue()`. 14 | -------------------------------------------------------------------------------- /docSource/source/group/apiExporter.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: ThorsAnvil::Serialize 5 | headers: 6 | base: ThorSerialize/Exporter.h 7 | files: 8 | - name: 9 | functions: 10 | - return: std::ostream& 11 | name: operator<< 12 | param: [ std::ostream& stream, Exporter const& data ] 13 | showParam: true 14 | notes: This was copied from package/ThorSerialize.md and made to look nice 15 | thus it must be manially maintained. 16 | --- 17 | -------------------------------------------------------------------------------- /docSource/source/group/apiImporter.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: ThorsAnvil::Serialize 5 | headers: 6 | base: ThorSerialize/Importer.h 7 | files: 8 | - name: 9 | functions: 10 | - return: std::istream& 11 | name: operator>> 12 | param: [ std::istream& stream, Importer const& data ] 13 | showParam: true 14 | notes: This was copied from package/ThorSerialize.md and made to look nice 15 | thus it must be manially maintained. 16 | --- 17 | -------------------------------------------------------------------------------- /docSource/source/group/usageDeclarations.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | children: 5 | - name: Standard Types 6 | value: usageDeclarationsStandardTypes.md 7 | - name: Standard Containers 8 | value: usageDeclarationsStandardContainers.md 9 | - name: Enum 10 | value: usageDeclarationsEnum.md 11 | - name: Structure 12 | value: usageDeclarationsStructure.md 13 | - name: Pointers 14 | value: usageDeclarationsPointers.md 15 | - name: Value 16 | value: usageDeclarationsValue.md 17 | --- 18 | -------------------------------------------------------------------------------- /docSource/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "ThorsSerialize", 3 | "title": "ThorsSerialize", 4 | "description": "Modern C++ declaritive Serialization Library", 5 | "theme": "documentation", 6 | "themeGit": "git@github.com:Loki-Astari/andvari-theme-documentation.git", 7 | "toc": [ 8 | {"name": "Introduction", "value": "intro.md"}, 9 | {"name": "API", "value": "api.md"}, 10 | {"name": "Usage", "value": "usage.md"}, 11 | {"name": "Implementation", "value": "impl.md"}, 12 | {"name": "APi Generated", "value": "ThorSerialize-api.md"} 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /docSource/source/group/usageSerializingStrictness.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | std::cin << jsonImport(dst) << "\n"; 7 | ... 8 | using ParseType = ThorsAnvil::Serialize::ParserInterface::ParseType; 9 | std::cin >> jsonImport(dst, ParseType::Strict); 10 | ```` 11 | By default the parser is forgiving; extra or missing fields are simply ignored. If you want to use **Strict** parsing then you specify this as part of the `jsonImport()`. In this mode all fields are required no additional fields are allowed. If either of these constraints are broken then an exception is thrown. 12 | -------------------------------------------------------------------------------- /docSource/source/group/implTraitsSerialize.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | template<> 7 | class Traits 8 | { 9 | public: 10 | static constexpr TraitType type = TraitType::Serialize; 11 | }; 12 | ```` 13 | In this case ThorsSerializer expects the object to serialize itself via `operator<<` and `operator>>`. The resulting value should be a simple JSON value (Bool/Integer/Float/String). 14 | 15 | ````C++ 16 | ThorsAnvil_MakeTraitCustom(); 17 | ```` 18 | The easy way to generate the `Traits<>` specialization for a Serialize type is via the macro `ThorsAnvil_MakeTraitCustom()`. 19 | -------------------------------------------------------------------------------- /Makefile.config.in: -------------------------------------------------------------------------------- 1 | 2 | THOR_CONAN_ENABLE=@THOR_CONAN_ENABLE@ 3 | 4 | MagicEnumHeaderOnly_ROOT_DIR=@MagicEnumHeaderOnly_ROOT_DIR@ 5 | 6 | snappy_ROOT_DIR=@snappy_ROOT_DIR@ 7 | snappy_ROOT_LIB=@snappy_ROOT_LIB@ 8 | 9 | yaml_ROOT_DIR=@yaml_ROOT_DIR@ 10 | yaml_ROOT_LIB=@yaml_ROOT_LIB@ 11 | 12 | crypto_ROOT_DIR=@crypto_ROOT_DIR@ 13 | crypto_ROOT_LIB=@crypto_ROOT_LIB@ 14 | 15 | ZLIB_ROOT_DIR=@ZLIB_ROOT_DIR@ 16 | ZLIB_ROOT_LIB=@ZLIB_ROOT_LIB@ 17 | 18 | ThorSerialize_ROOT_LIB=@ThorSerialize_ROOT_LIB@ 19 | ThorSerialize_ROOT_DIR=@ThorSerialize_ROOT_DIR@ 20 | ThorSerializeHeaderOnly_ROOT_DIR= 21 | 22 | event_ROOT_DIR=@event_ROOT_DIR@ 23 | event_ROOT_LIB=@event_ROOT_LIB@ 24 | -------------------------------------------------------------------------------- /docSource/source/group/apiJSON.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: ThorsAnvil::Serialize 5 | headers: 6 | base: ThorSerialize/JsonThor.h 7 | files: 8 | - name: 9 | functions: 10 | - return: Exporter 11 | name: jsonExport 12 | param: [ T const& value ] 13 | showParam: true 14 | - return: Importer 15 | name: jsonImport 16 | param: [ T& value ] 17 | showParam: true 18 | notes: This was copied from package/ThorSerialize.md and made to look nice 19 | thus it must be manially maintained. 20 | --- 21 | -------------------------------------------------------------------------------- /docSource/source/group/apiYAML.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: ThorsAnvil::Serialize 5 | headers: 6 | base: ThorSerialize/YamlThor.h 7 | files: 8 | - name: 9 | functions: 10 | - return: Exporter 11 | name: yamlExport 12 | param: [ T const& value ] 13 | showParam: true 14 | - return: Importer 15 | name: yamlImport 16 | param: [ T& value ] 17 | showParam: true 18 | notes: This was copied from package/ThorSerialize.md and made to look nice 19 | thus it must be manially maintained. 20 | --- 21 | -------------------------------------------------------------------------------- /docSource/source/group/apiBinary.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: ThorsAnvil::Serialize 5 | headers: 6 | base: ThorSerialize/BinaryThor.h 7 | files: 8 | - name: 9 | functions: 10 | - return: Exporter 11 | name: binaryExport 12 | param: [ T const& value ] 13 | showParam: true 14 | - return: Importer 15 | name: binaryImport 16 | param: [ T& value ] 17 | showParam: true 18 | notes: This was copied from package/ThorSerialize.md and made to look nice 19 | thus it must be manially maintained. 20 | --- 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /docs/posts/2018-03-14-Test-Article.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Article 5 | 6 | 7 | 8 |

A Blog Role Item

9 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

10 | 11 | 12 | -------------------------------------------------------------------------------- /docSource/source/function/ThorSerialize.BinaryThor.binExport.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: function 3 | generate: false 4 | typeInfo: 5 | namespace: ThorsAnvil::Serialize 6 | header: ThorSerialize/BinaryThor.h 7 | function: binExport 8 | description: 9 | template: template 10 | return: 11 | type: 'Exporter, T>' 12 | description: 'Object that can be passed to operator<< for serialization.' 13 | parameters: 14 | - name: value 15 | type: 'T const&' 16 | default: 17 | description: 'The object to be serialized.' 18 | - name: catchExceptions 19 | type: 'bool' 20 | default: false 21 | description: 22 | children: [] 23 | --- 24 | -------------------------------------------------------------------------------- /docSource/source/function/ThorSerialize.BinaryThor.binImport.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: function 3 | generate: false 4 | typeInfo: 5 | namespace: ThorsAnvil::Serialize 6 | header: ThorSerialize/BinaryThor.h 7 | function: binImport 8 | description: 9 | template: template 10 | return: 11 | type: 'Importer, T>' 12 | description: 'Object that can be passed to operator>> for de-serialization.' 13 | parameters: 14 | - name: value 15 | type: 'T&' 16 | default: 17 | description: 'The object to be de-serialized.' 18 | - name: catchExceptions 19 | type: 'bool' 20 | default: false 21 | description: 22 | children: [] 23 | --- 24 | -------------------------------------------------------------------------------- /docSource/source/posts/2018-03-14-Test-Article.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Article 5 | 6 | 7 | 8 |

A Blog Role Item

9 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

10 | 11 | 12 | -------------------------------------------------------------------------------- /doc/exampleE.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ThorSerialize/JsonThor.h" 4 | 5 | enum class EnumType : int { 6 | A, B, C 7 | }; 8 | 9 | struct MyStruct { 10 | EnumType e; 11 | std::string s; 12 | }; 13 | 14 | // ThorsAnvil_MakeEnum is still supported for backwards compatibility. 15 | // But this functionality has been replaces by magic_enum 16 | // Please see: https://github.com/Neargye/magic_enum 17 | 18 | ThorsAnvil_MakeEnum(EnumType, A, B, C); 19 | ThorsAnvil_MakeTrait(MyStruct, e, s); 20 | 21 | int main() 22 | { 23 | using ThorsAnvil::Serialize::jsonImporter; 24 | using ThorsAnvil::Serialize::jsonExporter; 25 | 26 | MyStruct val; 27 | std::cin >> jsonImporter(val); 28 | std::cout << jsonExporter(val) << "\n"; 29 | } 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | THORSANVIL_ROOT = $(realpath ./) 3 | 4 | TARGET = src 5 | 6 | include $(THORSANVIL_ROOT)/build/tools/Project.Makefile 7 | 8 | all: apps_$(PLATFORM)_all 9 | install: apps_$(PLATFORM)_install 10 | 11 | .PHONY: apps_Linux_all apps_Darwin_all apps_MSYS_NT_all apps_MINGW64_NT_all 12 | apps_Linux_all: apps_all 13 | apps_Darwin_all: apps_all 14 | apps_MSYS_NT_all: 15 | apps_MINGW64_NT_all: 16 | 17 | .PHONY: apps_Linux_install apps_Darwin_install apps_MSYS_NT_install apps_MINGW64_NT_install 18 | apps_Linux_install: apps_install 19 | apps_Darwin_install: apps_install 20 | apps_MSYS_NT_install: 21 | apps_MINGW64_NT_install: 22 | 23 | .PHONY: apps_all apps_install 24 | apps_all: 25 | $(MAKE) -C apps all 26 | apps_install: 27 | $(MAKE) -C apps install 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /doc/example0.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-0 [See doc/example0.cpp](example0.cpp) 4 | ```C++ 5 | #include 6 | #include 7 | #include "ThorSerialize/JsonThor.h" 8 | 9 | int main() 10 | { 11 | std::vector data; 12 | using ThorsAnvil::Serialize::jsonImporter; 13 | using ThorsAnvil::Serialize::jsonExporter; 14 | 15 | std::cin >> jsonImporter(data); 16 | std::cout << jsonExporter(data) << "\n"; 17 | } 18 | ``` 19 | 20 | ### Build and run 21 | ```bash 22 | > g++ -std=c++20 example0.cpp -lThorSerialize -lThorsLogging 23 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 24 | > echo "[1,2,3,4,5]" | ./a.out 25 | [ 1, 2, 3, 4, 5] 26 | > 27 | ``` 28 | -------------------------------------------------------------------------------- /docSource/source/group/usageSerializingFormat.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | std::cout << jsonExport(mark) << "\n"; 7 | ... 8 | { 9 | "name": "mark", 10 | "score": 10, 11 | "damage": 5, 12 | "team": 13 | { 14 | "red": 66, 15 | "green": 42, 16 | "blue": 23 17 | } 18 | } 19 | ... 20 | using OutputType = ThorsAnvil::Serialize::PrinterInterface::OutputType; 21 | std::cout << jsonExport(mark, OutputType::Stream) << "\n"; 22 | ... 23 | {"name":"mark","score":10,"damage":5,"team":{"red":66,"green":42,"blue":23}} 24 | ```` 25 | By default the generated JSON is verbose and easy for humans to read. This also makes it longer than required. You can compact the output by `OutputType::Stream` in the `jsonFormat()`. 26 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 2 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 3 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 5 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 6 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 7 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 8 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 9 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 10 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | 12 | 13 | This software is provided under the MIT License see the file "LICENSE" 14 | 15 | 16 | -------------------------------------------------------------------------------- /docSource/source/group/usageSerializingExceptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | using OutputType = ThorsAnvil::Serialize::PrinterInterface::OutputType; 7 | while(std::cout << jsonExport(12, OutputType::Default, true) << "\n") 8 | { 9 | // Successfully wrote an object to the output 10 | } 11 | ... 12 | using ParseType = ThorsAnvil::Serialize::ParserInterface::ParseType; 13 | while(std::cin >> jsonImport(dst, ParseType::Weak, true)) 14 | { 15 | // Successfully read an object from the input 16 | } 17 | ```` 18 | By default the ThorsSerializer will throw an exception when it encounters a parsing error (it also sets the stream state to fail). If you would prefer for the stream to swallow the exception (but still set the stream state to fail) then you can modify this behavior in `jsonImport()` and `jsonExport()`. 19 | -------------------------------------------------------------------------------- /doc/objective.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ### Objective: 4 | The objective is to make serialization/de-serialization of C++ object to/from 5 | JSON/YAML/Bson trivial. 6 | 7 | This means: 8 | 1) does not build a JSON/YAML/BSON object. Reads data directly into C++ object. 9 | 2) In normal usage there should be NO need to write any code. 10 | 3) User should not need to understand JSON/YAML/BSON or validate its input. 11 | 4) Should work seamlessly with streams. 12 | 5) Standard containers should automatically work 13 | 14 | I am not concerned about speed. 15 | Though my trivial test work just fine in terms of speed. 16 | 17 | The design was done with the primary goal of communicating with WEB-Servers 18 | that speak JSON. The main envisioned usage was for mobile devices were many 19 | small JSON objects are transfered in both directions. 20 | -------------------------------------------------------------------------------- /docSource/source/group/usageDeclarationsValue.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | #include "ThorSerialize/JsonThor.h" 7 | #include "ThorSerialize/Traits.h" 8 | 9 | using ThorsAnvil::Serialize::jsonExport; 10 | using ThorsAnvil::Serialize::jsonImport; 11 | 12 | struct ID 13 | { 14 | int id; 15 | friend std::ostream& operator<<(std::ostream& s, ID const& data) {return s << data.id;} 16 | friend std::istream& operator>>(std::istream& s, ID& data) {return s >> data.id;} 17 | }; 18 | ThorsAnvil_MakeTraitCustom(ID); 19 | 20 | int main() 21 | { 22 | ID id{23}; 23 | std::cout << jsonExport(id) << "\n"; 24 | } 25 | ... 26 | 23 27 | ```` 28 | In situations where your class already has appropriate input and output operators (that generate JSON like values (Bool,Integer/Float/String) then you can simply declare your type as serializeable using the macro `ThorsAnvil_MakeTraitCustom()`. 29 | -------------------------------------------------------------------------------- /docSource/source/function/ThorSerialize.JsonThor.jsonExport.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: function 3 | generate: false 4 | typeInfo: 5 | namespace: ThorsAnvil::Serialize 6 | header: ThorSerialize/JsonThor.h 7 | function: jsonExport 8 | description: 9 | template: template 10 | return: 11 | type: 'Exporter' 12 | description: 'Object that can be passed to operator<< for serialization.' 13 | parameters: 14 | - name: value 15 | type: 'T const&' 16 | default: 17 | description: 'The object to be serialized.' 18 | - name: characteristics 19 | type: 'PrinterInterface::OutputType' 20 | default: PrinterInterface::OutputType::Default 21 | description: 'Default: is verbose and logical. Stream: remove all white space.' 22 | - name: catchExceptions 23 | type: 'bool' 24 | default: false 25 | description: 26 | children: [] 27 | --- 28 | -------------------------------------------------------------------------------- /docSource/source/function/ThorSerialize.YamlThor.yamlExport.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: function 3 | generate: false 4 | typeInfo: 5 | namespace: ThorsAnvil::Serialize 6 | header: ThorSerialize/YamlThor.h 7 | function: yamlExport 8 | description: 9 | template: template 10 | return: 11 | type: 'Exporter' 12 | description: 'Object that can be passed to operator<< for serialization.' 13 | parameters: 14 | - name: value 15 | type: 'T const&' 16 | default: 17 | description: 'The object to be serialized.' 18 | - name: characteristics 19 | type: 'PrinterInterface::OutputType' 20 | default: PrinterInterface::OutputType::Default 21 | description: 'Default: is verbose and logical. Stream: remove all white space.' 22 | - name: catchExceptions 23 | type: 'bool' 24 | default: false 25 | description: 26 | children: [] 27 | --- 28 | -------------------------------------------------------------------------------- /docSource/source/group/implTraitsEnum.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | template<> 7 | class Traits 8 | { 9 | public: 10 | static constexpr TraitType type = TraitType::Enum; 11 | 12 | static char const* const* getValues(); 13 | static Enum_Type getValue(std::string const& val, std::string const& msg); 14 | }; 15 | ```` 16 | In this case ThorsSerializer expects the `Traits` class to have two extra static methods: `getValues()` and `getValue()`. 17 | 18 | * `getValues()` 19 | Is used for serializing the value by providing an array of `char const*` that represent the text version of the enum value. 20 | * `getValue()` 21 | Is used for deserializing a specific string into a specifc enum value. 22 | 23 | ````C++ 24 | ThorsAnvil_MakeEnum(, ...) 25 | ```` 26 | The easy way to generate the `Traits<>` specialization for an enum with these fields is via the macro `ThorsAnvil_MakeEnum()`. 27 | -------------------------------------------------------------------------------- /docSource/source/function/ThorSerialize.JsonThor.jsonImport.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: function 3 | generate: false 4 | typeInfo: 5 | namespace: ThorsAnvil::Serialize 6 | header: ThorSerialize/JsonThor.h 7 | function: jsonImport 8 | description: 9 | template: template 10 | return: 11 | type: 'Importer' 12 | description: 'Object that can be passed to operator>> for de-serialization.' 13 | parameters: 14 | - name: value 15 | type: 'T&' 16 | default: 17 | description: 'The object to be de-serialized.' 18 | - name: parseStrictness 19 | type: 'ParserInterface::ParseType' 20 | default: ParserInterface::ParseType::Weak 21 | description: 'Weak: ignore missing extra fields. Strict: Any missing or extra fields throws exception.' 22 | - name: catchExceptions 23 | type: 'bool' 24 | default: false 25 | description: 26 | children: [] 27 | --- 28 | -------------------------------------------------------------------------------- /docSource/source/function/ThorSerialize.YamlThor.yamlImport.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: function 3 | generate: false 4 | typeInfo: 5 | namespace: ThorsAnvil::Serialize 6 | header: ThorSerialize/YamlThor.h 7 | function: yamlImport 8 | description: 9 | template: template 10 | return: 11 | type: 'Importer' 12 | description: 'Object that can be passed to operator>> for de-serialization.' 13 | parameters: 14 | - name: value 15 | type: 'T&' 16 | default: 17 | description: 'The object to be de-serialized.' 18 | - name: parseStrictness 19 | type: 'ParserInterface::ParseType' 20 | default: ParserInterface::ParseType::Weak 21 | description: 'Weak: ignore missing extra fields. Strict: Any missing or extra fields throws exception.' 22 | - name: catchExceptions 23 | type: 'bool' 24 | default: false 25 | description: 26 | children: [] 27 | --- 28 | -------------------------------------------------------------------------------- /docSource/source/group/usageDeclarationsStandardContainers.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | #include "ThorSerialize/JsonThor.h" 7 | #include "ThorSerialize/SerUtil.h" 8 | 9 | using ThorsAnvil::Serialize::jsonExport; 10 | using ThorsAnvil::Serialize::jsonImport; 11 | 12 | int main() 13 | { 14 | std::vector data = {1,2,3,4,5,6,7}; 15 | std::cout << jsonExport(data) << "\n"; 16 | } 17 | ... 18 | [ 1, 2, 3, 4, 5, 6, 7] 19 | ```` 20 | The standard library container types are all supported. You simply need to include `#include "ThorSerialize/SerUtil.h"`. 21 | 22 | * `std::array` 23 | * `std::list` 24 | * `std::vector` 25 | * `std::deque` 26 | * `std::pair` 27 | * `std::set` 28 | * `std::multiset` 29 | * `std::map` 30 | * `std::multimap` 31 | * `std::tuple` 32 | * `std::unordered_set` 33 | * `std::unordered_multiset` 34 | * `std::unordered_map` 35 | * `std::unordered_multimap` 36 | * `std::initializer_list` 37 | * `std::unique_ptr` 38 | -------------------------------------------------------------------------------- /docSource/source/group/usageDeclarationsEnum.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | #include "ThorSerialize/JsonThor.h" 7 | #include "ThorSerialize/Traits.h" 8 | 9 | using ThorsAnvil::Serialize::jsonExport; 10 | using ThorsAnvil::Serialize::jsonImport; 11 | 12 | enum Color { red, green, blue }; 13 | ThorsAnvil_MakeEnum(Color, red, green, blue); 14 | 15 | int main() 16 | { 17 | Color c = red; 18 | std::cout << jsonExport(c) << "\n"; 19 | } 20 | ... 21 | "red" 22 | ```` 23 | In C++ enums are serialized as integer types. This can work but you loose meaning in this translation. It also binds you contractually to never changing the order of any enum items in the type. 24 | 25 | The ThorsSerializer library provides you a mechanism to stream the type as a string. This maintains its symantic meaning while in the JSON format and when de-serialized is converted back to the correct enum value automatically. 26 | 27 | For each enum type that you want to serialize simply use `ThorsAnvil_MakeEnum()` macros to declare the enum and all valid streamable values in the enum range. You simply need to include #include "ThorSerialize/Traits.h". 28 | -------------------------------------------------------------------------------- /docSource/source/group/implTraitsPointer.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | template 7 | class Traits 8 | { 9 | public: 10 | static constexpr TraitType type = TraitType::Pointer; 11 | static T* alloc(); 12 | static void release(T* p); 13 | }; 14 | ```` 15 | 16 | In this case ThorsSerializer expects the `Traits` class to have two extra static methods: `alloc()` and `release()`. 17 | 18 | * `alloc()` 19 | Is used to allocate an object of type T 20 | * `release()` 21 | Is used to release an onbject of type T that was allocated via the `alloc()` function. 22 | 23 | If you simply want to use `new` and `delete` then the default partial specialization of thie object works out of the box with no extra configuration needed. 24 | 25 | ##### ThorsAnvil_PointerAllocator 26 | ````C++ 27 | strict MyDataMemoryPool 28 | { 29 | MyData* alloc(); 30 | void release(MyData*); 31 | }; 32 | ThorsAnvil_PointerAllocator(MyData, MyDataMemoryPool); 33 | ```` 34 | The easy way to generate the `Traits<>` specialization for a pointer that has its own allocators is via the macro `ThorsAnvil_PointerAllocator()`. 35 | -------------------------------------------------------------------------------- /docSource/source/group/usageDeclarationsStandardTypes.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | #include "ThorSerialize/JsonThor.h" 7 | 8 | using ThorsAnvil::Serialize::jsonExport; 9 | using ThorsAnvil::Serialize::jsonImport; 10 | 11 | int main() 12 | { 13 | int v1 = 12; // All the different types of int are supported) 14 | double v2 = 13.5; // float/double/long double all supported 15 | bool v3 = true; 16 | std::string v4 = "A string"; 17 | 18 | std::cout << jsonExport(v1) << " " 19 | << jsonExport(v2) << " " 20 | << jsonExport(v3) << " " 21 | << jsonExport(v4) << "\n"; 22 | } 23 | ... 24 | 12 13.5 true "A string" 25 | ```` 26 | The built-in types `integer/float/bool/std::string` are serialalable out of the box. You may notice a couple of notable exceptions `char` and `char*`. The `char` type is not supported as it is very easily confused with an integer and `char*` is not supported because I did not want to encourage C-Strings when `std::string` is available (sorry). 27 | 28 | Note: I know this is not very useful by itself. Bare with me it becomes useful when you start composing types. 29 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docSource/themes/documentation"] 2 | path = docSource/themes/documentation 3 | url = ../../Loki-Astari/andvari-theme-documentation.git 4 | [submodule ".build"] 5 | path = build 6 | url = ../../Loki-Astari/ThorMaker.git 7 | [submodule "third/ThorsStorage"] 8 | path = third/ThorsStorage 9 | url = ../../Loki-Astari/ThorsStorage.git 10 | [submodule "third/ThorsCrypto"] 11 | path = third/ThorsCrypto 12 | url = ../../Loki-Astari/ThorsCrypto.git 13 | [submodule "third/ThorsSocket"] 14 | path = third/ThorsSocket 15 | url = ../../Loki-Astari/ThorsSocket.git 16 | [submodule "third/ThorsLogging"] 17 | path = third/ThorsLogging 18 | url = ../../Loki-Astari/ThorsLogging.git 19 | [submodule "third/ThorsIOUtil"] 20 | path = third/ThorsIOUtil 21 | url = ../../Loki-Astari/ThorsIOUtil.git 22 | [submodule "third/ThorsSerializer"] 23 | path = third/ThorsSerializer 24 | url = ../../Loki-Astari/ThorsSerializer 25 | [submodule "third/Nisse"] 26 | path = third/Nisse 27 | url = ../../Loki-Astari/Nisse.git 28 | [submodule "third/Mug"] 29 | path = third/Mug 30 | url = ../../Loki-Astari/Mug.git 31 | [submodule "third/ThorsMongo"] 32 | path = third/ThorsMongo 33 | url = ../../Loki-Astari/ThorsMongo.git 34 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([ThorsSerialize], [0.1], [Loki.Astari+ThorsAnvil@gmail.com]) 2 | AC_PREREQ([2.65]) 3 | 4 | AC_CONFIG_MACRO_DIR([build/autotools/m4]) 5 | AC_CONFIG_AUX_DIR([build/autotools/build]) 6 | 7 | AX_THOR_FUNC_INIT_BUILD([ThorsSerializer], [], [20]) 8 | 9 | AX_THOR_ENABLE_CONAN 10 | 11 | AX_THOR_CHECK_USE_THORS_SERIALIZE([ThorsLogging]) 12 | AX_THOR_CHECK_USE_MAGIC_ENUM 13 | AX_THOR_CHECK_USE_YAML 14 | AX_THOR_CHECK_USE_SNAPPY 15 | AX_THOR_CHECK_USE_CRYPTO 16 | AX_THOR_CHECK_USE_ZLIB 17 | AX_THOR_CHECK_USE_EVENT 18 | 19 | AX_THOR_DISABLE_TEST_REQUIREING_LOCK_FILES 20 | AX_THOR_DISABLE_TEST_REQUIREING_MONGO_QUERY 21 | AX_THOR_SERVICE_AVAILABLE_MONGO 22 | AX_THOR_CHECK_IS_SLACK_TESTABLE 23 | AX_THOR_CHECK_USE_BOOST([1.70], [], [ 24 | AC_MSG_ERROR([ 25 | Nisse requires boost CoRoutine2 26 | The minimum version we support is via boost 1.70 please upgrade your boost libraries to this (or later). 27 | ]) 28 | ]) 29 | 30 | LT_INIT 31 | 32 | subconfigure="${subconfigure} --with-thorserialize-root=$(pwd)/build --with-nisse-root=$(pwd)/build --disable-slacktest" 33 | 34 | AX_THOR_FEATURE_HEADER_ONLY_VARIANT([THORS_SERIALIZER]) 35 | AX_THOR_FUNC_TERM_BUILD([SERIALIZER], [localConfigSummary.h:config.h.in]) 36 | 37 | AC_OUTPUT 38 | -------------------------------------------------------------------------------- /doc/example8.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ThorSerialize/Traits.h" 3 | #include "ThorSerialize/JsonThor.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class Identifier 10 | { 11 | public: 12 | std::string name; 13 | std::string bar; 14 | std::string foo; 15 | }; 16 | class Properties 17 | { 18 | public: 19 | std::string category; 20 | std::string time; 21 | std::string shouldRetry; 22 | std::string Id; 23 | }; 24 | class Data 25 | { 26 | public: 27 | std::string operation; 28 | Identifier identifier; 29 | Properties properties; 30 | }; 31 | 32 | ThorsAnvil_MakeTrait(Identifier, name, bar, foo); 33 | ThorsAnvil_MakeTrait(Properties, category, time, shouldRetry, Id); 34 | ThorsAnvil_MakeTrait(Data, operation, identifier, properties); 35 | 36 | int main() 37 | { 38 | using ThorsAnvil::Serialize::jsonImporter; 39 | using ThorsAnvil::Serialize::jsonExporter; 40 | 41 | std::vector objects; 42 | 43 | std::ifstream file("file.json"); 44 | 45 | if (file >> jsonImporter(objects)) { 46 | std::cout << "Read Worked\n"; 47 | 48 | std::cout << jsonExporter(objects); 49 | } 50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /docSource/source/group/usageSerializing.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | children: 5 | - name: Format 6 | value: usageSerializingFormat.md 7 | - name: Strictness 8 | value: usageSerializingStrictness.md 9 | - name: Exceptions 10 | value: usageSerializingExceptions.md 11 | --- 12 | There are two serialization formats supported out o the box (JSON/YAML) and an experimental binary format (I would love if somebody added the google Protocol Buffers). 13 | 14 | ````C++ 15 | #include "ThorSerialize/JsonThor.h" 16 | 17 | using ThorsAnvil::Serialize::jsonExport; 18 | using ThorsAnvil::Serialize::jsonImport; 19 | 20 | int main() 21 | { 22 | std::cout << jsonExport(12) << "\n"; 23 | 24 | int value; 25 | std::cin >> jsonImport(value); 26 | } 27 | ```` 28 | Each format has two commands `Import()` and `Export()`. e.g. `jsonExport(12)`. 29 | 30 | These functions return a very lightweight object (it simply contains a reference to the object being serialized) that can be passed to the standard stream operators. Thats at it for a the user of serialization library. 31 | 32 | To include all the functionality all you need to do is include `#include "ThorSerialize/Thor.h"` and link against `libThorSerialize.so`. 33 | -------------------------------------------------------------------------------- /doc/exampleE.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-E [See doc/exampleE.cpp](exampleE.cpp) 4 | ```C++ 5 | #include 6 | #include 7 | #include "ThorSerialize/JsonThor.h" 8 | 9 | enum class EnumType : int { 10 | A, B, C 11 | }; 12 | 13 | struct MyStruct { 14 | EnumType e; 15 | std::string s; 16 | }; 17 | 18 | // ThorsAnvil_MakeEnum is still supported for backwards compatibility. 19 | // But this functionality has been replaces by magic_enum 20 | // Please see: https://github.com/Neargye/magic_enum 21 | 22 | ThorsAnvil_MakeEnum(EnumType, A, B, C); 23 | ThorsAnvil_MakeTrait(MyStruct, e, s); 24 | 25 | int main() 26 | { 27 | using ThorsAnvil::Serialize::jsonImporter; 28 | using ThorsAnvil::Serialize::jsonExporter; 29 | 30 | MyStruct val; 31 | std::cin >> jsonImporter(val); 32 | std::cout << jsonExporter(val) << "\n"; 33 | } 34 | ``` 35 | 36 | ### Build and run 37 | ```bash 38 | > g++ -std=c++20 example0.cpp -lThorSerialize -lThorsLogging 39 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 40 | > echo '{"e": "A", "s": "This string"}' | ./a.out 41 | { 42 | "e": "A", 43 | "s": "This string" 44 | } 45 | 46 | ``` 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | > A minimal compilable example of that features the bug. 12 | 13 | #### main.cpp 14 | int main() 15 | { 16 | // Action to reproduce bug. 17 | } 18 | 19 | > A description of how to build and run the code 20 | 21 | g++ -std=c++14 -I/usr/local/include -L/usr/local/lib -lThorSerialize17 main.cpp 22 | cat stuff | ./a.out 23 | 24 | **Expected behavior** 25 | > A clear and concise description of what you expected to happen. 26 | 27 | **Environment:** 28 | - OS: 29 | > uname -a 30 | Darwin Host.local 18.5.0 Darwin Kernel Version 18.5.0: Mon Mar 11 20:40:32 PDT 2019; root:xnu-4903.251.3~3/RELEASE_X86_64 x86_64 31 | 32 | - Compiler and Version 33 | > g++ --version 34 | Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1 35 | Apple LLVM version 10.0.1 (clang-1001.0.46.3) 36 | Target: x86_64-apple-darwin18.5.0 37 | Thread model: posix 38 | InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin 39 | 40 | **Additional context** 41 | > Add any other context about the problem here. 42 | -------------------------------------------------------------------------------- /docSource/source/group/implTraits.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | children: 5 | - name: Traits Value 6 | value: implTraitsValue.md 7 | - name: Traits Enum 8 | value: implTraitsEnum.md 9 | - name: Traits Serialize 10 | value: implTraitsSerialize.md 11 | - name: Traits Pointer 12 | value: implTraitsPointer.md 13 | - name: Traits Map 14 | value: implTraitsMap.md 15 | - name: Traits Array 16 | value: implTraitsArray.md 17 | --- 18 | ````C++ 19 | namespace ThorsAnvil 20 | { 21 | namespace Serialize 22 | { 23 | 24 | template 25 | class Traits 26 | { 27 | public: 28 | static constexpr TraitType type = TraitType::Invalid; 29 | }; 30 | 31 | } 32 | } 33 | ```` 34 | The serialization processes is built around around a traits class `Traits` that is specialized for each type. This is similar in technique to the `std::iterator_traits<>` used by the standard library. 35 | 36 | The generic (and thus default) `Traits` has a single member `type` that has the value `TraitType::Invalid`. 37 | 38 | The `type` member of the `Traits<>` specialization indicates how the member will be serialized/de-serialized and defines what other members of the `Traits<>` class are needed for that speialization. 39 | 40 | The following values are allowed: `{Invalid, Parent, Value, Map, Array, Enum, Pointer, Serialize}` 41 | -------------------------------------------------------------------------------- /doc/example4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ThorSerialize/Traits.h" 6 | #include "ThorSerialize/JsonThor.h" 7 | 8 | 9 | 10 | class Car 11 | { 12 | public: 13 | Car(std::string color, uint16_t speed, uint32_t price) : 14 | Color(color), 15 | Speed(speed), 16 | Price(price){}; 17 | 18 | std::string getColor(){return Color;}; 19 | uint16_t getSpeed(){return Speed;}; 20 | uint32_t getPrice(){return Price;}; 21 | private: 22 | // Note: Member names must match JSON names. 23 | friend class ThorsAnvil::Serialize::Traits; 24 | std::string Color; 25 | uint16_t Speed; 26 | uint32_t Price; 27 | }; 28 | struct AllCars 29 | { 30 | std::map myCars; 31 | }; 32 | 33 | 34 | ThorsAnvil_MakeTrait(Car, Color, Price, Speed); 35 | ThorsAnvil_MakeTrait(AllCars, myCars); 36 | 37 | int main() 38 | { 39 | std::map myGarage; 40 | myGarage.emplace("car1", Car{"red", 200, 10000}); 41 | myGarage.emplace("car2", Car{"blue", 666, 16000}); 42 | myGarage.emplace("car3", Car{"yellow", 50, 7500}); 43 | myGarage.emplace("car4", Car{"green", 10, 750}); 44 | 45 | std::ofstream outputJSONfile("pretty.json"); 46 | 47 | using ThorsAnvil::Serialize::jsonExporter; 48 | outputJSONfile << jsonExporter(myGarage); 49 | } 50 | -------------------------------------------------------------------------------- /doc/example6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ThorSerialize/Traits.h" 3 | #include "ThorSerialize/SerUtil.h" 4 | #include "ThorSerialize/JsonThor.h" 5 | 6 | /* A class that you want to serialize. */ 7 | class MyClass 8 | { 9 | std::string H; 10 | int N; 11 | int D1; 12 | int D2; 13 | friend struct ThorsAnvil::Serialize::Traits; 14 | 15 | public: 16 | MyClass(std::string const& h, int n, int d1, int d2) 17 | : H(h) 18 | , N(n) 19 | , D1(d1) 20 | , D2(d2) 21 | {} 22 | }; 23 | 24 | 25 | /* 26 | * Though there is no code involved, you do need to set up 27 | * this structure to tell the library what fields need to be serialized. 28 | * To do this use the macro: ThorsAnvil_MakeTrait() 29 | * Specifying your class, and a list of members to serialize. 30 | */ 31 | ThorsAnvil_MakeTrait(MyClass, H, N, D1, D2); 32 | 33 | int main() 34 | { 35 | using ThorsAnvil::Serialize::jsonExporter; 36 | using ThorsAnvil::Serialize::PrinterInterface; 37 | using namespace std::string_literals; 38 | 39 | MyClass data {"1"s, 3, 3, 150}; 40 | 41 | 42 | // This generates a simple JSON Object (wordy) 43 | std::cout << "Version 1\n"; 44 | std::cout << jsonExporter(data) << "\n\n\n"; 45 | 46 | // This generates a compact JSON 47 | std::cout << "Version 2 (Stream)\n"; 48 | std::cout << jsonExporter(data, PrinterInterface::OutputType::Stream) << "\n\n\n"; 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /docSource/source/group/implTraitsArray.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | template<> 7 | class Traits 8 | { 9 | public: 10 | static constexpr TraitType type = TraitType::Array; 11 | 12 | struct MemberExtractor 13 | { 14 | void operator()(PrinterInterface& printer, ArrayType const& object) const; 15 | void operator()(ParserInterface& parser, std::size_t index, ArrayType& object) const; 16 | }; 17 | static ExtractorType const& getMembers() 18 | }; 19 | ```` 20 | If the `Traits<>::type` is `TraitType::Array` then the `Traits<>` specialization is expected to have a static `getMembers()` method that returns an `MemberExtractor` object (see below for details). 21 | 22 | When serializing an object where the `Traits<>::type` is `TraitType::Array` the library will call `openArray()` on the `printerInterface` (generates a '[' in JSON) and conversely will call `closeArray()` (generates a ']' in JSON) after all the members have been serialized. Conversily when de-serializing into an object with these `Traits<>::type` the parser will expect an arrayOpen/arrayClose marker (in JSON '[' amd ']' respecively). 23 | 24 | The method using `PrinterInterface` is called once and is expected to serialize the object using this interface. The method using the `ParserInterface` is called for each new value that is available on the stream and is expected to de-serialize the value directly into the destination object. Note: each time it is called the index is passed. 25 | 26 | -------------------------------------------------------------------------------- /doc/example7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ThorSerialize/Traits.h" 6 | #include "ThorSerialize/JsonThor.h" 7 | 8 | struct Component 9 | { 10 | std::string type; 11 | std::vector axis; 12 | }; 13 | struct Data 14 | { 15 | std::vector components; 16 | }; 17 | 18 | // Declare the traits. 19 | // Specifying what members need to be serialized. 20 | ThorsAnvil_MakeTrait(Component, type, axis); 21 | ThorsAnvil_MakeTrait(Data, components); 22 | 23 | int main() 24 | { 25 | using ThorsAnvil::Serialize::jsonImporter; 26 | using ThorsAnvil::Serialize::jsonExporter; 27 | 28 | Data data1; 29 | Data data2; 30 | // See: https://github.com/Loki-Astari/ThorsSerializer/blob/master/doc/example7.json 31 | std::ifstream file("example7.json"); 32 | 33 | if (file >> jsonImporter(data1)) { 34 | std::cout << "Object Read OK\n"; 35 | std::cout << jsonExporter(data1) << "\n"; 36 | } 37 | else { 38 | std::cout << "Object Read FAIL\n"; 39 | } 40 | 41 | 42 | if (file >> jsonImporter(data2)) { 43 | std::cout << "Object Read OK\n"; 44 | std::cout << jsonExporter(data2) << "\n"; 45 | } 46 | else { 47 | std::cout << "Object Read FAIL\n"; 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /doc/example1.cpp: -------------------------------------------------------------------------------- 1 | #include "ThorSerialize/Traits.h" 2 | #include "ThorSerialize/JsonThor.h" 3 | 4 | namespace X 5 | { 6 | struct Shirt 7 | { 8 | int red; 9 | int green; 10 | int blue; 11 | }; 12 | class TeamMember 13 | { 14 | std::string name; 15 | int score; 16 | int damage; 17 | Shirt team; 18 | public: 19 | TeamMember(std::string const& name, int score, int damage, Shirt const& team) 20 | : name(name) 21 | , score(score) 22 | , damage(damage) 23 | , team(team) 24 | {} 25 | // Define the trait as a friend to get accesses to private 26 | // Members. 27 | friend class ThorsAnvil::Serialize::Traits; 28 | }; 29 | } 30 | 31 | // Declare the traits. 32 | // Specifying what members need to be serialized. 33 | ThorsAnvil_MakeTrait(X::Shirt, red, green, blue); 34 | ThorsAnvil_MakeTrait(X::TeamMember, name, score, damage, team); 35 | 36 | int main() 37 | { 38 | using ThorsAnvil::Serialize::jsonImporter; 39 | using ThorsAnvil::Serialize::jsonExporter; 40 | 41 | X::TeamMember mark("mark", 10, 5, X::Shirt{255,0,0}); 42 | // Use the export function to serialize 43 | std::cout << jsonExporter(mark) << "\n"; 44 | 45 | X::TeamMember john("Empty", 0, 0, X::Shirt{0,0,0}); 46 | std::stringstream input(R"({"name": "John","score": 13,"team":{"red": 0,"green": 0,"blue": 255, "black":25}})"); 47 | input >> jsonImporter(john); 48 | std::cout << jsonExporter(john) << "\n"; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /docSource/source/group/apiMacros.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: 5 | headers: 6 | base: ThorSerialize/Traits.h 7 | files: 8 | - name: 9 | functions: 10 | - name: ThorsAnvil_MakeEnum 11 | param: [ EnumType, EnumValues... ] 12 | showParam: true 13 | - name: ThorsAnvil_MakeTraitCustom 14 | param: [ Type ] 15 | showParam: true 16 | - name: ThorsAnvil_PointerAllocator 17 | param: [ Type, Action] 18 | showParam: true 19 | - name: ThorsAnvil_MakeTrait 20 | param: [ Type, fields...] 21 | showParam: true 22 | - name: ThorsAnvil_ExpandTrait 23 | param: [ ParentType, Type, fields...] 24 | showParam: true 25 | - name: ThorsAnvil_Template_MakeTrait 26 | param: [ TemplateParameterCount, Type, fields... ] 27 | showParam: true 28 | - name: ThorsAnvil_Template_ExpandTrait 29 | param: [ TemplateParameterCount, ParentType, Type, fields... ] 30 | showParam: true 31 | - name: ThorsAnvil_PolyMorphicSerializer 32 | param: [ Type ] 33 | showParam: true 34 | - name: ThorsAnvil_RegisterPolyMorphicType 35 | param: [ Type ] 36 | showParam: true 37 | 38 | notes: This was copied from package/ThorSerialize.md and made to look nice 39 | thus it must be manially maintained. 40 | --- 41 | -------------------------------------------------------------------------------- /doc/example3.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ThorSerialize/Serialize.h" 3 | #include "ThorSerialize/Serialize.tpp" 4 | #include "ThorSerialize/Traits.h" 5 | #include "ThorSerialize/JsonThor.h" 6 | #include 7 | #include 8 | #include 9 | 10 | struct Vehicle 11 | { 12 | Vehicle(){} 13 | Vehicle(int speed) 14 | : speed(speed) 15 | {} 16 | virtual ~Vehicle() {} 17 | int speed; 18 | ThorsAnvil_PolyMorphicSerializer(Vehicle); 19 | }; 20 | struct Car: public Vehicle 21 | { 22 | Car(){} 23 | Car(int speed, std::string const& make) 24 | : Vehicle(speed) 25 | , make(make) 26 | {} 27 | std::string make; 28 | ThorsAnvil_PolyMorphicSerializer(Car); 29 | }; 30 | struct Bike: public Vehicle 31 | { 32 | Bike(){} 33 | Bike(int speed, int stroke) 34 | : Vehicle(speed) 35 | , stroke(stroke) 36 | {} 37 | int stroke; 38 | ThorsAnvil_PolyMorphicSerializer(Bike); 39 | }; 40 | 41 | ThorsAnvil_MakeTrait(Vehicle, speed); 42 | ThorsAnvil_ExpandTrait(Vehicle, Car, make); 43 | ThorsAnvil_ExpandTrait(Vehicle, Bike, stroke); 44 | 45 | int main() 46 | { 47 | Vehicle* init = new Bike(15, 2); 48 | 49 | std::stringstream stream; 50 | stream << ThorsAnvil::Serialize::jsonExporter(init); 51 | std::cout << ThorsAnvil::Serialize::jsonExporter(init) << "\n\n"; 52 | 53 | Vehicle* result = nullptr; 54 | std::cout << ThorsAnvil::Serialize::jsonExporter(result) << "\n\n"; 55 | stream >> ThorsAnvil::Serialize::jsonImporter(result); 56 | 57 | std::cout << ThorsAnvil::Serialize::jsonExporter(result) << "\n\n"; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /doc/example2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ThorSerialize/Traits.h" 3 | #include "ThorSerialize/SerUtil.h" 4 | #include "ThorSerialize/JsonThor.h" 5 | 6 | /* A class that you want to serialize. */ 7 | class MyClass 8 | { 9 | int data1; 10 | float data2; 11 | std::string data3; 12 | public: 13 | MyClass(int data1, float data2, std::string const& data3) 14 | : data1(data1) 15 | , data2(data2) 16 | , data3(data3) 17 | {} 18 | 19 | // This is only required if the members are private. 20 | friend struct ThorsAnvil::Serialize::Traits; 21 | }; 22 | 23 | 24 | /* 25 | * Though there is no code involved, you do need to set up 26 | * this structure to tell the library what fields need to be serialized. 27 | * To do this use the macro: ThorsAnvil_MakeTrait() 28 | * Specifying your class, and a list of members to serialize. 29 | */ 30 | ThorsAnvil_MakeTrait(MyClass, data1, data2, data3); 31 | 32 | int main() 33 | { 34 | using ThorsAnvil::Serialize::jsonExporter; 35 | using ThorsAnvil::Serialize::PrinterInterface; 36 | 37 | MyClass data {56, 23.456, "Hi there"}; 38 | 39 | 40 | // This generates a simple JSON Object (wordy) 41 | std::cout << "Version 1\n"; 42 | std::cout << jsonExporter(data) << "\n\n\n"; 43 | 44 | // This generates a compact JSON 45 | std::cout << "Version 2 (Stream)\n"; 46 | std::cout << jsonExporter(data, PrinterInterface::OutputType::Stream) << "\n\n\n"; 47 | 48 | // Standard containers work automatically. 49 | // As long as the type held by the container has had an appropriate 50 | // Traits declaration. 51 | std::vector vec(4, data); 52 | std::cout << "Vector\n"; 53 | std::cout << jsonExporter(vec) << "\n"; 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to ThorsSerializer 2 | 3 | #### **Did you find a bug?** 4 | 5 | * [Open an Issue](https://github.com/Loki-Astari/ThorsSerializer/issues/new). 6 | Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. 7 | 8 | #### **Did you write a patch that fixes a bug?** 9 | 10 | * Open a new GitHub pull request with the patch. 11 | 12 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 13 | 14 | * Make sure it build localy with no errors. 15 | 16 | ./configure --disable-binary 17 | make 18 | 19 | #### **Did you fix whitespace, format code, or make a purely cosmetic patch?** 20 | 21 | * Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of ThorsSerializer will generally not be accepted. 22 | 23 | #### **Do you intend to add a new feature or change an existing one?** 24 | 25 | * [Open an Issue](https://github.com/Loki-Astari/ThorsSerializer/issues/new). 26 | 27 | #### **Do you have questions about the source code?** 28 | 29 | * Check the internal [documentation](https://lokiastari.com/ThorsSerializer/) 30 | 31 | * If this does not resolve your question [Open an Issue](https://github.com/Loki-Astari/ThorsSerializer/issues/new). 32 | 33 | #### **Do you want to contribute to the ThorsSerializer documentation?** 34 | 35 | * Documentation files can be found in [/docSource/source/package/](https://github.com/Loki-Astari/ThorsSerializer/tree/master/docSource/source/package) directory. 36 | They are built with [andvari](https://github.com/Loki-Astari/andvari) using the [documentation theme](https://github.com/Loki-Astari/andvari-theme-documentation). 37 | All documentation on hosted by github via [docs](https://lokiastari.com/ThorsSerializer/) 38 | 39 | 40 | Thanks! :heart: :heart: :heart: 41 | 42 | Loki Astari 43 | -------------------------------------------------------------------------------- /doc/example7.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-1 [See doc/example1.cpp](example1.cpp) 4 | ```C++ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ThorSerialize/Traits.h" 10 | #include "ThorSerialize/JsonThor.h" 11 | 12 | struct Component 13 | { 14 | std::string type; 15 | std::vector axis; 16 | }; 17 | struct Data 18 | { 19 | std::vector components; 20 | }; 21 | 22 | // Declare the traits. 23 | // Specifying what members need to be serialized. 24 | ThorsAnvil_MakeTrait(Component, type, axis); 25 | ThorsAnvil_MakeTrait(Data, components); 26 | 27 | int main() 28 | { 29 | using ThorsAnvil::Serialize::jsonImporter; 30 | using ThorsAnvil::Serialize::jsonExporter; 31 | 32 | Data data1; 33 | Data data2; 34 | // See: https://github.com/Loki-Astari/ThorsSerializer/blob/master/doc/example7.json 35 | std::ifstream file("example7.json"); 36 | 37 | if (file >> jsonImporter(data1)) { 38 | std::cout << "Object Read OK\n"; 39 | std::cout << jsonExporter(data1) << "\n"; 40 | } 41 | else { 42 | std::cout << "Object Read FAIL\n"; 43 | } 44 | 45 | 46 | if (file >> jsonImporter(data2)) { 47 | std::cout << "Object Read OK\n"; 48 | std::cout << jsonExporter(data2) < "\n"; 49 | } 50 | else { 51 | std::cout << "Object Read FAIL\n"; 52 | } 53 | } 54 | ``` 55 | 56 | ### Build and run 57 | ```bash 58 | > g++ -std=c++20 example7.cpp -lThorSerialize -lThorsLogging 59 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 60 | > ./a.out 61 | Object Read OK 62 | 63 | { 64 | "components": [ 65 | { 66 | "type": "mesh", 67 | "axis": [ "x", "y", "z"] 68 | }] 69 | } 70 | Object Read FAIL 71 | 72 | ``` 73 | -------------------------------------------------------------------------------- /doc/example6.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-6: [see doc/example6.cpp](example6.cpp) 4 | ```C++ 5 | #include 6 | #include "ThorSerialize/Traits.h" 7 | #include "ThorSerialize/SerUtil.h" 8 | #include "ThorSerialize/JsonThor.h" 9 | 10 | /* A class that you want to serialize. */ 11 | class MyClass 12 | { 13 | std::string H; 14 | int N; 15 | int D1; 16 | int D2; 17 | friend struct ThorsAnvil::Serialize::Traits; 18 | 19 | public: 20 | MyClass(std::string const& h, int n, int d1, int d2) 21 | : H(h) 22 | , N(n) 23 | , D1(d1) 24 | , D2(d2) 25 | {} 26 | }; 27 | 28 | 29 | /* 30 | * Though there is no code involved, you do need to set up 31 | * this structure to tell the library what fields need to be serialized. 32 | * To do this use the macro: ThorsAnvil_MakeTrait() 33 | * Specifying your class, and a list of members to serialize. 34 | */ 35 | ThorsAnvil_MakeTrait(MyClass, H, N, D1, D2); 36 | 37 | ``` 38 | This allows us to import and export object of the above class really easily. 39 | ```C++ 40 | int main() 41 | { 42 | using ThorsAnvil::Serialize::jsonExporter; 43 | using ThorsAnvil::Serialize::PrinterInterface; 44 | using namespace std::string_literals; 45 | 46 | MyClass data {"1"s, 3, 3, 150}; 47 | 48 | 49 | // This generates a simple JSON Object (wordy) 50 | std::cout << "Version 1\n"; 51 | std::cout << jsonExporter(data) << "\n\n\n"; 52 | 53 | // This generates a compact JSON 54 | std::cout << "Version 2 (Stream)\n"; 55 | std::cout << jsonExporter(data, PrinterInterface::OutputType::Stream) << "\n\n\n"; 56 | } 57 | ``` 58 | 59 | This generates: 60 | 61 | ```bash 62 | > g++ -std=c++20 -o example6 example6.cpp -lThorSerialize -lThorsLogging 63 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 64 | > ./example6 65 | Version 1 66 | 67 | { 68 | "H": "1", 69 | "N": 3, 70 | "D1": 3, 71 | "D2": 150 72 | } 73 | 74 | 75 | Version 2 (Stream) 76 | {"H":"1","N":3,"D1":3,"D2":150} 77 | ``` 78 | -------------------------------------------------------------------------------- /docSource/source/package/ThorSerialize-api.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: package 3 | generate: false 4 | nameSpace: ThorsAnvil::Serialize 5 | headers: 6 | base: ThorSerialize 7 | files: 8 | - name: BinaryThor.h 9 | functions: 10 | - return: Exporter, T> 11 | name: binExport 12 | param: [ T const& value, bool catchExceptions = false ] 13 | - return: Importer, T> 14 | name: binImport 15 | param: [ T& value, bool catchExceptions = false ] 16 | classes: [] 17 | - name: JsonThor.h 18 | functions: 19 | - return: Exporter 20 | name: jsonExport 21 | param: [ T const& value, PrinterInterface::OutputType characteristics = PrinterInterface::OutputType::Default, bool catchExceptions = false ] 22 | - return: Importer 23 | name: jsonImport 24 | param: [ T& value, ParserInterface::ParseType parseStrictness = ParserInterface::ParseType::Weak, bool catchExceptions = false ] 25 | classes: [] 26 | - name: YamlThor.h 27 | functions: 28 | - return: Exporter 29 | name: yamlExport 30 | param: [ T const& value, PrinterInterface::OutputType characteristics = PrinterInterface::OutputType::Default, bool catchExceptions = false ] 31 | - return: Importer 32 | name: yamlImport 33 | param: [ T& value, ParserInterface::ParseType parseStrictness = ParserInterface::ParseType::Weak, bool catchExceptions = false ] 34 | classes: [] 35 | children: 36 | - name: binExport 37 | value: ThorSerialize.BinaryThor.binExport.md 38 | - name: binImport 39 | value: ThorSerialize.BinaryThor.binImport.md 40 | - name: jsonExport 41 | value: ThorSerialize.JsonThor.jsonExport.md 42 | - name: jsonImport 43 | value: ThorSerialize.JsonThor.jsonImport.md 44 | - name: yamlExport 45 | value: ThorSerialize.YamlThor.yamlExport.md 46 | - name: yamlImport 47 | value: ThorSerialize.YamlThor.yamlImport.md 48 | --- 49 | -------------------------------------------------------------------------------- /doc/example1.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-1 [See doc/example1.cpp](example1.cpp) 4 | ```C++ 5 | #include 6 | #include 7 | #include "ThorSerialize/Traits.h" 8 | #include "ThorSerialize/JsonThor.h" 9 | 10 | struct Shirt 11 | { 12 | int red; 13 | int green; 14 | int blue; 15 | }; 16 | class TeamMember 17 | { 18 | std::string name; 19 | int score; 20 | int damage; 21 | Shirt team; 22 | public: 23 | TeamMember(std::string const& name, int score, int damage, Shirt const& team) 24 | : name(name) 25 | , score(score) 26 | , damage(damage) 27 | , team(team) 28 | {} 29 | // Define the trait as a friend to get accesses to private 30 | // Members. 31 | friend class ThorsAnvil::Serialize::Traits; 32 | }; 33 | 34 | // Declare the traits. 35 | // Specifying what members need to be serialized. 36 | ThorsAnvil_MakeTrait(Shirt, red, green, blue); 37 | ThorsAnvil_MakeTrait(TeamMember, name, score, damage, team); 38 | 39 | int main() 40 | { 41 | using ThorsAnvil::Serialize::jsonImporter; 42 | using ThorsAnvil::Serialize::jsonExporter; 43 | 44 | TeamMember mark("mark", 10, 5, Shirt{255,0,0}); 45 | // Use the export function to serialize 46 | std::cout << jsonExporter(mark) << "\n"; 47 | 48 | TeamMember john("Empty", 0, 0, Shirt{0,0,0}); 49 | std::stringstream input(R"({"name": "John","score": 13,"team":{"red": 0,"green": 0,"blue": 255, "black":25}})"); 50 | input >> jsonImporter(john); 51 | std::cout << jsonExporter(john) << "\n"; 52 | } 53 | ``` 54 | 55 | ### Build and run 56 | ```bash 57 | > g++ -std=c++20 example1.cpp -lThorSerialize -lThorsLogging 58 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 59 | > ./a.out 60 | { 61 | "name": "mark", 62 | "score": 10, 63 | "damage": 5, 64 | "team": 65 | { 66 | "red": 255, 67 | "green": 0, 68 | "blue": 0 69 | } 70 | } 71 | { 72 | "name": "John", 73 | "score": 13, 74 | "damage": 0, 75 | "team": 76 | { 77 | "red": 0, 78 | "green": 0, 79 | "blue": 255 80 | } 81 | } 82 | ``` 83 | -------------------------------------------------------------------------------- /docSource/source/group/implTraitsMap.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | template<> 7 | class Traits 8 | { 9 | public: 10 | static constexpr TraitType type = TraitType::Map; // or TraitType::Parent 11 | 12 | static ExtractorType const& getMembers(); 13 | }; 14 | // ExtractorType => std::tuple 15 | // or MemberExtractor 16 | // 17 | // Item => std::pair // M* pointer to a static member of the class. 18 | // => std::pair // M MapType::* pointer to a member of the class 19 | // struct MemberExtractor 20 | // { 21 | // void operator()(PrinterInterface& printer, ArrayType const& object) const; 22 | // void operator()(ParserInterface& parser, std::string const& key, ArrayType& object) const; 23 | // }; 24 | ```` 25 | If the `Traits<>::type` is `TraitType::Map` or `TraitType::Parent` then the `Traits<>` specialization is expected to have a static `getMembers()` method that returns an `Extractor` object (see below for details). 26 | 27 | When serializing an object where the `Traits<>::type` is `TraitType::Map` or `TraitType::Parent` the library will call `openMap()` on the `printerInterface` (generates a '{' in JSON) and conversely will call `closeMap()` (generates a '}' in JSON) after all the members have been serialized. Conversily when de-serializing into an object with these `Traits<>::type` the parser will expect an mapOpen/mapClose marker (in JSON '{' amd '}' respecively). 28 | 29 | #### Tuple of pair 30 | ````C++ 31 | ThorsAnvil_MakeTrait(DataType, ...); 32 | ThorsAnvil_ExpandTrait(ParentType, DataType, ...); 33 | ```` 34 | If the `getMembers()` method returns a `std::tuple` with a set of `std::pair<>`. Then each pair represents a member of the map that needs to be serialized. The `pair<>::first` represents the key and is serialized as string and when de-serializing we search the `std::tuple` to see if we can match the key that was read from the input. The `pair<>::second` is a pointer to the object that represents the value. A recursive call to de-serialize the value is made. 35 | 36 | The easy way to generate the `Traits<>` specialization for an Map with fields is via the macro `ThorsAnvil_MakeTrait()` or `ThorsAnvil_ExpandTrait()`. 37 | #### MemberExtractor 38 | 39 | If the `getMembers()` method returns any other type it is expected to have an interface that matchs the `MemberExtractor` definition. The method using `PrinterInterface` is called once and is expected to serialize the object using this interface. The method using the `ParserInterface` is called after each key has been extracted and is expected to de-serialize the value directly into the destination object. 40 | -------------------------------------------------------------------------------- /doc/building.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | # Install Instructions: 4 | ## From [Homebrew](https://brew.sh/) 5 | ```bash 6 | brew update 7 | brew install thors-mongo 8 | ``` 9 | ## From [GitHub](https://github.com/Loki-Astari/ThorsSerializer) Header only version 10 | 11 | ```bash 12 | git clone --single-branch --branch header-only https://github.com/Loki-Astari/ThorsSerializer.git 13 | ``` 14 | 15 | This will download just the set of required header files into the directory ThorsSerializer. 16 | 17 | You will need to add this directory to your include path. 18 | 19 | 20 | ## From [GitHub](https://github.com/Loki-Astari/ThorsSerializer) For Development 21 | 22 | The basic script for installing everything is: 23 | 24 | ```bash 25 | > git clone https://github.com/Loki-Astari/ThorsSerializer.git 26 | > cd ThorsSerializer 27 | > ./configure 28 | > make 29 | > sudo make install 30 | ``` 31 | 32 | But installing everything requires a couple of extra libraries and some development tools. You may not need all these tools (try and use brew if you don't). 33 | 34 | ### Description 35 | By default installation will be in `/usr/local/include` and `/usr/local/lib`. You can override this with the normal auto-tools defaults. Use `./configure --help` to get details. 36 | 37 | Note: On M1 Macs this is now `/opt/homebrew/include` and `/opt/homebrew/lib`. 38 | 39 | Note: 40 | libThor.so is build using `-O3` and thus is fully optimized and debug symbols have been stripped. 41 | libThorD.so is build using `-g` and is useful for debugging purposes. 42 | 43 | Note: On mac it uses .dylib rather than .so. 44 | 45 | 46 | ### What is Downloaded 47 | The configuration processes will download the generic makefiles (using git) from [ThorMaker](https://github.com/Loki-Astari/ThorMaker) which in turn will download and build [google's gtest](https://github.com/google/googletest) and [vera++](https://github.com/Loki-Astari/vera-plusplus) library that is used in running the unit tests. 48 | 49 | ## Requirements 50 | This library uses features from C++20 so you will need a compiler that supports this. The generic makefile also does code coverage tests so your compiler will also need to support a code coverage tool that has an interface similar to `gcov`. 51 | 52 | ### What is installed: 53 | * `/user/local/include/ThorSerialize` 54 | * `/user/local/include/ThorsCrypto` 55 | * `/user/local/include/ThorsIOUtil` 56 | * `/user/local/include/ThorsLogging` 57 | * `/user/local/include/ThorsMongo` 58 | * `/user/local/include/ThorsSocket` 59 | * `/user/local/include/ThorsStorage` 60 | * `/usr/local/lib/libThorsLogging.so` 61 | * `/usr/local/lib/libThorSerialize.so` 62 | * `/usr/local/lib/libThorsStorage.so` 63 | * `/usr/local/lib/libThorsSocket.so` 64 | * `/usr/local/lib/libThorsMongo.so` 65 | * `/usr/local/share/man/man3/*` 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at Loki.Astari@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /doc/example2.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-2: [see doc/example2.cpp](example2.cpp) 4 | ```C++ 5 | #include 6 | #include "ThorSerialize/Traits.h" 7 | #include "ThorSerialize/SerUtil.h" 8 | #include "ThorSerialize/JsonThor.h" 9 | 10 | /* A class that you want to serialize. */ 11 | class MyClass 12 | { 13 | int data1; 14 | float data2; 15 | std::string data3; 16 | public: 17 | MyClass(int data1, float data2, std::string const& data3) 18 | : data1(data1) 19 | , data2(data2) 20 | , data3(data3) 21 | {} 22 | 23 | // This is only required if the members are private. 24 | friend struct ThorsAnvil::Serialize::Traits; 25 | }; 26 | 27 | 28 | /* 29 | * Though there is no code involved, you do need to set up 30 | * this structure to tell the library what fields need to be serialized. 31 | * To do this use the macro: ThorsAnvil_MakeTrait() 32 | * Specifying your class, and a list of members to serialize. 33 | */ 34 | ThorsAnvil_MakeTrait(MyClass, data1, data2, data3); 35 | ``` 36 | This allows us to import and export object of the above class really easily. 37 | ```C++ 38 | int main() 39 | { 40 | using ThorsAnvil::Serialize::jsonExporter; 41 | using ThorsAnvil::Serialize::PrinterInterface; 42 | 43 | MyClass data {56, 23.456, "Hi there"}; 44 | 45 | 46 | // This generates a simple JSON Object (wordy) 47 | std::cout << "Version 1\n"; 48 | std::cout << jsonExporter(data) << "\n\n\n"; 49 | 50 | // This generates a compact JSON 51 | std::cout << "Version 2 (Stream)\n"; 52 | std::cout << jsonExporter(data, PrinterInterface::OutputType::Stream) << "\n\n\n"; 53 | 54 | // Standard containers work automatically. 55 | // As long as the type held by the container has had an appropriate 56 | // Traits declaration. 57 | std::vector vec(4, data); 58 | std::cout << "Vector\n"; 59 | std::cout << jsonExporter(vec) << "\n"; 60 | } 61 | ``` 62 | 63 | This generates: 64 | 65 | ```bash 66 | > g++ -std=c++20 -o example2 example2.cpp -lThorSerialize -lThorsLogging 67 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 68 | > ./example2 69 | Version 1 70 | 71 | { 72 | "data1": 56, 73 | "data2": 23.456, 74 | "data3": "Hi there" 75 | } 76 | 77 | 78 | Version 2 (Stream) 79 | {"data1":56,"data2":23.456,"data3":"Hi there"} 80 | 81 | 82 | Vector 83 | [ 84 | { 85 | "data1": 56, 86 | "data2": 23.456, 87 | "data3": "Hi there" 88 | }, 89 | { 90 | "data1": 56, 91 | "data2": 23.456, 92 | "data3": "Hi there" 93 | }, 94 | { 95 | "data1": 56, 96 | "data2": 23.456, 97 | "data3": "Hi there" 98 | }, 99 | { 100 | "data1": 56, 101 | "data2": 23.456, 102 | "data3": "Hi there" 103 | }] 104 | ``` 105 | -------------------------------------------------------------------------------- /doc/example3.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-3: [see doc/example3.cpp](example3.cpp) 4 | The library handles polymorphic types via pointers. The only addition the developer needs to do is add the macro `ThorsAnvil_PolyMorphicSerializer()` into the class (as part of the public) 5 | 6 | ```C++ 7 | #include "ThorSerialize/Serialize.h" 8 | #include "ThorSerialize/Serialize.tpp" 9 | #include "ThorSerialize/Traits.h" 10 | #include "ThorSerialize/JsonThor.h" 11 | #include 12 | #include 13 | #include 14 | 15 | struct Vehicle 16 | { 17 | Vehicle(){} 18 | Vehicle(int speed) 19 | : speed(speed) 20 | {} 21 | virtual ~Vehicle() {} 22 | int speed; 23 | ThorsAnvil_PolyMorphicSerializer(Vehicle); 24 | }; 25 | struct Car: public Vehicle 26 | { 27 | Car(){} 28 | Car(int speed, std::string const& make) 29 | : Vehicle(speed) 30 | , make(make) 31 | {} 32 | std::string make; 33 | ThorsAnvil_PolyMorphicSerializer(Car); 34 | }; 35 | struct Bike: public Vehicle 36 | { 37 | Bike(){} 38 | Bike(int speed, int stroke) 39 | : Vehicle(speed) 40 | , stroke(stroke) 41 | {} 42 | int stroke; 43 | ThorsAnvil_PolyMorphicSerializer(Bike); 44 | }; 45 | ``` 46 | 47 | As per normal the class's must also be declared as serializable. 48 | ```C++ 49 | ThorsAnvil_MakeTrait(Vehicle, speed); 50 | ThorsAnvil_ExpandTrait(Vehicle, Car, make); 51 | ThorsAnvil_ExpandTrait(Vehicle, Bike, stroke); 52 | ``` 53 | 54 | The use cases for serialization/de-serialization are the same: 55 | ```C++ 56 | int main() 57 | { 58 | Vehicle* init = new Bike(15, 2); 59 | 60 | std::stringstream stream; 61 | stream << ThorsAnvil::Serialize::jsonExporter(init); 62 | std::cout << ThorsAnvil::Serialize::jsonExporter(init) << "\n\n"; 63 | 64 | Vehicle* result = nullptr; 65 | std::cout << ThorsAnvil::Serialize::jsonExporter(result) << "\n\n"; 66 | stream >> ThorsAnvil::Serialize::jsonImporter(result); 67 | 68 | std::cout << ThorsAnvil::Serialize::jsonExporter(result) << "\n\n"; 69 | } 70 | ``` 71 | 72 | The one difference from normal serialization is that it adds an extra member to the output class. The key `"__type"` is serialized as the first member of an object. When reading (De-Serializing) a stream the key `"__type"` must be the first member of the object (Otherwise you will get an exception). Notice a `nullptr` is serialized as `null` in JSON. 73 | 74 | ```bash 75 | > g++ -std=c++20 -o example3 example3.cpp -lThorSerialize -lThorsLogging 76 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 77 | > ./example3 78 | { 79 | "__type": "Bike", 80 | "speed": 15, 81 | "stroke": 2 82 | } 83 | 84 | null 85 | 86 | 87 | { 88 | "__type": "Bike", 89 | "speed": 15, 90 | "stroke": 2 91 | } 92 | ``` 93 | 94 | To make this work the `Traits` class for pointers generates a default `alloc()` method that simply calls new on the object (and assumes a default constructor). If you need a custom allocation methods you can specify your own custom one. 95 | 96 | ```C++ 97 | ThorsAnvil_PointerAllocator(Bike, [](){return new Bike(6,7);}); 98 | ``` 99 | -------------------------------------------------------------------------------- /docs/stylesheet/style.css: -------------------------------------------------------------------------------- 1 | 190 | 191 | -------------------------------------------------------------------------------- /docSource/source/group/usageDeclarationsPointers.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | #include "ThorSerialize/JsonThor.h" 7 | #include "ThorSerialize/SerUtil.h" 8 | #include "TeamMember.h" 9 | 10 | 11 | using ThorsAnvil::Serialize::jsonExport; 12 | using ThorsAnvil::Serialize::jsonImport; 13 | 14 | int main() 15 | { 16 | std::unique_ptr data; 17 | std::cout << jsonExport(data) << "\n"; 18 | std::cout << jsonExport(data.get()) << "\n"; 19 | 20 | data.reset(new TeamMember{"Tim", 33, 2, Shirt{12, 13, 14}}); 21 | std::cout << jsonExport(data) << "\n"; 22 | std::cout << jsonExport(data.get()) << "\n"; 23 | } 24 | ... 25 | null 26 | null 27 | 28 | { 29 | "name": "Tim", 30 | "score": 33, 31 | "damage": 2, 32 | "team": 33 | { 34 | "red": 12, 35 | "green": 13, 36 | "blue": 14 37 | } 38 | } 39 | 40 | { 41 | "name": "Tim", 42 | "score": 33, 43 | "damage": 2, 44 | "team": 45 | { 46 | "red": 12, 47 | "green": 13, 48 | "blue": 14 49 | } 50 | } 51 | ```` 52 | No extra work needs to be done to serialize pointers. If the pointer is `nullptr` it will serialize to the `null` type of the serialization format. If the pointer is not null then it will serialize as an object. 53 | 54 | #### std::unique_ptr 55 | The `std::unique_ptr<>` behaves just like a pointer during serialization. 56 | 57 | #### std::shared_ptr 58 | The `std::shared_ptr` is correctly de-dupped. i.e. If you have two (or more) shared pointers pointing at the same object then the object is only serialized once (the second time we serialize an id). When de-serializing shared_ptr the reference id is used to reconnect the objects so that the shared pointers now continue to use a shared object. 59 | 60 | #### Polymorphic Objects 61 | ````C++ 62 | #include "ThorSerialize/JsonThor.h" 63 | #include "TeamMember.h" 64 | 65 | using ThorsAnvil::Serialize::jsonExport; 66 | using ThorsAnvil::Serialize::jsonImport; 67 | 68 | struct Vehicle 69 | { 70 | Vehicle(){} 71 | Vehicle(int speed) 72 | : speed(speed) 73 | {} 74 | virtual ~Vehicle() {} 75 | int speed; 76 | ThorsAnvil_PolyMorphicSerializer(Vehicle); 77 | }; 78 | struct Car: public Vehicle 79 | { 80 | Car(){} 81 | Car(int speed, std::string const& make) 82 | : Vehicle(speed) 83 | , make(make) 84 | {} 85 | std::string make; 86 | ThorsAnvil_PolyMorphicSerializer(Car); 87 | }; 88 | struct Bike: public Vehicle 89 | { 90 | Bike(){} 91 | Bike(int speed, int stroke) 92 | : Vehicle(speed) 93 | , stroke(stroke) 94 | {} 95 | int stroke; 96 | ThorsAnvil_PolyMorphicSerializer(Bike); 97 | }; 98 | ThorsAnvil_MakeTrait(Vehicle, speed); 99 | ThorsAnvil_ExpandTrait(Vehicle, Car, make); 100 | ThorsAnvil_ExpandTrait(Vehicle, Bike, stroke); 101 | 102 | int main() 103 | { 104 | Vehicle* v = new Bike(12,3); 105 | std::cout << jsonExport(v) << "\n"; 106 | } 107 | ... 108 | { 109 | "__type": "Bike", 110 | "speed": 12, 111 | "stroke": 3 112 | } 113 | 114 | ```` 115 | Polymorphic objects are supported. **BUT** require an intrusive change in the type. To mark objects as polymorphic you need to add the macro `ThorsAnvil_PolyMorphicSerializer()`. This macro adds a couple of virtual methods to your class (but no data members). Additonally the resulting JSON has an extra field `__ type` that contains the name of the type. This allows the serialization library to dynamically create the correct type at runtime. 116 | 117 | 118 | -------------------------------------------------------------------------------- /doc/example8.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Example-1 [See doc/example1.cpp](example1.cpp) 4 | Input File: **file.json** 5 | 6 | ```json 7 | [ 8 | { 9 | "operation": "test", 10 | "identifier": { 11 | "name": "1", 12 | "bar": "sandbox", 13 | "foo": "foo" 14 | }, 15 | "properties": { 16 | "category": "xxx", 17 | "time": "yyy", 18 | "shouldRetry": "False", 19 | "Id": "vvvv" 20 | } 21 | } 22 | ] 23 | ``` 24 | 25 | Source file: **example8.cpp** 26 | 27 | ```C++ 28 | #include "ThorSerialize/Traits.h" 29 | #include "ThorSerialize/JsonThor.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | class Identifier 36 | { 37 | public: 38 | std::string name; 39 | std::string bar; 40 | std::string foo; 41 | }; 42 | class Properties 43 | { 44 | public: 45 | std::string category; 46 | std::string time; 47 | std::string shouldRetry; 48 | std::string Id; 49 | }; 50 | class Data 51 | { 52 | public: 53 | std::string operation; 54 | Identifier identifier; 55 | Properties properties; 56 | }; 57 | 58 | ThorsAnvil_MakeTrait(Identifier, name, bar, foo); 59 | ThorsAnvil_MakeTrait(Properties, category, time, shouldRetry, Id); 60 | ThorsAnvil_MakeTrait(Data, operation, identifier, properties); 61 | 62 | int main() 63 | { 64 | using ThorsAnvil::Serialize::jsonImporter; 65 | using ThorsAnvil::Serialize::jsonExporter; 66 | 67 | std::vector objects; 68 | 69 | std::ifstream file("file.json"); 70 | 71 | if (file >> jsonImporter(objects)) { 72 | std::cout << "Read Worked\n"; 73 | 74 | std::cout << jsonExporter(objects); 75 | } 76 | } 77 | ``` 78 | 79 | ### Build and run 80 | ```bash 81 | > # Assume you have installed ThorsAnvil from Brew 82 | > # brew install ThorsSerializer 83 | > g++ -std=c++20 example8.cpp -lThorSerialize -lThorsLogging 84 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 85 | > ./a.out 86 | Object Read OK 87 | 88 | Read Worked 89 | [ 90 | { 91 | "operation": "test", 92 | "identifier": 93 | { 94 | "name": "1", 95 | "bar": "sandbox", 96 | "foo": "foo" 97 | }, 98 | "properties": 99 | { 100 | "category": "xxx", 101 | "time": "yyy", 102 | "shouldRetry": "False", 103 | "Id": "vvvv" 104 | } 105 | }] 106 | 107 | ``` 108 | 109 | Alternative Build using header only library: 110 | ```bash 111 | > git clone https://github.com/Neargye/magic_enum.git ~/MyHeaders/MagicEnum 112 | > git clone --single-branch --branch header-only https://github.com/Loki-Astari/ThorsSerializer.git ~/MyHeaders/ThorsSerializer 113 | > 114 | > g++ -std=c++20 example8.cpp -I ~/MyHeaders/MagicEnum/include/magic_enum -I ~/MyHeaders/ThorsSerializer 115 | > ./a.out 116 | Object Read OK 117 | 118 | Read Worked 119 | [ 120 | { 121 | "operation": "test", 122 | "identifier": 123 | { 124 | "name": "1", 125 | "bar": "sandbox", 126 | "foo": "foo" 127 | }, 128 | "properties": 129 | { 130 | "category": "xxx", 131 | "time": "yyy", 132 | "shouldRetry": "False", 133 | "Id": "vvvv" 134 | } 135 | }] 136 | 137 | ``` 138 | -------------------------------------------------------------------------------- /docs/stylesheet/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.15.0 2 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+c+bash+bison+cpp+json&plugins=line-numbers */ 3 | /** 4 | * prism.js default theme for JavaScript, CSS and HTML 5 | * Based on dabblet (http://dabblet.com) 6 | * @author Lea Verou 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: black; 12 | background: none; 13 | text-shadow: 0 1px white; 14 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | } 31 | 32 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 33 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 34 | text-shadow: none; 35 | background: #b3d4fc; 36 | } 37 | 38 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 39 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 40 | text-shadow: none; 41 | background: #b3d4fc; 42 | } 43 | 44 | @media print { 45 | code[class*="language-"], 46 | pre[class*="language-"] { 47 | text-shadow: none; 48 | } 49 | } 50 | 51 | /* Code blocks */ 52 | pre[class*="language-"] { 53 | padding: 1em; 54 | margin: .5em 0; 55 | overflow: auto; 56 | } 57 | 58 | :not(pre) > code[class*="language-"], 59 | pre[class*="language-"] { 60 | background: #f5f2f0; 61 | } 62 | 63 | /* Inline code */ 64 | :not(pre) > code[class*="language-"] { 65 | padding: .1em; 66 | border-radius: .3em; 67 | white-space: normal; 68 | } 69 | 70 | .token.comment, 71 | .token.prolog, 72 | .token.doctype, 73 | .token.cdata { 74 | color: slategray; 75 | } 76 | 77 | .token.punctuation { 78 | color: #999; 79 | } 80 | 81 | .namespace { 82 | opacity: .7; 83 | } 84 | 85 | .token.property, 86 | .token.tag, 87 | .token.boolean, 88 | .token.number, 89 | .token.constant, 90 | .token.symbol, 91 | .token.deleted { 92 | color: #905; 93 | } 94 | 95 | .token.selector, 96 | .token.attr-name, 97 | .token.string, 98 | .token.char, 99 | .token.builtin, 100 | .token.inserted { 101 | color: #690; 102 | } 103 | 104 | .token.operator, 105 | .token.entity, 106 | .token.url, 107 | .language-css .token.string, 108 | .style .token.string { 109 | color: #9a6e3a; 110 | background: hsla(0, 0%, 100%, .5); 111 | } 112 | 113 | .token.atrule, 114 | .token.attr-value, 115 | .token.keyword { 116 | color: #07a; 117 | } 118 | 119 | .token.function, 120 | .token.class-name { 121 | color: #DD4A68; 122 | } 123 | 124 | .token.regex, 125 | .token.important, 126 | .token.variable { 127 | color: #e90; 128 | } 129 | 130 | .token.important, 131 | .token.bold { 132 | font-weight: bold; 133 | } 134 | .token.italic { 135 | font-style: italic; 136 | } 137 | 138 | .token.entity { 139 | cursor: help; 140 | } 141 | 142 | pre[class*="language-"].line-numbers { 143 | position: relative; 144 | padding-left: 3.8em; 145 | counter-reset: linenumber; 146 | } 147 | 148 | pre[class*="language-"].line-numbers > code { 149 | position: relative; 150 | white-space: inherit; 151 | } 152 | 153 | .line-numbers .line-numbers-rows { 154 | position: absolute; 155 | pointer-events: none; 156 | top: 0; 157 | font-size: 100%; 158 | left: -3.8em; 159 | width: 3em; /* works for line-numbers below 1000 lines */ 160 | letter-spacing: -1px; 161 | border-right: 1px solid #999; 162 | 163 | -webkit-user-select: none; 164 | -moz-user-select: none; 165 | -ms-user-select: none; 166 | user-select: none; 167 | 168 | } 169 | 170 | .line-numbers-rows > span { 171 | pointer-events: none; 172 | display: block; 173 | counter-increment: linenumber; 174 | } 175 | 176 | .line-numbers-rows > span:before { 177 | content: counter(linenumber); 178 | color: #999; 179 | display: block; 180 | padding-right: 0.8em; 181 | text-align: right; 182 | } 183 | 184 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | 4 | 5 | #ifndef THORS_SERIALIZER_CONFIG_H 6 | #define THORS_SERIALIZER_CONFIG_H 7 | #ifndef THORS_PACKAGE_INFO_CONFIG_H 8 | #define THORS_PACKAGE_INFO_CONFIG_H 9 | 10 | 11 | 12 | /* define if the Boost library is available */ 13 | #undef HAVE_BOOST 14 | 15 | /* We have found package CRYPTO */ 16 | #undef HAVE_CRYPTO 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_DLFCN_H 20 | 21 | /* We have found package Event */ 22 | #undef HAVE_EVENT 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_INTTYPES_H 26 | 27 | /* We have found MagicEnumHeaderOnly package */ 28 | #undef HAVE_MagicEnumHeaderOnly 29 | 30 | /* Magic Enum V1 being used */ 31 | #undef HAVE_MagicEnumHeaderOnlyV1 32 | 33 | /* Magic Enum V2 being used */ 34 | #undef HAVE_MagicEnumHeaderOnlyV2 35 | 36 | /* We have found package SNAPPY */ 37 | #undef HAVE_SNAPPY 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_STDINT_H 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #undef HAVE_STDIO_H 44 | 45 | /* Define to 1 if you have the header file. */ 46 | #undef HAVE_STDLIB_H 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #undef HAVE_STRINGS_H 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #undef HAVE_STRING_H 53 | 54 | /* Define to 1 if you have the header file. */ 55 | #undef HAVE_SYS_STAT_H 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #undef HAVE_SYS_TYPES_H 59 | 60 | /* We have found package Thors Serializer */ 61 | #undef HAVE_THORSSERIALIZER 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #undef HAVE_UNISTD_H 65 | 66 | /* We have found package YAML */ 67 | #undef HAVE_YAML 68 | 69 | /* We have found package ZLIB */ 70 | #undef HAVE_ZLIB 71 | 72 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 73 | #undef LT_OBJDIR 74 | 75 | /* "Get mongosh version into #define. That way we can turn off some tests" */ 76 | #undef MONGO_MAJOR_VERSION 77 | 78 | /* Name of package */ 79 | #undef PACKAGE 80 | 81 | /* Define to the address where bug reports for this package should be sent. */ 82 | #undef PACKAGE_BUGREPORT 83 | 84 | /* Define to the full name of this package. */ 85 | #undef PACKAGE_NAME 86 | 87 | /* Define to the full name and version of this package. */ 88 | #undef PACKAGE_STRING 89 | 90 | /* Define to the one symbol short name of this package. */ 91 | #undef PACKAGE_TARNAME 92 | 93 | /* Define to the home page for this package. */ 94 | #undef PACKAGE_URL 95 | 96 | /* Define to the version of this package. */ 97 | #undef PACKAGE_VERSION 98 | 99 | /* Define to 1 if all of the C89 standard headers exist (not just the ones 100 | required in a freestanding environment). This macro is provided for 101 | backward compatibility; new code need not use it. */ 102 | #undef STDC_HEADERS 103 | 104 | /* Enable to use header only libraries */ 105 | 106 | /* For header only convert to inline */ 107 | 108 | /* Set up to build on Conan */ 109 | #undef THOR_CONAN 110 | 111 | /* Disable test that require files to be locked */ 112 | #undef THOR_DISABLE_TEST_WITH_LOCKED_FILES 113 | 114 | /* Disable test that require the Mongo server to support the OP_QUERY command 115 | */ 116 | #undef THOR_DISABLE_TEST_WITH_MONGO_QUERY 117 | 118 | /* mongosh DB for testing */ 119 | #undef THOR_TESTING_MONGO_DB 120 | 121 | /* mongosh DB host for testing */ 122 | #undef THOR_TESTING_MONGO_HOST 123 | 124 | /* mongosh DB password for testing */ 125 | #undef THOR_TESTING_MONGO_PASS 126 | 127 | /* mongosh DB user for testing */ 128 | #undef THOR_TESTING_MONGO_USER 129 | 130 | /* Version number of package */ 131 | #undef VERSION 132 | 133 | 134 | 135 | 136 | 137 | #endif 138 | 139 | 140 | /* Enable to use header only libraries */ 141 | #undef THORS_SERIALIZER_HEADER_ONLY 142 | 143 | /* For header only convert to inline */ 144 | #undef THORS_SERIALIZER_HEADER_ONLY_INCLUDE 145 | 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | from conan import ConanFile, tools 2 | from conan.tools.scm import Git 3 | from conan.tools.gnu import Autotools 4 | from conan.tools.gnu import AutotoolsDeps 5 | from conan.tools.gnu import AutotoolsToolchain 6 | 7 | class ThorsSerializerConan(ConanFile): 8 | name = "thors-mongo" 9 | version = "3.2.20" 10 | license = "GPL-3.0" 11 | author = "Martin York Loki.Astari@gmail.com" 12 | url = "https://github.com/Loki-Astari/ThorsSerializer" 13 | description = "Serialization Library including C++ Mongo layer" 14 | topics = ("C++", "Serialization", "Mongo", "JSON", "BSON", "YAML") 15 | settings = "os", "compiler", "build_type", "arch" 16 | options = {"shared": [True, False], "fPIC": [True, False]} 17 | default_options = {"shared": True, "fPIC": True} 18 | 19 | def generate(self): 20 | tc = AutotoolsToolchain(self) 21 | tc.configure_args.append("--enable-test-with-conan") 22 | tc.configure_args.append("--enable-dark-mode") 23 | tc.configure_args.append("--disable-test-with-mongo-query") 24 | tc.configure_args.append("--disable-Mongo-Service") 25 | tc.configure_args.append("--disable-vera") 26 | print("ZLib: " + self.dependencies["zlib"].package_folder) 27 | tc.configure_args.append("--with-zlib-root=" + self.dependencies["zlib"].package_folder) 28 | print("Yaml: " + self.dependencies["libyaml"].package_folder) 29 | tc.configure_args.append("--with-yaml-root=" + self.dependencies["libyaml"].package_folder) 30 | print("Snappy: " + self.dependencies["snappy"].package_folder) 31 | tc.configure_args.append("--with-snappy-root=" + self.dependencies["snappy"].package_folder) 32 | print("Open: " + self.dependencies["openssl"].package_folder) 33 | tc.configure_args.append("--with-crypto-root=" + self.dependencies["openssl"].package_folder) 34 | print("Magic: " + self.dependencies["magic_enum"].package_folder) 35 | tc.configure_args.append("--with-magicenum-header-only-root=" + self.dependencies["magic_enum"].package_folder + "/include/magic_enum") 36 | tc.generate() 37 | 38 | def requirements(self): 39 | self.requires("bzip2/1.0.8") 40 | self.requires("zlib/1.3.1") 41 | self.requires("libyaml/0.2.5") 42 | self.requires("snappy/1.2.1") 43 | self.requires("openssl/3.3.1") 44 | self.requires("magic_enum/0.9.6") 45 | 46 | def source(self): 47 | git = Git(self) 48 | git.clone(url="https://github.com/Loki-Astari/ThorsSerializer.git", target=".") 49 | 50 | def validate(self): 51 | tools.build.check_min_cppstd(self, 20) 52 | 53 | def build(self): 54 | autotools = Autotools(self) 55 | autotools.configure() 56 | autotools.make() 57 | 58 | def package(self): 59 | autotools = Autotools(self) 60 | autotools.install() 61 | 62 | def package_info(self): 63 | self.cpp_info.libs = [ "ThorSerialize", "ThorsLogging", "ThorsMongo", "ThorsSocket", "ThorsStorage", # Release Sym 64 | "ThorSerializeD", "ThorsLoggingD", "ThorsMongoD", "ThorsSocketD", "ThorsStorageD", # Debug Sym 65 | "ThorSerialize20", "ThorsLogging20", "ThorsMongo20", "ThorsSocket20", "ThorsStorage20", # Relase Versioned 66 | "ThorSerialize20D", "ThorsLogging20D", "ThorsMongo20D", "ThorsSocket20D", "ThorsStorage20D" # Debug Versioned 67 | ] 68 | self.cpp_info.libdirs = ["lib"] 69 | self.cpp_info.includedirs = [ "include", 70 | "include/GitUtility", 71 | "include/ThorSerialize", 72 | "include/ThorsCrypto", 73 | "include/ThorsIOUtil", 74 | "include/ThorsLogging", 75 | "include/ThorsMongo", 76 | "include/ThorsSocket", 77 | "include/ThorsStorage" 78 | ] 79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/stylesheet/print.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.content h1,.content h2,.content h3,.content h4,body{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size:14px}.content h1,.content h2,.content h3,.content h4{font-weight:bold}.content pre,.content code{font-family:Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;font-size:12px;line-height:1.5}.content pre,.content code{word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}@font-face{font-family:'slate';src:url(../fonts/slate.eot?-syv14m);src:url(../fonts/slate.eot?#iefix-syv14m) format("embedded-opentype"),url(../fonts/slate.woff2?-syv14m) format("woff2"),url(../fonts/slate.woff?-syv14m) format("woff"),url(../fonts/slate.ttf?-syv14m) format("truetype"),url(../fonts/slate.svg?-syv14m#slate) format("svg");font-weight:normal;font-style:normal}.content aside.warning:before,.content aside.notice:before,.content aside.success:before{font-family:'slate';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1}.content aside.warning:before{content:"\e600"}.content aside.notice:before{content:"\e602"}.content aside.success:before{content:"\e606"}.tocify,.toc-footer,.lang-selector,.search,#nav-button{display:none}.tocify-wrapper>img{margin:0 auto;display:block}.content{font-size:12px}.content pre,.content code{border:1px solid #999;border-radius:5px;font-size:0.8em}.content pre code{border:0}.content pre{padding:1.3em}.content code{padding:0.2em}.content table{border:1px solid #999}.content table tr{border-bottom:1px solid #999}.content table td,.content table th{padding:0.7em}.content p{line-height:1.5}.content a{text-decoration:none;color:#000}.content h1{font-size:2.5em;padding-top:0.5em;padding-bottom:0.5em;margin-top:1em;margin-bottom:21px;border:2px solid #ccc;border-width:2px 0;text-align:center}.content h2{font-size:1.8em;margin-top:2em;border-top:2px solid #ccc;padding-top:0.8em}.content h1+h2,.content h1+div+h2{border-top:none;padding-top:0;margin-top:0}.content h3,.content h4{font-size:0.8em;margin-top:1.5em;margin-bottom:0.8em;text-transform:uppercase}.content h5,.content h6{text-transform:uppercase}.content aside{padding:1em;border:1px solid #ccc;border-radius:5px;margin-top:1.5em;margin-bottom:1.5em;line-height:1.6}.content aside:before{vertical-align:middle;padding-right:0.5em;font-size:14px} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G216KZR3) 2 | 3 | 4 | # ThorsAnvil 5 | 6 | ![ThorStream](img/thorsanvil.jpg) 7 | 8 | A set of modern C++20 libraries for writing interactive Web-Services. 9 | 10 | This project provides the following libraries: 11 | 12 | 1. [Mug](https://github.com/Loki-Astari/Mug) 13 | A simple configurable C++ `NissaServer` that dynamically loads shared libraries that install `NisseHTTP` handlers. 14 | 1. [Nisse](https://github.com/Loki-Astari/Nisse) 15 | + **NisseServer** 16 | Provides a server object that handles socket events and non-blocking async IO operations. 17 | + **NisseHTTP** 18 | Provides HTTP request/response objects exposing the body as an async std::iostream. This allows C++ objects to be streamed directly via a REST interface with no serialization code. 19 | 1. API Supported: 20 | + [ThorsSlack](https://github.com/Loki-Astari/Mug/tree/master/src/ThorsSlack) 21 | Type-safe API to send REST messages to/from Slack. 22 | Supports REST Slack API and Slack webhooks via NissaHTTP. 23 | Use C++ objects, no serialization code required. 24 | + [ThorsMongo](https://github.com/Loki-Astari/ThorsMongo) 25 | Type-safe interface for inserting/updating/finding objects in a collection. 26 | Sends and receives MongoDB wire protocol messages. 27 | Directly send C++ objects to a Mongo collection with no serialization code. 28 | 1. [ThorsSerializer](https://github.com/Loki-Astari/ThorsSerializer) 29 | Automatically converts C++ objects into **JSON** / **BSON** / **YAML** 30 | 31 | 1. [ThorsSocket](https://github.com/Loki-Astari/ThorsSocket) 32 | Async IO library for **Files**/**Pipes**/**Sockets**/**Secure Sockets** that exposes all of them via std::iostream interface. 33 | 34 | 1. [ThorsCrypto](https://github.com/Loki-Astari/ThorsCrypto) 35 | C++ wrapper around platform-specific libraries to support **base64 Encoding**, **CRC Checksum**, **Hashing**, **HMAC**, **SCRAM**, **MD5**, **SHA-1**, **SHA-256**. 36 | 37 | 1. [ThorsIOUtil](https://github.com/Loki-Astari/ThorsIOUtil) 38 | 1. [ThorsLogging](https://github.com/Loki-Astari/ThorsLogging) 39 | 40 | 41 | The main goal of these projects is to remove the need to write boilerplate code. Using a declarative style, an engineer can define the C++ classes and members that need to be serialized. 42 | 43 | # Write-Ups 44 | Detailed explanations of these projects can be found at: 45 | 46 | [LokiAstari.com](https://lokiastari.com/series) 47 | 48 | # Installing 49 | 50 | ## Easy: Using Brew 51 | 52 | Can be installed via brew on Mac and Linux 53 | 54 | > brew install thors-anvil 55 | 56 | * Mac: https://formulae.brew.sh/formula/thors-anvil 57 | * Linux: https://formulae.brew.sh/formula-linux/thors-anvil 58 | 59 | ## Building Manually 60 | 61 | > git clone git@github.com:Loki-Astari/ThorsAnvil.git 62 | > cd ThorsAnvil 63 | > ./configure 64 | > make 65 | 66 | Note: The `configure` script will tell you about any missing dependencies and how to install them. 67 | 68 | ## Building Conan 69 | 70 | If you have Conan installed, the Conan build processes should work. 71 | 72 | > git clone git@github.com:Loki-Astari/ThorsAnvil.git 73 | > cd ThorsAnvil 74 | > conan build -s compiler.cppstd=20 conanfile.py 75 | 76 | ## Header Only 77 | 78 | To install the header-only version 79 | 80 | > git clone --single-branch --branch header-only https://github.com/Loki-Astari/ThorsAnvil.git 81 | 82 | Some dependencies you will need to install manually for header-only builds. 83 | 84 | Magic Enum: https://github.com/Neargye/magic_enum 85 | libYaml https://github.com/yaml/libyaml 86 | libSnappy https://github.com/google/snappy 87 | libZ https://www.zlib.net/ 88 | 89 | Note: The header-only version does not include Mug/Nisse/ThorsSlack. 90 | 91 | ## Building With Visual Studio 92 | 93 | To build on Windows, you will need to add the flag: [`/Zc:preprocessor`](https://learn.microsoft.com/en-us/cpp/build/reference/zc-preprocessor?view=msvc-170). These libraries make heavy use of VAR_ARG macros to generate code for you, so they require a conforming pre-processor. See [Macro Expansion of __VA_ARGS__ Bug in Visual Studio?](https://stackoverflow.com/questions/78605945/macro-expansion-of-va-args-bug-in-visual-studio) for details. 94 | 95 | -------------------------------------------------------------------------------- /docs/group/1: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | #include "ThorSerialize/Traits.h" 7 | 8 | struct Shirt 9 | { 10 | int red; 11 | int green; 12 | int blue; 13 | }; 14 | ThorsAnvil_MakeTrait(Shirt, red, green, blue); 15 | 16 | ... 17 | Shirt shirt{10, 20, 45}; 18 | std::cout << jsonExport(shirt) << "\n"; 19 | 20 | ... 21 | { 22 | "red": 10, 23 | "green": 20, 24 | "blue": 45 25 | } 26 | ```` 27 | In C++ structures are not serializable by default (but often have the appropriate stream operators defined). The advantage of ThorsSerializer library is that it adds a serialization feature to a class without altering the class in any way. This is achieved by building a `Serialization::Traits<>` type for your class. We will go into more detail on how this works in the implementation section. 28 | 29 | The easiest way to build the appropriate `Serialization::Traits<>` type is to use the macro `ThorsAnvil_MakeTrait()` naming the type and all members you want to serialize as part of the object. You simply need to include #include "ThorSerialize/Traits.h". 30 | 31 | #### Private Members 32 | ````C++ 33 | #include "ThorSerialize/Traits.h" 34 | 35 | class TeamMember 36 | { 37 | std::string name; 38 | int score; 39 | int damage; 40 | Shirt team; 41 | public: 42 | TeamMember(std::string const& name, int score, int damage, Shirt const& team) 43 | : name(name) 44 | , score(score) 45 | , damage(damage) 46 | , team(team) 47 | {} 48 | // Define the trait as a friend to get accesses to private Members. 49 | friend class ThorsAnvil::Serialize::Traits; 50 | }; 51 | ThorsAnvil_MakeTrait(TeamMember, name, score, damage, team); 52 | 53 | ... 54 | TeamMember mark("mark", 10, 5, Shirt{66, 42, 23}); 55 | std::cout << jsonExport(mark) << "\n"; 56 | 57 | ... 58 | { 59 | "name": "mark", 60 | "score": 10, 61 | "damage": 5, 62 | "team: 63 | { 64 | "red": 66, 65 | "green": 42, 66 | "blue": 23 67 | } 68 | } 69 | ```` 70 | If you have a class/struct were the members that need to be serialized are private then there is no automatic accesses for the ThorsSerializer library to these members. To give the library accesses your class must declare the `Serialization::Traits<>` type as a friend of the class. This will allow the class to directly accesses these members and both read/write them during the serialization/de-serialization processes. 71 | 72 | #### Inheritance 73 | ````C++ 74 | class ExtendedTeamMember: public TeamMember 75 | { 76 | bool extension; 77 | public: 78 | ExtendedTeamMember(std::string const& name, int score, int damage, Shirt const& team, bool ex) 79 | : TeamMember(name, score, damage, team) 80 | , extension(ex) 81 | {} 82 | }; 83 | ThorsAnvil_ExpandTrait(ExtendedTeamMember, TeamMember, extension); 84 | 85 | ... 86 | TeamMember rangers("Rangers", 10, 5, Shirt{66, 42, 23}, true); 87 | std::cout << jsonExport(rangers) << "\n"; 88 | 89 | ... 90 | { 91 | "name": "Rangers", 92 | "score": 10, 93 | "damage": 5, 94 | "team: 95 | { 96 | "red": 66, 97 | "green": 42, 98 | "blue": 23 99 | }, 100 | "extension": true 101 | } 102 | ```` 103 | The only difference from a base type is that we use `ThorsAnvil_ExpandTrait()` rather than `ThorsAnvil_MakeTrait()`. The difference between these two is that `ThorsAnvil_ExpandTrait()` takes the parent class as the first parameter followed by the child type as the second parameter. 104 | 105 | #### Multiple Inheritance 106 | ````C++ 107 | struct Base1 108 | { 109 | }; 110 | struct Base2 111 | { 112 | }; 113 | struct Object: public Base1, public Base2 114 | { 115 | }; 116 | ThorsAnvil_MakeTrait(Base1); 117 | ThorsAnvil_MakeTrait(Base2); 118 | 119 | // The macro ThorsAnvil_ExpandTrait() only allows you to declare 1 base type name. 120 | // To get around this limitation you need place both base types into `Serialize::Parents<>` template. 121 | // This can then be used as the parent type in the macro ThorsAnvil_ExpandTrait() 122 | using Base1Base2Parent = ThorsAnvil::Serialize::Parents; 123 | ThorsAnvil_ExpandTrait(Object, Base1Base2Parent); 124 | ```` 125 | 126 | -------------------------------------------------------------------------------- /docSource/source/group/1: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | #include "ThorSerialize/Traits.h" 7 | 8 | struct Shirt 9 | { 10 | int red; 11 | int green; 12 | int blue; 13 | }; 14 | ThorsAnvil_MakeTrait(Shirt, red, green, blue); 15 | 16 | ... 17 | Shirt shirt{10, 20, 45}; 18 | std::cout << jsonExport(shirt) << "\n"; 19 | 20 | ... 21 | { 22 | "red": 10, 23 | "green": 20, 24 | "blue": 45 25 | } 26 | ```` 27 | In C++ structures are not serializable by default (but often have the appropriate stream operators defined). The advantage of ThorsSerializer library is that it adds a serialization feature to a class without altering the class in any way. This is achieved by building a `Serialization::Traits<>` type for your class. We will go into more detail on how this works in the implementation section. 28 | 29 | The easiest way to build the appropriate `Serialization::Traits<>` type is to use the macro `ThorsAnvil_MakeTrait()` naming the type and all members you want to serialize as part of the object. You simply need to include #include "ThorSerialize/Traits.h". 30 | 31 | #### Private Members 32 | ````C++ 33 | #include "ThorSerialize/Traits.h" 34 | 35 | class TeamMember 36 | { 37 | std::string name; 38 | int score; 39 | int damage; 40 | Shirt team; 41 | public: 42 | TeamMember(std::string const& name, int score, int damage, Shirt const& team) 43 | : name(name) 44 | , score(score) 45 | , damage(damage) 46 | , team(team) 47 | {} 48 | // Define the trait as a friend to get accesses to private Members. 49 | friend class ThorsAnvil::Serialize::Traits; 50 | }; 51 | ThorsAnvil_MakeTrait(TeamMember, name, score, damage, team); 52 | 53 | ... 54 | TeamMember mark("mark", 10, 5, Shirt{66, 42, 23}); 55 | std::cout << jsonExport(mark) << "\n"; 56 | 57 | ... 58 | { 59 | "name": "mark", 60 | "score": 10, 61 | "damage": 5, 62 | "team: 63 | { 64 | "red": 66, 65 | "green": 42, 66 | "blue": 23 67 | } 68 | } 69 | ```` 70 | If you have a class/struct were the members that need to be serialized are private then there is no automatic accesses for the ThorsSerializer library to these members. To give the library accesses your class must declare the `Serialization::Traits<>` type as a friend of the class. This will allow the class to directly accesses these members and both read/write them during the serialization/de-serialization processes. 71 | 72 | #### Inheritance 73 | ````C++ 74 | class ExtendedTeamMember: public TeamMember 75 | { 76 | bool extension; 77 | public: 78 | ExtendedTeamMember(std::string const& name, int score, int damage, Shirt const& team, bool ex) 79 | : TeamMember(name, score, damage, team) 80 | , extension(ex) 81 | {} 82 | }; 83 | ThorsAnvil_ExpandTrait(ExtendedTeamMember, TeamMember, extension); 84 | 85 | ... 86 | TeamMember rangers("Rangers", 10, 5, Shirt{66, 42, 23}, true); 87 | std::cout << jsonExport(rangers) << "\n"; 88 | 89 | ... 90 | { 91 | "name": "Rangers", 92 | "score": 10, 93 | "damage": 5, 94 | "team: 95 | { 96 | "red": 66, 97 | "green": 42, 98 | "blue": 23 99 | }, 100 | "extension": true 101 | } 102 | ```` 103 | The only difference from a base type is that we use `ThorsAnvil_ExpandTrait()` rather than `ThorsAnvil_MakeTrait()`. The difference between these two is that `ThorsAnvil_ExpandTrait()` takes the parent class as the first parameter followed by the child type as the second parameter. 104 | 105 | #### Multiple Inheritance 106 | ````C++ 107 | struct Base1 108 | { 109 | }; 110 | struct Base2 111 | { 112 | }; 113 | struct Object: public Base1, public Base2 114 | { 115 | }; 116 | ThorsAnvil_MakeTrait(Base1); 117 | ThorsAnvil_MakeTrait(Base2); 118 | 119 | // The macro ThorsAnvil_ExpandTrait() only allows you to declare 1 base type name. 120 | // To get around this limitation you need place both base types into `Serialize::Parents<>` template. 121 | // This can then be used as the parent type in the macro ThorsAnvil_ExpandTrait() 122 | using Base1Base2Parent = ThorsAnvil::Serialize::Parents; 123 | ThorsAnvil_ExpandTrait(Object, Base1Base2Parent); 124 | ```` 125 | 126 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | run-name: ${{ github.actor }} Building 3 | on: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | # windows-latest 9 | # windows-2022 10 | # windows-2019 11 | # ubuntu-latest 12 | # ubuntu-22.04 13 | # ubuntu-20.04 14 | # ubuntu-18.04 15 | # macos-latest 16 | # macos-13 17 | # macos-12 18 | # macos-11 19 | Build_on_Mac: 20 | runs-on: macos-latest 21 | steps: 22 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install vera++ 23 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install magic_enum 24 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install snappy 25 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install libevent 26 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install boost 27 | - uses: actions/checkout@master 28 | with: 29 | submodules: recursive 30 | token: ${{ secrets.GITHUB_TOKEN }} 31 | - run: ./configure --disable-colour --disable-test-with-mongo-query --disable-Mongo-Service --disable-slacktest 32 | - run: make 33 | - run: make install 34 | Build_on_Linux: 35 | runs-on: ubuntu-22.04 36 | steps: 37 | - run: g++ --version 38 | - run: which g++ 39 | - run: sudo apt-get install vera++ 40 | - run: sudo apt-get install libsnappy-dev 41 | - run: sudo apt-get install libevent-dev 42 | - run: sudo apt-get install libsnappy-dev 43 | - run: sudo apt-get install libboost-all-dev 44 | - run: sudo apt-get update -y && sudo apt-get install lsb-release -y && sudo apt-get clean all 45 | - run: git clone https://github.com/Neargye/magic_enum.git /tmp/magic_enum 46 | - uses: actions/checkout@master 47 | with: 48 | submodules: recursive 49 | token: ${{ secrets.GITHUB_TOKEN }} 50 | - run: ./configure --enable-dark-mode --with-magicenum-header-only-root=/tmp/magic_enum/include/magic_enum --disable-test-with-mongo-query --disable-Mongo-Service --disable-slacktest 51 | - run: | 52 | cat Makefile.config 53 | cat third/ThorsStorage/Makefile.config 54 | cat third/ThorsStorage/src/ThorsStorage/Makefile 55 | - run: | 56 | cat third/Nisse/src/NisseHTTP/NisseHTTPConfig.h 57 | cat third/Nisse/src/NisseServer/NisseConfig.h 58 | cat third/Mug/src/ThorsMug/ThorsMugConfig.h 59 | cat third/ThorsSerializer/src/Serialize/SerializeConfig.h 60 | - run: make 61 | - run: sudo make install 62 | Build_on_Windows: 63 | runs-on: windows-latest 64 | steps: 65 | - run: git config --global core.autocrlf input 66 | - uses: actions/checkout@master 67 | with: 68 | submodules: recursive 69 | token: ${{ secrets.GITHUB_TOKEN }} 70 | - name: Install MSYS2 71 | uses: msys2/setup-msys2@v2 72 | with: 73 | install: >- 74 | autoconf 75 | automake 76 | make 77 | git 78 | gperf 79 | coreutils 80 | vim 81 | mingw-w64-x86_64-gcc 82 | mingw-w64-x86_64-gdb 83 | mingw-w64-x86_64-libyaml 84 | mingw-w64-x86_64-dlfcn 85 | mingw-w64-x86_64-snappy 86 | mingw-w64-x86_64-libevent 87 | mingw-w64-x86_64-boost 88 | cmake 89 | ninja 90 | - name: GetInfo 91 | shell: msys2 {0} 92 | run: | 93 | uname -a 94 | uname -s 95 | uname -s | sed 's/-.*//' 96 | - name: Clone Magic Enum 97 | shell: msys2 {0} 98 | run: git clone https://github.com/Neargye/magic_enum.git /tmp/magic_enum 99 | - uses: actions/checkout@master 100 | - name: Configure 101 | shell: msys2 {0} 102 | env: 103 | MSYS: winsymlinks:nativestrict 104 | run: ./configure --disable-colour --disable-vera --with-magicenum-header-only-root=/tmp/magic_enum/include/magic_enum --with-yaml-root=/mingw64/ --disable-test-with-locked-file --disable-test-with-mongo-query --disable-Mongo-Service --disable-slacktest 105 | - name: Make 106 | shell: msys2 {0} 107 | run: make 108 | Build_Header_Only_Version: 109 | runs-on: macos-latest 110 | #- if: github.ref == 'refs/heads/master' 111 | steps: 112 | - run: echo "Building Header Only" 113 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install vera++ 114 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install magic_enum 115 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install snappy 116 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install libevent 117 | - run: env HOMEBREW_NO_AUTO_UPDATE=1 brew install boost 118 | - uses: actions/checkout@master 119 | with: 120 | submodules: recursive 121 | token: ${{ secrets.GITHUB_TOKEN }} 122 | - run: ./configure --disable-colour --disable-test-with-mongo-query --disable-Mongo-Service --disable-slacktest 123 | - run: make header-only 124 | 125 | -------------------------------------------------------------------------------- /docSource/source/group/usageDeclarationsStructure.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | generate: false 4 | --- 5 | ````C++ 6 | // Shirt.h 7 | #include "ThorSerialize/Traits.h" 8 | struct Shirt 9 | { 10 | int red; 11 | int green; 12 | int blue; 13 | }; 14 | ThorsAnvil_MakeTrait(Shirt, red, green, blue); 15 | ```` 16 | ````C++ 17 | #include "ThorSerialize/JsonThor.h" 18 | #include "Shirt.h" 19 | 20 | using ThorsAnvil::Serialize::jsonExport; 21 | using ThorsAnvil::Serialize::jsonImport; 22 | 23 | int main() 24 | { 25 | Shirt shirt{10, 20, 45}; 26 | std::cout << jsonExport(shirt) << "\n"; 27 | } 28 | ... 29 | { 30 | "red": 10, 31 | "green": 20, 32 | "blue": 45 33 | } 34 | ```` 35 | In C++ structures are not serializable by default (but often have the appropriate stream operators defined). The advantage of ThorsSerializer library is that it adds a serialization feature to a class without altering the class in any way. This is achieved by building a `Serialization::Traits<>` type for your class. We will go into more detail on how this works in the implementation section. 36 | 37 | The easiest way to build the appropriate `Serialization::Traits<>` type is to use the macro `ThorsAnvil_MakeTrait()` naming the type and all members you want to serialize as part of the object. You simply need to include #include "ThorSerialize/Traits.h". 38 | 39 | #### Private Members 40 | ````C++ 41 | // TeamMember.h 42 | #include "Shirt.h" 43 | class TeamMember 44 | { 45 | std::string name; 46 | int score; 47 | int damage; 48 | Shirt team; 49 | public: 50 | TeamMember(std::string const& name, int score, int damage, Shirt const& team) 51 | : name(name) 52 | , score(score) 53 | , damage(damage) 54 | , team(team) 55 | {} 56 | // Define the trait as a friend to get accesses to private Members. 57 | friend class ThorsAnvil::Serialize::Traits; 58 | }; 59 | ThorsAnvil_MakeTrait(TeamMember, name, score, damage, team); 60 | ```` 61 | ````C++ 62 | #include "ThorSerialize/JsonThor.h" 63 | #include "TeamMember.h" 64 | 65 | using ThorsAnvil::Serialize::jsonExport; 66 | using ThorsAnvil::Serialize::jsonImport; 67 | 68 | int main() 69 | { 70 | TeamMember mark("mark", 10, 5, Shirt{66, 42, 23}); 71 | std::cout << jsonExport(mark) << "\n"; 72 | } 73 | ... 74 | { 75 | "name": "mark", 76 | "score": 10, 77 | "damage": 5, 78 | "team": 79 | { 80 | "red": 66, 81 | "green": 42, 82 | "blue": 23 83 | } 84 | } 85 | ```` 86 | If you have a class/struct were the members that need to be serialized are private then there is no automatic accesses for the ThorsSerializer library to these members. To give the library accesses your class must declare the `Serialization::Traits<>` type as a friend of the class. This will allow the class to directly accesses these members and both read/write them during the serialization/de-serialization processes. 87 | 88 | #### Inheritance 89 | ````C++ 90 | // ExtendedTeamMember.h 91 | #include "TeamMember.h" 92 | class ExtendedTeamMember: public TeamMember 93 | { 94 | bool extension; 95 | public: 96 | ExtendedTeamMember(std::string const& name, int score, int damage, Shirt const& team, bool ex) 97 | : TeamMember(name, score, damage, team) 98 | , extension(ex) 99 | {} 100 | friend class ThorsAnvil::Serialize::Traits; 101 | }; 102 | ThorsAnvil_ExpandTrait(TeamMember, ExtendedTeamMember, extension); 103 | ```` 104 | ````C++ 105 | #include "ThorSerialize/JsonThor.h" 106 | #include "ExtendedTeamMember.h" 107 | 108 | using ThorsAnvil::Serialize::jsonExport; 109 | using ThorsAnvil::Serialize::jsonImport; 110 | 111 | int main() 112 | { 113 | ExtendedTeamMember rangers("Rangers", 10, 5, Shirt{66, 42, 23}, true); 114 | std::cout << jsonExport(rangers) << "\n"; 115 | } 116 | ... 117 | { 118 | "name": "Rangers", 119 | "score": 10, 120 | "damage": 5, 121 | "team": 122 | { 123 | "red": 66, 124 | "green": 42, 125 | "blue": 23 126 | }, 127 | "extension": true 128 | } 129 | ```` 130 | The only difference from a base type is that we use `ThorsAnvil_ExpandTrait()` rather than `ThorsAnvil_MakeTrait()`. The difference between these two is that `ThorsAnvil_ExpandTrait()` takes the parent class as the first parameter followed by the child type as the second parameter. 131 | 132 | #### Multiple Inheritance 133 | ````C++ 134 | #include "ThorSerialize/JsonThor.h" 135 | #include "ThorSerialize/Traits.h" 136 | 137 | using ThorsAnvil::Serialize::jsonExport; 138 | using ThorsAnvil::Serialize::jsonImport; 139 | 140 | struct Base1 141 | { 142 | int data; 143 | }; 144 | struct Base2 145 | { 146 | std::string name; 147 | }; 148 | struct Object: public Base1, public Base2 149 | { 150 | bool good; 151 | }; 152 | ThorsAnvil_MakeTrait(Base1, data); 153 | ThorsAnvil_MakeTrait(Base2, name); 154 | 155 | // The macro ThorsAnvil_ExpandTrait() only allows you to declare 1 base type name. 156 | // To get around this limitation you need place both base types into `Serialize::Parents<>` template. 157 | // This can then be used as the parent type in the macro ThorsAnvil_ExpandTrait()␣ 158 | using Base1Base2Parent = ThorsAnvil::Serialize::Parents; 159 | ThorsAnvil_ExpandTrait(Base1Base2Parent, Object, good); 160 | 161 | int main() 162 | { 163 | Object object{12, "Test", true}; 164 | std::cout << jsonExport(object) << "\n"; 165 | } 166 | ... 167 | { 168 | "data": 12, 169 | "name": "Test", 170 | "good": true 171 | } 172 | ```` 173 | Multiple enheritance is a tiny bit of a hack. 174 | Multiple parent types must be combined using the template class `ThorsAnvil::Serialize::Parents` and then passed to the `ThorsAnvil_ExpandTrait()` macro as if that was the parent type. 175 | 176 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: Left 7 | AlignConsecutiveAssignments: 8 | Enabled: true 9 | AcrossEmptyLines: false 10 | AcrossComments: false 11 | AlignCompound: true 12 | AlignFunctionPointers: false 13 | PadOperators: true 14 | AlignConsecutiveBitFields: 15 | Enabled: false 16 | AcrossEmptyLines: false 17 | AcrossComments: false 18 | AlignCompound: false 19 | AlignFunctionPointers: false 20 | PadOperators: false 21 | AlignConsecutiveDeclarations: 22 | Enabled: true 23 | AcrossEmptyLines: false 24 | AcrossComments: false 25 | AlignCompound: false 26 | AlignFunctionPointers: false 27 | PadOperators: false 28 | AlignConsecutiveMacros: 29 | Enabled: false 30 | AcrossEmptyLines: false 31 | AcrossComments: false 32 | AlignCompound: false 33 | AlignFunctionPointers: false 34 | PadOperators: false 35 | AlignConsecutiveShortCaseStatements: 36 | Enabled: true 37 | AcrossEmptyLines: true 38 | AcrossComments: true 39 | AlignCaseColons: false 40 | AlignEscapedNewlines: Right 41 | AlignOperands: Align 42 | AlignTrailingComments: 43 | Kind: Always 44 | OverEmptyLines: 0 45 | AllowAllArgumentsOnNextLine: true 46 | AllowAllParametersOfDeclarationOnNextLine: true 47 | AllowBreakBeforeNoexceptSpecifier: Never 48 | AllowShortBlocksOnASingleLine: Always 49 | AllowShortCaseLabelsOnASingleLine: true 50 | AllowShortCompoundRequirementOnASingleLine: true 51 | AllowShortEnumsOnASingleLine: true 52 | AllowShortFunctionsOnASingleLine: All 53 | AllowShortIfStatementsOnASingleLine: WithoutElse 54 | AllowShortLambdasOnASingleLine: All 55 | AllowShortLoopsOnASingleLine: false 56 | AlwaysBreakAfterDefinitionReturnType: None 57 | AlwaysBreakAfterReturnType: None 58 | AlwaysBreakBeforeMultilineStrings: false 59 | AlwaysBreakTemplateDeclarations: Yes 60 | AttributeMacros: 61 | - __capability 62 | BinPackArguments: true 63 | BinPackParameters: false 64 | BitFieldColonSpacing: Both 65 | BraceWrapping: 66 | AfterCaseLabel: true 67 | AfterClass: true 68 | AfterControlStatement: MultiLine 69 | AfterEnum: false 70 | AfterExternBlock: true 71 | AfterFunction: false 72 | AfterNamespace: true 73 | AfterObjCDeclaration: false 74 | AfterStruct: true 75 | AfterUnion: true 76 | BeforeCatch: true 77 | BeforeElse: true 78 | BeforeLambdaBody: false 79 | BeforeWhile: true 80 | IndentBraces: false 81 | SplitEmptyFunction: false 82 | SplitEmptyRecord: true 83 | SplitEmptyNamespace: true 84 | BreakAdjacentStringLiterals: true 85 | BreakAfterAttributes: Leave 86 | BreakAfterJavaFieldAnnotations: false 87 | BreakArrays: false 88 | BreakBeforeBinaryOperators: None 89 | BreakBeforeConceptDeclarations: Always 90 | BreakBeforeBraces: Custom 91 | BreakBeforeInlineASMColon: OnlyMultiline 92 | BreakBeforeTernaryOperators: true 93 | BreakConstructorInitializers: BeforeComma 94 | BreakInheritanceList: AfterComma 95 | BreakStringLiterals: true 96 | ColumnLimit: 120 97 | CommentPragmas: '^ IWYU pragma:' 98 | CompactNamespaces: false 99 | ConstructorInitializerIndentWidth: 4 100 | ContinuationIndentWidth: 4 101 | Cpp11BracedListStyle: true 102 | DerivePointerAlignment: false 103 | DisableFormat: false 104 | EmptyLineAfterAccessModifier: Never 105 | EmptyLineBeforeAccessModifier: LogicalBlock 106 | ExperimentalAutoDetectBinPacking: false 107 | FixNamespaceComments: false 108 | ForEachMacros: 109 | - foreach 110 | - Q_FOREACH 111 | - BOOST_FOREACH 112 | IfMacros: 113 | - KJ_IF_MAYBE 114 | IncludeBlocks: Preserve 115 | IncludeCategories: 116 | - Regex: '^' 117 | Priority: 2 118 | SortPriority: 0 119 | CaseSensitive: false 120 | - Regex: '^<.*\.h>' 121 | Priority: 1 122 | SortPriority: 0 123 | CaseSensitive: false 124 | - Regex: '^<.*' 125 | Priority: 2 126 | SortPriority: 0 127 | CaseSensitive: false 128 | - Regex: '.*' 129 | Priority: 3 130 | SortPriority: 0 131 | CaseSensitive: false 132 | IncludeIsMainRegex: '([-_](test|unittest))?$' 133 | IncludeIsMainSourceRegex: '' 134 | IndentAccessModifiers: true 135 | IndentCaseBlocks: true 136 | IndentCaseLabels: true 137 | IndentExternBlock: AfterExternBlock 138 | IndentGotoLabels: true 139 | IndentPPDirectives: None 140 | IndentRequiresClause: true 141 | IndentWidth: 4 142 | IndentWrappedFunctionNames: false 143 | InsertBraces: false 144 | InsertNewlineAtEOF: false 145 | InsertTrailingCommas: None 146 | IntegerLiteralSeparator: 147 | Binary: 4 148 | BinaryMinDigits: 0 149 | Decimal: 3 150 | DecimalMinDigits: 0 151 | Hex: 0 152 | HexMinDigits: 4 153 | JavaScriptQuotes: Leave 154 | JavaScriptWrapImports: true 155 | KeepEmptyLinesAtTheStartOfBlocks: false 156 | KeepEmptyLinesAtEOF: false 157 | LambdaBodyIndentation: OuterScope 158 | LineEnding: DeriveLF 159 | MacroBlockBegin: '' 160 | MacroBlockEnd: '' 161 | MaxEmptyLinesToKeep: 3 162 | NamespaceIndentation: All 163 | ObjCBinPackProtocolList: Never 164 | ObjCBlockIndentWidth: 2 165 | ObjCBreakBeforeNestedBlockParam: true 166 | ObjCSpaceAfterProperty: false 167 | ObjCSpaceBeforeProtocolList: true 168 | PackConstructorInitializers: Never 169 | PenaltyBreakAssignment: 2 170 | PenaltyBreakBeforeFirstCallParameter: 1 171 | PenaltyBreakComment: 300 172 | PenaltyBreakFirstLessLess: 120 173 | PenaltyBreakOpenParenthesis: 0 174 | PenaltyBreakScopeResolution: 500 175 | PenaltyBreakString: 1000 176 | PenaltyBreakTemplateDeclaration: 10 177 | PenaltyExcessCharacter: 1000000 178 | PenaltyIndentedWhitespace: 0 179 | PenaltyReturnTypeOnItsOwnLine: 200 180 | PointerAlignment: Left 181 | PPIndentWidth: -1 182 | QualifierAlignment: Right 183 | RawStringFormats: 184 | - Language: Cpp 185 | Delimiters: 186 | - cc 187 | - CC 188 | - cpp 189 | - Cpp 190 | - CPP 191 | - 'c++' 192 | - 'C++' 193 | CanonicalDelimiter: '' 194 | BasedOnStyle: google 195 | - Language: TextProto 196 | Delimiters: 197 | - pb 198 | - PB 199 | - proto 200 | - PROTO 201 | EnclosingFunctions: 202 | - EqualsProto 203 | - EquivToProto 204 | - PARSE_PARTIAL_TEXT_PROTO 205 | - PARSE_TEST_PROTO 206 | - PARSE_TEXT_PROTO 207 | - ParseTextOrDie 208 | - ParseTextProtoOrDie 209 | - ParseTestProto 210 | - ParsePartialTestProto 211 | CanonicalDelimiter: pb 212 | BasedOnStyle: google 213 | ReferenceAlignment: Pointer 214 | ReflowComments: true 215 | RemoveBracesLLVM: false 216 | RemoveParentheses: Leave 217 | RemoveSemicolon: true 218 | RequiresClausePosition: OwnLine 219 | RequiresExpressionIndentation: OuterScope 220 | SeparateDefinitionBlocks: Leave 221 | ShortNamespaceLines: 1 222 | SkipMacroDefinitionBody: false 223 | SortIncludes: CaseSensitive 224 | SortJavaStaticImport: Before 225 | SortUsingDeclarations: LexicographicNumeric 226 | SpaceAfterCStyleCast: false 227 | SpaceAfterLogicalNot: false 228 | SpaceAfterTemplateKeyword: true 229 | SpaceAroundPointerQualifiers: Default 230 | SpaceBeforeAssignmentOperators: true 231 | SpaceBeforeCaseColon: false 232 | SpaceBeforeCpp11BracedList: false 233 | SpaceBeforeCtorInitializerColon: true 234 | SpaceBeforeInheritanceColon: false 235 | SpaceBeforeJsonColon: false 236 | SpaceBeforeParens: ControlStatements 237 | SpaceBeforeParensOptions: 238 | AfterControlStatements: true 239 | AfterForeachMacros: true 240 | AfterFunctionDefinitionName: false 241 | AfterFunctionDeclarationName: false 242 | AfterIfMacros: true 243 | AfterOverloadedOperator: false 244 | AfterPlacementOperator: true 245 | AfterRequiresInClause: false 246 | AfterRequiresInExpression: false 247 | BeforeNonEmptyParentheses: false 248 | SpaceBeforeRangeBasedForLoopColon: true 249 | SpaceBeforeSquareBrackets: false 250 | SpaceInEmptyBlock: false 251 | SpacesBeforeTrailingComments: 2 252 | SpacesInAngles: Never 253 | SpacesInContainerLiterals: false 254 | SpacesInLineCommentPrefix: 255 | Minimum: 1 256 | Maximum: -1 257 | SpacesInParens: Never 258 | SpacesInParensOptions: 259 | InCStyleCasts: false 260 | InConditionalStatements: false 261 | InEmptyParentheses: false 262 | Other: false 263 | SpacesInSquareBrackets: false 264 | Standard: Auto 265 | StatementAttributeLikeMacros: 266 | - Q_EMIT 267 | StatementMacros: 268 | - Q_UNUSED 269 | - QT_REQUIRE_VERSION 270 | TabWidth: 4 271 | UseTab: Never 272 | VerilogBreakBetweenInstancePorts: true 273 | WhitespaceSensitiveMacros: 274 | - BOOST_PP_STRINGIZE 275 | - CF_SWIFT_NAME 276 | - NS_SWIFT_NAME 277 | - PP_STRINGIZE 278 | - STRINGIZE 279 | ... 280 | 281 | -------------------------------------------------------------------------------- /doc/usage.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | 4 | ## Marking your class Serializable/Deserializable 5 | * Include the header file: `ThorSerialize/Traits.h` 6 | * Use one of these macros to declare your type as serializable 7 | * ThorsAnvil_MakeTrait(DataType, members...) 8 | * ThorsAnvil_ExpandTrait(ParentType, DataType, members...) 9 | * ThorsAnvil_Template_MakeTrait(TemplateParameterCount, DataType, members...) 10 | * ThorsAnvil_Template_ExpandTrait(TemplateParameterCount, ParentType, DataType, members...) 11 | * 12 | * ThorsAnvil_PointerAllocator(DataType, Action) 13 | * ThorsAnvil_MakeEnum(EnumType, EnumValues...) 14 | * 15 | * ThorsAnvil_PolyMorphicSerializer(Type) 16 | * ThorsAnvil_RegisterPolyMorphicType(Type) 17 | * 18 | * ThorsAnvil_MakeTraitCustomSerialize(Type, SerializableType) 19 | 20 | ```bash 21 | DataType: The name of a class (includeing namespace) of the type 22 | you want to be able to serialize at some point. 23 | ParentType: The name of a class that has previously been declared 24 | using `ThorsAnvil_MakeTrait` or `ThorsAnvil_ExpandTrait` 25 | and the parent of `Type` 26 | TemplateParamCount: If `Type` is a template type the number of parameters it needs 27 | so that it is fully generalized. 28 | members: A list of member (names) of the class `Type` that need 29 | to be serialized. 30 | EnumValues: A list of the enum values for the associated enum type. 31 | Action: A type that supports to static methods 32 | static DataType* alloc() // Called to default allocate an object. default new 33 | static void release(DataType*) // Called to release object. default delete 34 | SerializableType: A type used to serialize non standard (or complex types). 35 | This is specialized for each format type. 36 | See the documentation in Traits.h for details. 37 | ``` 38 | The two macros above build a template specialization of the class `ThorsAnvil::Serialize::Traits` specific to your class. As a consequence these macros should not be placed inside any namespace blocks. 39 | ```C++ 40 | #include "ThorSerialize/Traits.h" 41 | 42 | namespace MyNameSpace 43 | { 44 | class MyClass 45 | { 46 | public: 47 | int x; 48 | }; 49 | // This will fail as it is being used inside the `MyNameSpace` namespace 50 | ThorsAnvil_MakeTrait(MyClass, x); 51 | } 52 | 53 | // The correct location to use the macro is here 54 | ThorsAnvil_MakeTrait(MyNameSpace::MyClass, x); 55 | ``` 56 | 57 | ## Private Members 58 | If any members of the class that need to be serialized are private you must define a friendship to allow the `Traits` class to have access to the private members. 59 | ```C++ 60 | #include "ThorSerialize/Traits.h" 61 | 62 | namespace MyNameSpace 63 | { 64 | class MyClass 65 | { 66 | // Allow the traits class to access private members of your class. 67 | friend class ThorsAnvil::Serialize::Traits; 68 | double y; 69 | public: 70 | int x; 71 | 72 | }; 73 | } 74 | 75 | ThorsAnvil_MakeTrait(MyNameSpace::MyClass, x, y); 76 | ``` 77 | 78 | ## Standard containers 79 | The appropriate declarations for all the standard containers are provided. You simply need to include "ThorSerialize/SerUtil.h" to include these declarations. 80 | ```C++ 81 | #include "ThorSerialize/SerUtil.h" 82 | #include "ThorSerialize/JsonThor.h" 83 | #include 84 | #include 85 | 86 | int main() 87 | { 88 | using ThorsAnvil::Serialize::jsonExporter; 89 | using ThorsAnvil::Serialize::PrinterInterface; 90 | std::vector data {1,2,3,4,5}; 91 | std::cout << ThorsAnvil::Serialize::jsonExporter(data, PrinterInterface::OutputType::Stream); 92 | } 93 | ``` 94 | 95 | ## Serialization 96 | ### JSON 97 | * Include the header file "ThorSerialize/JsonThor.h". 98 | * There are two functions in the namespace `ThorsAnvil::Serialize`. 99 | * `jsonExporter(, characteristics = Default);` 100 | * `jsonImporter();` 101 | 102 | Both these methods return an object that simply contains a reference to `YourObject` (no actual serialization happens). When this object is serialized to a stream using `operator<<` or `operator>>` respectively then the code will read/write the appropriate members and serialize/de-serialize them to/from the stream. Because the returned object contains a reference to the object that needs to be serialized; the lifespan should be shorted than `YourObject` to avoid a dangling reference. Therefore it is usually best to just use them directly in the stream operation. 103 | 104 | ```C++ 105 | std::vector data{1,2,3,4,5,6}; 106 | 107 | std::cout << jsonExporter(data); 108 | std::cin >> jsonImporter(data); 109 | ``` 110 | 111 | On export there is a second parameter `characteristics` that allows some simple control on serialization (it basically affects white space to make debugging easier). Values are: 112 | ```bash 113 | Default: What ever the implementation likes. 114 | Currently this means `Config` but I have plans for an 115 | application level setting that is checked. 116 | Stream: Compressed for over the wire protocol. ie. No Space. 117 | Config: Human readable Potentially config file like. 118 | ``` 119 | 120 | ### YAML 121 | The description above is for JSON Serialization/De-serialization. But the exact same description can be used for YAML. Simply replace JSON with YAML and replace JSON with YAML. 122 | 123 | The export parameter `characteristics` has slightly different meaning for printing YAML. See the [libyaml documentation](http://libyaml.sourcearchive.com/documentation/0.1.1/group__styles_g1efef592e2e3df6f00432c04ef77d98f.html) for the meaning of these flags. 124 | ```bash 125 | Default: What ever the implementation likes. 126 | Currently this means YAML_BLOCK_MAPPING_STYLE but I have plans for an 127 | application level setting that is checked. 128 | Stream: YAML_FLOW_MAPPING_STYLE 129 | Config: YAML_BLOCK_MAPPING_STYLE 130 | ``` 131 | 132 | ### BSON 133 | The description above is for JSON Serialization/De-serialization. But the exact same description can be used for BSON versions. Simply replace JSON with BSON and replace JSON with BSON. 134 | 135 | The export parameter `characteristics` has no affect on binary. 136 | 137 | ## Notes on std::map (JSON) 138 | The JSON "Object" is a set of "name"/"value" pairs. But the name part is always a "String". If you use a `std::map` where the "Key" is a `std::string` then the `std::map<>` will be represented by a JSON "Object". If any other type is used as the "Key" then `std::map<>` will be represented as a JSON "Array" where each member of the array is `std::pair`. 139 | ```C++ 140 | // Example: 141 | int main() 142 | { 143 | std::map data1{{"M": 1}}; 144 | std::cout << jsonExporter(data1) << "\n"; // {"M":1} 145 | 146 | std::map data2{{15,2}}; 147 | std::cout << jsonExporter(data2) << "\n"; // [{"first":15, "second":2}] 148 | } 149 | ``` 150 | 151 | ## Strict Vs Weak Parsing. 152 | 153 | By default the parser is lenient. 154 | If it finds a "Key" that it does not recognize (or know how to decode) then it will ignore the "Value". This is controlled via the second parameter passed to the parser which defaults to "Weak" 155 | 156 | ```C++ 157 | using TS = ThorsAnvil::Serializer; 158 | using PT = TS::ParserInterface::ParseType; 159 | 160 | TS::JasonParser parser(stream, PT::Strict /* or Weak*/); 161 | TS::DeSerializeMember deSer(parser); 162 | 163 | T object; 164 | deSer.parse(object); 165 | 166 | // ----------- 167 | // Or Short hand 168 | 169 | T object; 170 | stream >> TS::jsonImporter(object, PT::Strict); 171 | ``` 172 | 173 | ## Strict Vs Exact Parsing. 174 | 175 | Strict parsing does not allow extra parameters in the JSON input. Exact parsing takes one further step in that all members in the object must be present in the JSON. If not all members are available then an exception is thrown. 176 | 177 | ```C++ 178 | using TS = ThorsAnvil::Serializer; 179 | using PT = TS::ParserInterface::ParseType; 180 | 181 | TS::JasonParser parser(stream, PT::Exact; 182 | TS::DeSerializeMember deSer(parser); 183 | 184 | T object; 185 | deSer.parse(object); 186 | 187 | // ----------- 188 | // Or Short hand 189 | 190 | T object; 191 | stream >> TS::jsonImporter(object, PT::Exact); // 192 | ``` 193 | -------------------------------------------------------------------------------- /docs/stylesheet/screen.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6,html,body{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size:14px}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{font-weight:bold}.content code,.content pre{font-family:Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;font-size:12px;line-height:1.5}.content code{word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}@font-face{font-family:'slate';src:url(../fonts/slate.eot?-syv14m);src:url(../fonts/slate.eot?#iefix-syv14m) format("embedded-opentype"),url(../fonts/slate.woff2?-syv14m) format("woff2"),url(../fonts/slate.woff?-syv14m) format("woff"),url(../fonts/slate.ttf?-syv14m) format("truetype"),url(../fonts/slate.svg?-syv14m#slate) format("svg");font-weight:normal;font-style:normal}.content aside.warning:before,.content aside.notice:before,.content aside.success:before,.toc-wrapper>.search:before{font-family:'slate';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1}.content aside.warning:before{content:"\e600"}.content aside.notice:before{content:"\e602"}.content aside.success:before{content:"\e606"}.toc-wrapper>.search:before{content:"\e607"}div.classTable{width:50%}div.classLayout{margin-left:28px;margin-right:5px;border:1px solid #E6E6E6}div.classBlock{display:table;width:100%;margin-bottom:5px}div.classRow{display:table-row;width:100%}div.classRow:nth-child(odd){background-color:#E6E6E6}div.classRow div{padding-left:3px;padding-right:3px}div.classItem{display:table-cell;min-width:25%;font-weight:bold}div.classValue{display:table-cell;max-width:75%}div.classDesc{padding-left:25px;width:100%}div.classSect{width:100%;font-weight:bold}div.methodRet{display:table-cell;text-align:right;padding-right:10px}div.methodName{display:table-cell}html,body{color:#333;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:#F3F7F9;height:100%;-webkit-text-size-adjust:none}#toc>ul>li>a>span{float:right;background-color:#2484FF;border-radius:40px;width:20px}.toc-wrapper{transition:left 0.3s ease-in-out;overflow-y:auto;overflow-x:hidden;position:fixed;z-index:30;top:0;left:0;bottom:0;width:230px;background-color:#2E3336;font-size:13px;font-weight:bold}.toc-wrapper .lang-selector{display:none}.toc-wrapper .lang-selector a{padding-top:0.5em;padding-bottom:0.5em}.toc-wrapper>img{display:block;max-width:100%}.toc-wrapper>.search{position:relative}.toc-wrapper>.search input{background:#2E3336;border-width:0 0 1px 0;border-color:#666;padding:6px 0 6px 20px;box-sizing:border-box;margin:10px 15px;width:200px;outline:none;color:#fff;border-radius:0}.toc-wrapper>.search:before{position:absolute;top:17px;left:15px;color:#fff}.toc-wrapper .logo{margin-bottom:0px}.toc-wrapper .search-results{margin-top:0;box-sizing:border-box;height:0;overflow-y:auto;overflow-x:hidden;transition-property:height, margin;transition-duration:180ms;transition-timing-function:ease-in-out;background:#1E2224}.toc-wrapper .search-results.visible{height:30%;margin-bottom:1em}.toc-wrapper .search-results li{margin:1em 15px;line-height:1}.toc-wrapper .search-results a{color:#fff;text-decoration:none}.toc-wrapper .search-results a:hover{text-decoration:underline}.toc-wrapper ul,.toc-wrapper li{list-style:none;margin:0;padding:0;line-height:28px}.toc-wrapper li{color:#fff;transition-property:background;transition-timing-function:linear;transition-duration:200ms}.toc-wrapper .toc-link.active{background-color:#0F75D4;color:#fff}.toc-wrapper .toc-link.active-parent{background-color:#1E2224;color:#fff}.toc-wrapper .toc-list-h2{display:none;background-color:#1E2224;font-weight:500}.toc-wrapper .toc-list-h3{display:none;background-color:#1E2224}.toc-wrapper .toc-h2{padding-left:25px;font-size:12px}.toc-wrapper .toc-h3{padding-left:35px;font-size:12px}.toc-wrapper .toc-footer{padding:1em 0;margin-top:1em;border-top:1px dashed #666}.toc-wrapper .toc-footer li,.toc-wrapper .toc-footer a{color:#fff;text-decoration:none}.toc-wrapper .toc-footer a:hover{text-decoration:underline}.toc-wrapper .toc-footer li{font-size:0.8em;line-height:1.7;text-decoration:none}.toc-link,.toc-footer li{padding:0 15px 0 15px;display:block;overflow-x:hidden;white-space:nowrap;text-overflow:ellipsis;text-decoration:none;color:#fff;transition-property:background;transition-timing-function:linear;transition-duration:130ms}#nav-button{padding:0 1.5em 5em 0;display:none;position:fixed;top:0;left:0;z-index:100;color:#000;text-decoration:none;font-weight:bold;opacity:0.7;line-height:16px;transition:left 0.3s ease-in-out}#nav-button span{display:block;padding:6px 6px 6px;background-color:rgba(243,247,249,0.7);transform-origin:0 0;transform:rotate(-90deg) translate(-100%, 0);border-radius:0 0 0 5px}#nav-button img{height:16px;vertical-align:bottom}#nav-button:hover{opacity:1}#nav-button.open{left:230px}.page-wrapper{margin-left:230px;position:relative;z-index:10;background-color:#F3F7F9;min-height:100%;padding-bottom:1px}.page-wrapper .dark-box{width:50%;background-color:#2E3336;position:absolute;right:0;top:0;bottom:0}.page-wrapper .lang-selector{position:fixed;z-index:50;border-bottom:5px solid #2E3336}.lang-selector{background-color:#1E2224;width:100%;font-weight:bold}.lang-selector a{display:block;float:left;color:#fff;text-decoration:none;padding:0 10px;line-height:30px;outline:0}.lang-selector a:active,.lang-selector a:focus{background-color:#111;color:#fff}.lang-selector a.active{background-color:#2E3336;color:#fff}.lang-selector:after{content:'';clear:both;display:block}.content{-webkit-transform:translateZ(0);position:relative;z-index:30}.content:after{content:'';display:block;clear:both}.content>h1,.content>h2,.content>h3,.content>h4,.content>h5,.content>h6,.content>p,.content>table,.content>ul,.content>ol,.content>aside,.content>dl{margin-right:50%;padding:0 28px;box-sizing:border-box;display:block}.content>ul,.content>ol{padding-left:43px}.content>.allowFloat{clear:none}.content>h1,.content>h2,.content>h3,.content>h4,.content>div{clear:both}.content h1{font-size:25px;padding-top:0.5em;padding-bottom:0.5em;margin-bottom:21px;margin-top:2em;border-top:1px solid #ccc;border-bottom:1px solid #ccc;background-color:#fdfdfd}.content h1:first-child,.content div:first-child+h1{border-top-width:0;margin-top:0}.content h2{font-size:19px;margin-top:4em;margin-bottom:0;border-top:1px solid #ccc;padding-top:1.2em;padding-bottom:1.2em;background-image:linear-gradient(to bottom, rgba(255,255,255,0.2), rgba(255,255,255,0))}.content h1+h2,.content h1+div+h2{margin-top:-21px;border-top:none}.content h3,.content h4,.content h5,.content h6{font-size:15px;margin-top:2.5em;margin-bottom:0.8em}.content hr{margin:2em 0;border-top:2px solid #2E3336;border-bottom:2px solid #F3F7F9}.content table{margin-bottom:1em;overflow:auto}.content table th,.content table td{text-align:left;vertical-align:top;line-height:1.6}.content table th{padding:5px 10px;border-bottom:1px solid #ccc;vertical-align:bottom}.content table td{padding:10px}.content table tr:last-child{border-bottom:1px solid #ccc}.content table tr:nth-child(odd)>td{background-color:white}.content table tr:nth-child(even)>td{background-color:#fbfcfd}.content dt{font-weight:bold}.content dd{margin-left:15px}.content p,.content li,.content dt,.content dd{line-height:1.6;margin-top:0}.content img{max-width:100%}.content code{background-color:rgba(0,0,0,0.05);padding:3px;border-radius:3px}.content pre>code{background-color:transparent;padding:0}.content aside{padding-top:1em;padding-bottom:1em;margin-top:1.5em;margin-bottom:1.5em;background:#8fbcd4;line-height:1.6}.content aside.warning{background-color:#c97a7e}.content aside.success{background-color:#6ac174}.content aside:before{vertical-align:middle;padding-right:0.5em;font-size:14px}.content .search-highlight{padding:2px;margin:-2px;border-radius:4px;border:1px solid #F7E633;background:linear-gradient(to top left, #F7E633 0%, #F1D32F 100%)}.content pre,.content blockquote{background-color:#1E2224;color:#fff;margin:0;width:50%;float:right;clear:right;box-sizing:border-box}.content pre>p,.content blockquote>p{margin:0}.content pre a,.content blockquote a{color:#fff;text-decoration:none;border-bottom:dashed 1px #ccc}.content pre{padding-top:2em;padding-bottom:2em;padding:2em 28px}.content blockquote>p{background-color:#191D1F;padding:13px 2em;color:#eee}@media (max-width: 930px){.toc-wrapper{left:-230px}.toc-wrapper.open{left:0}.page-wrapper{margin-left:0}#nav-button{display:block}.toc-link{padding-top:0.3em;padding-bottom:0.3em}}@media (max-width: 700px){.dark-box{display:none}.content>h1,.content>h2,.content>h3,.content>h4,.content>h5,.content>h6,.content>p,.content>table,.content>ul,.content>ol,.content>aside,.content>dl{margin-right:0}.toc-wrapper .lang-selector{display:block}.page-wrapper .lang-selector{display:none}.content pre,.content blockquote{width:auto;float:none}.content>pre+h1,.content>blockquote+h1,.content>pre+h2,.content>blockquote+h2,.content>pre+h3,.content>blockquote+h3,.content>pre+h4,.content>blockquote+h4,.content>pre+h5,.content>blockquote+h5,.content>pre+h6,.content>blockquote+h6,.content>pre+p,.content>blockquote+p,.content>pre+table,.content>blockquote+table,.content>pre+ul,.content>blockquote+ul,.content>pre+ol,.content>blockquote+ol,.content>pre+aside,.content>blockquote+aside,.content>pre+dl,.content>blockquote+dl{margin-top:28px}}.highlight .c,.highlight .cm,.highlight .c1,.highlight .cs{color:#909090}.highlight,.highlight .w{background-color:#1E2224} -------------------------------------------------------------------------------- /docs/javascripts/prism.js: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.15.0 2 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+c+bash+bison+cpp+json&plugins=line-numbers */ 3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-([\w-]+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(w instanceof s)){if(m&&b!=t.length-1){h.lastIndex=k;var _=h.exec(e);if(!_)break;for(var j=_.index+(d?_[1].length:0),P=_.index+_[0].length,A=b,x=k,O=t.length;O>A&&(P>x||!t[A].type&&!t[A-1].greedy);++A)x+=t[A].length,j>=x&&(++b,k=x);if(t[b]instanceof s)continue;I=A-b,w=e.slice(k,x),_.index-=k}else{h.lastIndex=0;var _=h.exec(w),I=1}if(_){d&&(p=_[1]?_[1].length:0);var j=_.index+p,_=_[0].slice(p),P=j+_.length,N=w.slice(0,j),S=w.slice(P),C=[b,I];N&&(++b,k+=N.length,C.push(N));var E=new s(u,f?n.tokenize(_,f):_,y,_,m);if(C.push(E),S&&C.push(S),Array.prototype.splice.apply(t,C),1!=I&&n.matchGrammar(e,t,r,b,k,!0,u),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join("");var l={type:e.type,content:r.stringify(e.content,t,a),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:a};if(e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+""},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 4 | Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; 5 | Prism.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(?:;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^{}\s][^{};]*?(?=\s*\{)/,string:{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.languages.css,Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\s\S]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css",greedy:!0}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag)); 6 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; 7 | Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},/\b(?:as|async|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/],number:/\b(?:(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+)n?|\d+n|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,"function":/[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\(|\.(?:apply|bind|call)\()/,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"},constant:/\b[A-Z][A-Z\d_]*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${[^}]+}|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\${[^}]+}/,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript; 8 | Prism.languages.c=Prism.languages.extend("clike",{keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*\/%&|^!=<>]=?/,number:/(?:\b0x[\da-f]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\]|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(?:<.+?>|("|')(?:\\?.)+?\2)/,lookbehind:!0},directive:{pattern:/(#\s*)\b(?:define|defined|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,lookbehind:!0,alias:"keyword"}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c["class-name"],delete Prism.languages.c["boolean"]; 9 | !function(e){var t={variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\([^)]+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},/\$(?:[\w#?*!@]+|\{[^}]+\})/i]};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<\s*)["']?(\w+?)["']?\s*\r?\n(?:[\s\S])*?\r?\n\2/,lookbehind:!0,greedy:!0,inside:t},{pattern:/(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/,greedy:!0,inside:t}],variable:t.variable,"function":{pattern:/(^|[\s;|&])(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|[\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&])(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|[\s;|&])/,lookbehind:!0},"boolean":{pattern:/(^|[\s;|&])(?:true|false)(?=$|[\s;|&])/,lookbehind:!0},operator:/&&?|\|\|?|==?|!=?|<<>|<=?|>=?|=~/,punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];]/};var a=t.variable[1].inside;a.string=e.languages.bash.string,a["function"]=e.languages.bash["function"],a.keyword=e.languages.bash.keyword,a["boolean"]=e.languages.bash["boolean"],a.operator=e.languages.bash.operator,a.punctuation=e.languages.bash.punctuation,e.languages.shell=e.languages.bash}(Prism); 10 | Prism.languages.bison=Prism.languages.extend("c",{}),Prism.languages.insertBefore("bison","comment",{bison:{pattern:/^[\s\S]*?%%[\s\S]*?%%/,inside:{c:{pattern:/%\{[\s\S]*?%\}|\{(?:\{[^}]*\}|[^{}])*\}/,inside:{delimiter:{pattern:/^%?\{|%?\}$/,alias:"punctuation"},"bison-variable":{pattern:/[$@](?:<[^\s>]+>)?[\w$]+/,alias:"variable",inside:{punctuation:/<|>/}},rest:Prism.languages.c}},comment:Prism.languages.c.comment,string:Prism.languages.c.string,property:/\S+(?=:)/,keyword:/%\w+/,number:{pattern:/(^|[^@])\b(?:0x[\da-f]+|\d+)/i,lookbehind:!0},punctuation:/%[%?]|[|:;\[\]<>]/}}}); 11 | Prism.languages.cpp=Prism.languages.extend("c",{keyword:/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(?:true|false)\b/,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*\/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),Prism.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)\w+/i,lookbehind:!0}}),Prism.languages.insertBefore("cpp","string",{"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}); 12 | Prism.languages.json={comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,property:{pattern:/"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,greedy:!0},string:{pattern:/"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,greedy:!0},number:/-?\d+\.?\d*(e[+-]?\d+)?/i,punctuation:/[{}[\],]/,operator:/:/,"boolean":/\b(?:true|false)\b/,"null":/\bnull\b/},Prism.languages.jsonp=Prism.languages.json; 13 | !function(){if("undefined"!=typeof self&&self.Prism&&self.document){var e="line-numbers",t=/\n(?!$)/g,n=function(e){var n=r(e),s=n["white-space"];if("pre-wrap"===s||"pre-line"===s){var l=e.querySelector("code"),i=e.querySelector(".line-numbers-rows"),a=e.querySelector(".line-numbers-sizer"),o=l.textContent.split(t);a||(a=document.createElement("span"),a.className="line-numbers-sizer",l.appendChild(a)),a.style.display="block",o.forEach(function(e,t){a.textContent=e||"\n";var n=a.getBoundingClientRect().height;i.children[t].style.height=n+"px"}),a.textContent="",a.style.display="none"}},r=function(e){return e?window.getComputedStyle?getComputedStyle(e):e.currentStyle||null:null};window.addEventListener("resize",function(){Array.prototype.forEach.call(document.querySelectorAll("pre."+e),n)}),Prism.hooks.add("complete",function(e){if(e.code){var r=e.element.parentNode,s=/\s*\bline-numbers\b\s*/;if(r&&/pre/i.test(r.nodeName)&&(s.test(r.className)||s.test(e.element.className))&&!e.element.querySelector(".line-numbers-rows")){s.test(e.element.className)&&(e.element.className=e.element.className.replace(s," ")),s.test(r.className)||(r.className+=" line-numbers");var l,i=e.code.match(t),a=i?i.length+1:1,o=new Array(a+1);o=o.join(""),l=document.createElement("span"),l.setAttribute("aria-hidden","true"),l.className="line-numbers-rows",l.innerHTML=o,r.hasAttribute("data-start")&&(r.style.counterReset="linenumber "+(parseInt(r.getAttribute("data-start"),10)-1)),e.element.appendChild(l),n(r),Prism.hooks.run("line-numbers",e)}}}),Prism.hooks.add("line-numbers",function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0}),Prism.plugins.lineNumbers={getLine:function(t,n){if("PRE"===t.tagName&&t.classList.contains(e)){var r=t.querySelector(".line-numbers-rows"),s=parseInt(t.getAttribute("data-start"),10)||1,l=s+(r.children.length-1);s>n&&(n=s),n>l&&(n=l);var i=n-s;return r.children[i]}}}}}(); 14 | -------------------------------------------------------------------------------- /doc/full.md: -------------------------------------------------------------------------------- 1 | ![ThorStream](../img/stream.jpg) 2 | 3 | ## Objective: 4 | 5 | The objective is to make serialization/de-serialization of C++ object to/from 6 | JSON/YAML/BSON trivial. 7 | 8 | This means: 9 | 1) does not build a JSON/YAML/BSON object. Reads data directly into C++ object. 10 | 2) In normal usage there should be NO need to write any code. 11 | 3) User should not need to understand JSON/YAML/BSON or validate its input. 12 | 4) Should work seamlessly with streams. 13 | 5) Standard containers should automatically work 14 | 15 | I am not concerned about speed. 16 | Though my trivial test work just fine in terms of speed. 17 | 18 | The design was done with the primary goal of communicating with WEB-Servers 19 | that speak JSON. The main envisioned usage was for mobile devices were many 20 | small JSON objects are transfered in both directions. 21 | 22 | ## Marking your class Serializable/Deserializable 23 | 24 | * Include the header file: `ThorSerialize/Traits.h` 25 | * Use one of these macros to declare your type as serializable 26 | * ThorsAnvil_MakeTrait(DataType, members...) 27 | * ThorsAnvil_ExpandTrait(ParentType, DataType, members...) 28 | * ThorsAnvil_Template_MakeTrait(TemplateParameterCount, DataType, members...) 29 | * ThorsAnvil_Template_ExpandTrait(TemplateParameterCount, ParentType, DataType, members...) 30 | * 31 | * ThorsAnvil_PointerAllocator(DataType, Action) 32 | * ThorsAnvil_MakeEnum(EnumType, EnumValues...) 33 | * 34 | * ThorsAnvil_PolyMorphicSerializer(Type) 35 | * ThorsAnvil_RegisterPolyMorphicType(Type) 36 | * 37 | * ThorsAnvil_MakeTraitCustomSerialize(Type, SerializableType) 38 | 39 | ```bash 40 | DataType: The name of a class (includeing namespace) of the type 41 | you want to be able to serialize at some point. 42 | ParentType: The name of a class that has previously been declared 43 | using `ThorsAnvil_MakeTrait` or `ThorsAnvil_ExpandTrait` 44 | and the parent of `Type` 45 | TemplateParamCount: If `Type` is a template type the number of parameters it needs 46 | so that it is fully generalized. 47 | members: A list of member (names) of the class `Type` that need 48 | to be serialized. 49 | EnumValues: A list of the enum values for the associated enum type. 50 | Action: A type that supports to static methods 51 | static DataType* alloc() // Called to default allocate an object. default new 52 | static void release(DataType*) // Called to release object. default delete 53 | SerializableType: A type used to serialize non standard (or complex types). 54 | This is specialized for each format type. 55 | See the documentation in Traits.h for details. 56 | ``` 57 | 58 | The two macros above build a template specialization of the class `ThorsAnvil::Serialize::Traits` specific to your class. As a consequence these macros should not be placed inside any namespace blocks. 59 | 60 | ```C++ 61 | #include "ThorSerialize/Traits.h" 62 | 63 | namespace MyNameSpace 64 | { 65 | class MyClass 66 | { 67 | public: 68 | int x; 69 | }; 70 | // This will fail as it is being used inside the `MyNameSpace` namespace 71 | ThorsAnvil_MakeTrait(MyClass, x); 72 | } 73 | 74 | // The correct location to use the macro is here 75 | ThorsAnvil_MakeTrait(MyNameSpace::MyClass, x); 76 | ``` 77 | 78 | ## Private Members 79 | If any members of the class that need to be serialized are private you must define a friendship to allow the `Traits` class to have access to the private members. 80 | 81 | ```C++ 82 | #include "ThorSerialize/Traits.h" 83 | 84 | namespace MyNameSpace 85 | { 86 | class MyClass 87 | { 88 | // Allow the traits class to access private members of your class. 89 | friend class ThorsAnvil::Serialize::Traits; 90 | double y; 91 | public: 92 | int x; 93 | 94 | }; 95 | } 96 | 97 | ThorsAnvil_MakeTrait(MyNameSpace::MyClass, x, y); 98 | ``` 99 | 100 | ## Standard containers 101 | The appropriate declarations for all the standard containers are provided. You simply need to include "ThorSerialize/SerUtil.h" to include these declarations. 102 | 103 | ```C++ 104 | #include "ThorSerialize/SerUtil.h" 105 | #include "ThorSerialize/JsonThor.h" 106 | #include 107 | #include 108 | 109 | int main() 110 | { 111 | using ThorsAnvil::Serialize::jsonExporter; 112 | using ThorsAnvil::Serialize::PrinterInterface; 113 | std::vector data {1,2,3,4,5}; 114 | std::cout << ThorsAnvil::Serialize::jsonExporter(data, PrinterInterface::OutputType::Stream); 115 | } 116 | ``` 117 | 118 | ## Serialization 119 | 120 | ### JSON 121 | * Include the header file "ThorSerialize/JsonThor.h". 122 | * There are two functions in the namespace `ThorsAnvil::Serialize`. 123 | * `jsonExporter(, characteristics = Default);` 124 | * `jsonImporter();` 125 | 126 | Both these methods return an object that simply contains a reference to `YourObject` (no actual serialization happens). When this object is serialized to a stream using `operator<<` or `operator>>` respectively then the code will read/write the appropriate members and serialize/de-serialize them to/from the stream. Because the returned object contains a reference to the object that needs to be serialized; the lifespan should be shorted than `YourObject` to avoid a dangling reference. Therefore it is usually best to just use them directly in the stream operation. 127 | 128 | ```C++ 129 | std::vector data{1,2,3,4,5,6}; 130 | 131 | std::cout << jsonExporter(data); 132 | std::cin >> jsonImporter(data); 133 | ``` 134 | 135 | On export there is a second parameter `characteristics` that allows some simple control on serialization (it basically affects white space to make debugging easier). Values are: 136 | ```bash 137 | Default: What ever the implementation likes. 138 | Currently this means `Config` but I have plans for an 139 | application level setting that is checked. 140 | Stream: Compressed for over the wire protocol. ie. No Space. 141 | Config: Human readable Potentially config file like. 142 | ``` 143 | 144 | ### YAML 145 | 146 | The description above is for JSON Serialization/De-serialization. But the exact same description can be used for YAML. Simply replace JSON with YAML and replace JSON with YAML. 147 | 148 | The export parameter `characteristics` has slightly different meaning for printing YAML. See the [libyaml documentation](http://libyaml.sourcearchive.com/documentation/0.1.1/group__styles_g1efef592e2e3df6f00432c04ef77d98f.html) for the meaning of these flags. 149 | ```bash 150 | Default: What ever the implementation likes. 151 | Currently this means YAML_BLOCK_MAPPING_STYLE but I have plans for an 152 | application level setting that is checked. 153 | Stream: YAML_FLOW_MAPPING_STYLE 154 | Config: YAML_BLOCK_MAPPING_STYLE 155 | ``` 156 | ### BSON 157 | 158 | The description above is for JSON Serialization/De-serialization. But the exact same description can be used for BSON versions. Simply replace JSON with BSON and replace JSON with binary. 159 | 160 | The export parameter `characteristics` has no affect on binary. 161 | 162 | ## Notes on std::map (JSON) 163 | 164 | The JSON "Object" is a set of "name"/"value" pairs. But the name part is always a "String". If you use a `std::map` where the "Key" is a `std::string` then the `std::map<>` will be represented by a JSON "Object". If any other type is used as the "Key" then `std::map<>` will be represented as a JSON "Array" where each member of the array is `std::pair`. 165 | 166 | ```C++ 167 | // Example: 168 | int main() 169 | { 170 | std::map data1{{"M": 1}}; 171 | std::cout << jsonExporter(data1) << "\n"; // {"M":1} 172 | 173 | std::map data2{{15,2}}; 174 | std::cout << jsonExporter(data2) << "\n"; // [{"first":15, "second":2}] 175 | } 176 | 177 | ## Strict Vs Weak Parsing. 178 | 179 | By defaul the parser is linient. 180 | If it finds a "Key" that it does not recognize (or know how to decode) then it will ignore the "Value". This is controlled via the second parameter passed to the parser which defaults to "Weak" 181 | 182 | ```C++ 183 | using TS = ThorsAnvil::Serializer; 184 | using PT = TS::ParserInterface::ParseType; 185 | 186 | TS::JasonParser parser(stream, PT::Strict /* or Weak*/); 187 | TS::DeSerializeMember deSer(parser); 188 | 189 | T object; 190 | deSer.parse(object); 191 | 192 | // ----------- 193 | // Or Short hand 194 | 195 | T object; 196 | stream >> TS::jsonImporter(object, PT::Strict); 197 | ``` 198 | ## Strict Vs Exact Parsing. 199 | 200 | Strict parsing does not allow extra parameters in the JSON input. Exact parsing takes one further step in that all members in the object must be present in the JSON. If not all members are available then an exception is thrown. 201 | 202 | ```C++ 203 | using TS = ThorsAnvil::Serializer; 204 | using PT = TS::ParserInterface::ParseType; 205 | 206 | TS::JasonParser parser(stream, PT::Exact; 207 | TS::DeSerializeMember deSer(parser); 208 | 209 | T object; 210 | deSer.parse(object); 211 | 212 | // ----------- 213 | // Or Short hand 214 | 215 | T object; 216 | stream >> TS::jsonImporter(object, PT::Exact); // 217 | ``` 218 | ## Example-0 [See doc/example0.cpp](example0.cpp) 219 | ```C++ 220 | #include 221 | #include 222 | #include "ThorSerialize/JsonThor.h" 223 | 224 | int main() 225 | { 226 | std::vector data; 227 | using ThorsAnvil::Serialize::jsonImporter; 228 | using ThorsAnvil::Serialize::jsonExporter; 229 | 230 | std::cin >> jsonImporter(data); 231 | std::cout << jsonExporter(data) << "\n"; 232 | } 233 | ``` 234 | 235 | ### Build and run 236 | ```bash 237 | > g++ -std=c++20 example0.cpp -lThorSerialize -lThorsLogging 238 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 239 | > echo "[1,2,3,4,5]" | ./a.out 240 | [ 1, 2, 3, 4, 5] 241 | > 242 | ``` 243 | ## Example-1 [See doc/example1.cpp](example1.cpp) 244 | 245 | ```C++ 246 | #include "ThorSerialize/Traits.h" 247 | #include "ThorSerialize/JsonThor.h" 248 | 249 | struct Shirt 250 | { 251 | int red; 252 | int green; 253 | int blue; 254 | }; 255 | class TeamMember 256 | { 257 | std::string name; 258 | int score; 259 | int damage; 260 | Shirt team; 261 | public: 262 | TeamMember(std::string const& name, int score, int damage, Shirt const& team) 263 | : name(name) 264 | , score(score) 265 | , damage(damage) 266 | , team(team) 267 | {} 268 | // Define the trait as a friend to get accesses to private 269 | // Members. 270 | friend class ThorsAnvil::Serialize::Traits; 271 | }; 272 | 273 | // Declare the traits. 274 | // Specifying what members need to be serialized. 275 | ThorsAnvil_MakeTrait(Shirt, red, green, blue); 276 | ThorsAnvil_MakeTrait(TeamMember, name, score, damage, team); 277 | 278 | int main() 279 | { 280 | using ThorsAnvil::Serialize::jsonExporter; 281 | 282 | TeamMember mark("mark", 10, 5, Shirt{255,0,0}); 283 | // Use the export function to serialize 284 | std::cout << jsonExporter(mark) << "\n"; 285 | } 286 | ``` 287 | 288 | ### Build and run 289 | ```bash 290 | > g++ -std=c++20 expample1.cpp -lThorSerialize -lThorsLogging 291 | > ./a.out 292 | { 293 | "name": "mark", 294 | "score": 10, 295 | "damage": 5, 296 | "team": 297 | { 298 | "red": 255, 299 | "green": 0, 300 | "blue": 0 301 | } 302 | } 303 | ``` 304 | ## Example-E [See doc/exampleE.cpp](exampleE.cpp) 305 | ```C++ 306 | #include 307 | #include 308 | #include "ThorSerialize/JsonThor.h" 309 | 310 | enum class EnumType : int { 311 | A, B, C 312 | }; 313 | 314 | struct MyStruct { 315 | EnumType e; 316 | std::string s; 317 | }; 318 | 319 | ThorsAnvil_MakeEnum(EnumType, A, B, C); 320 | ThorsAnvil_MakeTrait(MyStruct, e, s); 321 | 322 | int main() 323 | { 324 | using ThorsAnvil::Serialize::jsonImporter; 325 | using ThorsAnvil::Serialize::jsonExporter; 326 | 327 | MyStruct val {EnumType::A, "This string"}; 328 | std::cout << jsonExporter(val) << "\n"; 329 | } 330 | ``` 331 | 332 | ### Build and run 333 | ```bash 334 | > g++ -std=c++20 example0.cpp -lThorSerialize -lThorsLogging 335 | > # Note on mac you may need to add -I/opt/homebrew/include -L/opt/homebrew/lib/ on Mac's with M1 chip. 336 | > ./a.out 337 | { 338 | "e": "A", 339 | "s": "This string" 340 | } 341 | ``` 342 | ## Example-2: [see doc/example2.cpp](example2.cpp) 343 | 344 | ```C++ 345 | #include 346 | #include "ThorSerialize/Traits.h" 347 | #include "ThorSerialize/SerUtil.h" 348 | #include "ThorSerialize/JsonThor.h" 349 | 350 | /* A class that you want to serialize. */ 351 | class MyClass 352 | { 353 | int data1; 354 | float data2; 355 | std::string data3; 356 | public: 357 | MyClass(int data1, float data2, std::string const& data3) 358 | : data1(data1) 359 | , data2(data2) 360 | , data3(data3) 361 | {} 362 | 363 | // This is only required if the members are private. 364 | friend struct ThorsAnvil::Serialize::Traits; 365 | }; 366 | 367 | 368 | /* 369 | * Though there is no code involved, you do need to set up 370 | * this structure to tell the library what fields need to be serialized. 371 | * To do this use the macro: ThorsAnvil_MakeTrait() 372 | * Specifying your class, and a list of members to serialize. 373 | */ 374 | ThorsAnvil_MakeTrait(MyClass, data1, data2, data3); 375 | ``` 376 | 377 | This allows us to import and export object of the above class really easily. 378 | 379 | ```C++ 380 | int main() 381 | { 382 | using ThorsAnvil::Serialize::jsonExporter; 383 | using ThorsAnvil::Serialize::PrinterInterface; 384 | 385 | MyClass data {56, 23.456, "Hi there"}; 386 | 387 | 388 | // This generates a simple JSON Object (wordy) 389 | std::cout << "Version 1\n"; 390 | std::cout << jsonExporter(data) << "\n\n\n"; 391 | 392 | // This generates a compact JSON 393 | std::cout << "Version 2 (Stream)\n"; 394 | std::cout << jsonExporter(data, PrinterInterface::OutputType::Stream) << "\n\n\n"; 395 | 396 | // Standard containers work automatically. 397 | // As long as the type held by the container has had an appropriate 398 | // Traits declaration. 399 | std::vector vec(4, data); 400 | std::cout << "Vector\n"; 401 | std::cout << jsonExporter(vec) << "\n"; 402 | } 403 | ``` 404 | 405 | This generates: 406 | 407 | ```bash 408 | > g++ -std=c++20 -o example2 example2.cpp -lThorSerialize -lThorsLogging 409 | > ./example2 410 | Version 1 411 | 412 | { 413 | "data1": 56, 414 | "data2": 23.456, 415 | "data3": "Hi there" 416 | } 417 | 418 | 419 | Version 2 (Stream) 420 | {"data1":56,"data2":23.456,"data3":"Hi there"} 421 | 422 | 423 | Vector 424 | [ 425 | { 426 | "data1": 56, 427 | "data2": 23.456, 428 | "data3": "Hi there" 429 | }, 430 | { 431 | "data1": 56, 432 | "data2": 23.456, 433 | "data3": "Hi there" 434 | }, 435 | { 436 | "data1": 56, 437 | "data2": 23.456, 438 | "data3": "Hi there" 439 | }, 440 | { 441 | "data1": 56, 442 | "data2": 23.456, 443 | "data3": "Hi there" 444 | }] 445 | ``` 446 | ## Example-3: [see doc/example3.cpp](example3.cpp) 447 | The library handles polymorphic types via pointers. The only addition the developer needs to do is add the macro `ThorsAnvil_PolyMorphicSerializer()` into the class (as part of the public) 448 | 449 | ```C++ 450 | struct Vehicle 451 | { 452 | Vehicle(){} 453 | Vehicle(int speed) 454 | : speed(speed) 455 | {} 456 | virtual ~Vehicle() {} 457 | int speed; 458 | ThorsAnvil_PolyMorphicSerializer(Vehicle); 459 | }; 460 | struct Car: public Vehicle 461 | { 462 | Car(){} 463 | Car(int speed, std::string const& make) 464 | : Vehicle(speed) 465 | , make(make) 466 | {} 467 | std::string make; 468 | ThorsAnvil_PolyMorphicSerializer(Car); 469 | }; 470 | struct Bike: public Vehicle 471 | { 472 | Bike(){} 473 | Bike(int speed, int stroke) 474 | : Vehicle(speed) 475 | , stroke(stroke) 476 | {} 477 | int stroke; 478 | ThorsAnvil_PolyMorphicSerializer(Bike); 479 | }; 480 | ``` 481 | 482 | As per normal the class's must also be declared as serializable. 483 | ```C++ 484 | ThorsAnvil_MakeTrait(Vehicle, speed); 485 | ThorsAnvil_ExpandTrait(Vehicle, Car, make); 486 | ThorsAnvil_ExpandTrait(Vehicle, Bike, stroke); 487 | ``` 488 | 489 | The use cases for serialization/de-serialization are the same: 490 | ```C++ 491 | int main() 492 | { 493 | Vehicle* init = new Bike(15, 2); 494 | 495 | std::stringstream stream; 496 | stream << ThorsAnvil::Serialize::jsonExporter(init); 497 | std::cout << ThorsAnvil::Serialize::jsonExporter(init) << "\n\n"; 498 | 499 | Vehicle* result = nullptr; 500 | std::cout << ThorsAnvil::Serialize::jsonExporter(result) << "\n\n"; 501 | stream >> ThorsAnvil::Serialize::jsonImporter(result); 502 | 503 | std::cout << ThorsAnvil::Serialize::jsonExporter(result) << "\n\n"; 504 | } 505 | ``` 506 | 507 | The one difference from normal serialization is that it adds an extra member to the output class. The key `"__type"` is serialized as the first member of an object. When reading (De-Serializing) a stream the key `"__type"` must be the first member of the object (Otherwise you will get an exception). Notice a `nullptr` is serialized as `null` in JSON. 508 | 509 | ```bash 510 | > g++ -std=c++20 -o example3 example3.cpp -lThorSerialize -lThorsLogging 511 | > ./example3 512 | { 513 | "__type": "Bike", 514 | "speed": 15, 515 | "stroke": 2 516 | } 517 | 518 | null 519 | 520 | 521 | { 522 | "__type": "Bike", 523 | "speed": 15, 524 | "stroke": 2 525 | } 526 | ``` 527 | 528 | To make this work the `Traits` class for pointers generates a default `alloc()` method that simply calls new on the object (and assumes a default constructor). If you need a custom allocation methods you can specify your own custom one. 529 | 530 | ```C++ 531 | ThorsAnvil_PointerAllocator(Bike, [](){return new Bike(6,7);}); 532 | ``` 533 | 534 | # Install Instructions: 535 | ## From [Homebrew](https://brew.sh/) 536 | ```bash 537 | brew update 538 | brew install thors-mongo 539 | ``` 540 | 541 | #### What is installed: 542 | * `/usr/local/include/ThorsIOUtil/` 543 | * `/usr/local/include/ThorsLogging/` 544 | * `/usr/local/include/ThorSerialize/` 545 | * `/usr/local/include/ThorsStorage/` 546 | * `/usr/local/include/ThorsCrypto/` 547 | * `/usr/local/include/ThorsSocket/` 548 | * `/usr/local/include/ThorsMongo/` 549 | * `/usr/local/lib/libThorsLogging.so` 550 | * `/usr/local/lib/libThorSerialize.so` 551 | * `/usr/local/lib/libThorsStorage.so` 552 | * `/usr/local/lib/libThorsSocket.so` 553 | * `/usr/local/lib/libThorsMongo.so` 554 | * `/usr/local/share/man/man3/*` 555 | 556 | ## From [GitHub](https://github.com/Loki-Astari/ThorsSerializer) 557 | 558 | The basic script for installing everything is: 559 | 560 | ```bash 561 | > git clone https://github.com/Loki-Astari/ThorsSerializer.git 562 | > cd ThorsSerializer 563 | > ./configure --disable-binary 564 | > make 565 | > sudo make install 566 | ``` 567 | 568 | But installing everything requires a couple of extra libraries and some development tools. You may not need all these tools (try and use brew if you don't). 569 | 570 | ### YAML 571 | By default it also installs the YAML serialization library. Underneath this uses libyaml this must be install first. If you don't need YAML support then add `--disable-yaml` to the `configure` command above. 572 | 573 | ### Development 574 | 575 | If you want to submit "pull requests" you are going to need vera++. Vera++ is a style checker and is automatically run as part of the build processes. The build will fail if you don't adhere to the style requirements of the project (you must adhere to the style guide for a pull request to be accepted). 576 | 577 | If you are simply building for yourself you may not care about the style guide. In this case you can switch it off by adding `--disable-vera` to the `configure` command above. 578 | 579 | ### Description 580 | By default installation will be in `/usr/local/include` and `/usr/local/lib`. You can override this with the normal auto-tools defaults. Use `./configure --help` to get details. 581 | 582 | #### What is installed: 583 | * `/usr/local/include/ThorsIOUtil/` 584 | * `/usr/local/include/ThorsLogging/` 585 | * `/usr/local/include/ThorSerialize/` 586 | * `/usr/local/include/ThorsCrypto/` 587 | * `/usr/local/include/ThorsStorage/` 588 | * `/usr/local/include/ThorsSocket/` 589 | * `/usr/local/include/ThorsMongo/` 590 | * `/usr/local/lib/libThorsLogging.so` 591 | * `/usr/local/lib/libThorSerialize.so` 592 | * `/usr/local/lib/libThorsStorage.so` 593 | * `/usr/local/lib/libThorsSocket.so` 594 | * `/usr/local/lib/libThorsMongo.so` 595 | * `/usr/local/share/man/man3/*` 596 | 597 | Note: 598 | libThor.so is build using `-O3` and thus is fully optimized and debug symbols have been stripped. 599 | libThorD.so is build using `-g` and is useful for debugging purposes. 600 | 601 | 602 | ### What is Downloaded 603 | The configuration processes will download the generic makefiles (using git) from [ThorMaker](https://github.com/Loki-Astari/ThorMaker) which in turn will download and build [google's gtest](https://github.com/google/googletest) and [vera++](https://github.com/Loki-Astari/vera-plusplus) library that is used in running the unit tests. 604 | 605 | ## Requirements 606 | This library uses features from C++14 so you will need a compiler that supports this. The generic makefile also does code coverage tests so your compiler will also need to support a code coverage tool that has an interface similar to `gcov`. 607 | 608 | 609 | --------------------------------------------------------------------------------