[
  {
    "path": ".cmake-format.py",
    "content": "# ----------------------------------\r\n# Options affecting listfile parsing\r\n# ----------------------------------\r\nwith section(\"parse\"):\r\n\r\n  # Specify structure for custom cmake functions\r\n  additional_commands = { 'foo': { 'flags': ['BAR', 'BAZ'],\r\n             'kwargs': {'DEPENDS': '*', 'HEADERS': '*', 'SOURCES': '*'}}}\r\n\r\n  # Override configurations per-command where available\r\n  override_spec = {}\r\n\r\n  # Specify variable tags.\r\n  vartags = []\r\n\r\n  # Specify property tags.\r\n  proptags = []\r\n\r\n# -----------------------------\r\n# Options affecting formatting.\r\n# -----------------------------\r\nwith section(\"format\"):\r\n\r\n  # Disable formatting entirely, making cmake-format a no-op\r\n  disable = False\r\n\r\n  # How wide to allow formatted cmake files\r\n  line_width = 80\r\n\r\n  # How many spaces to tab for indent\r\n  tab_size = 2\r\n\r\n  # If true, lines are indented using tab characters (utf-8 0x09) instead of\r\n  # <tab_size> space characters (utf-8 0x20). In cases where the layout would\r\n  # require a fractional tab character, the behavior of the  fractional\r\n  # indentation is governed by <fractional_tab_policy>\r\n  use_tabchars = False\r\n\r\n  # If <use_tabchars> is True, then the value of this variable indicates how\r\n  # fractional indentions are handled during whitespace replacement. If set to\r\n  # 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set\r\n  # to `round-up` fractional indentation is replaced with a single tab character\r\n  # (utf-8 0x09) effectively shifting the column to the next tabstop\r\n  fractional_tab_policy = 'use-space'\r\n\r\n  # If an argument group contains more than this many sub-groups (parg or kwarg\r\n  # groups) then force it to a vertical layout.\r\n  max_subgroups_hwrap = 2\r\n\r\n  # If a positional argument group contains more than this many arguments, then\r\n  # force it to a vertical layout.\r\n  max_pargs_hwrap = 6\r\n\r\n  # If a cmdline positional group consumes more than this many lines without\r\n  # nesting, then invalidate the layout (and nest)\r\n  max_rows_cmdline = 2\r\n\r\n  # If true, separate flow control names from their parentheses with a space\r\n  separate_ctrl_name_with_space = False\r\n\r\n  # If true, separate function names from parentheses with a space\r\n  separate_fn_name_with_space = False\r\n\r\n  # If a statement is wrapped to more than one line, than dangle the closing\r\n  # parenthesis on its own line.\r\n  dangle_parens = False\r\n\r\n  # If the trailing parenthesis must be 'dangled' on its on line, then align it\r\n  # to this reference: `prefix`: the start of the statement,  `prefix-indent`:\r\n  # the start of the statement, plus one indentation  level, `child`: align to\r\n  # the column of the arguments\r\n  dangle_align = 'prefix'\r\n\r\n  # If the statement spelling length (including space and parenthesis) is\r\n  # smaller than this amount, then force reject nested layouts.\r\n  min_prefix_chars = 4\r\n\r\n  # If the statement spelling length (including space and parenthesis) is larger\r\n  # than the tab width by more than this amount, then force reject un-nested\r\n  # layouts.\r\n  max_prefix_chars = 10\r\n\r\n  # If a candidate layout is wrapped horizontally but it exceeds this many\r\n  # lines, then reject the layout.\r\n  max_lines_hwrap = 2\r\n\r\n  # What style line endings to use in the output.\r\n  line_ending = 'unix'\r\n\r\n  # Format command names consistently as 'lower' or 'upper' case\r\n  command_case = 'canonical'\r\n\r\n  # Format keywords consistently as 'lower' or 'upper' case\r\n  keyword_case = 'unchanged'\r\n\r\n  # A list of command names which should always be wrapped\r\n  always_wrap = []\r\n\r\n  # If true, the argument lists which are known to be sortable will be sorted\r\n  # lexicographicall\r\n  enable_sort = True\r\n\r\n  # If true, the parsers may infer whether or not an argument list is sortable\r\n  # (without annotation).\r\n  autosort = False\r\n\r\n  # By default, if cmake-format cannot successfully fit everything into the\r\n  # desired linewidth it will apply the last, most agressive attempt that it\r\n  # made. If this flag is True, however, cmake-format will print error, exit\r\n  # with non-zero status code, and write-out nothing\r\n  require_valid_layout = False\r\n\r\n  # A dictionary mapping layout nodes to a list of wrap decisions. See the\r\n  # documentation for more information.\r\n  layout_passes = {}\r\n\r\n# ------------------------------------------------\r\n# Options affecting comment reflow and formatting.\r\n# ------------------------------------------------\r\nwith section(\"markup\"):\r\n\r\n  # What character to use for bulleted lists\r\n  bullet_char = '*'\r\n\r\n  # What character to use as punctuation after numerals in an enumerated list\r\n  enum_char = '.'\r\n\r\n  # If comment markup is enabled, don't reflow the first comment block in each\r\n  # listfile. Use this to preserve formatting of your copyright/license\r\n  # statements.\r\n  first_comment_is_literal = False\r\n\r\n  # If comment markup is enabled, don't reflow any comment block which matches\r\n  # this (regex) pattern. Default is `None` (disabled).\r\n  literal_comment_pattern = None\r\n\r\n  # Regular expression to match preformat fences in comments default=\r\n  # ``r'^\\s*([`~]{3}[`~]*)(.*)$'``\r\n  fence_pattern = '^\\\\s*([`~]{3}[`~]*)(.*)$'\r\n\r\n  # Regular expression to match rulers in comments default=\r\n  # ``r'^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'``\r\n  ruler_pattern = '^\\\\s*[^\\\\w\\\\s]{3}.*[^\\\\w\\\\s]{3}$'\r\n\r\n  # If a comment line matches starts with this pattern then it is explicitly a\r\n  # trailing comment for the preceeding argument. Default is '#<'\r\n  explicit_trailing_pattern = '#<'\r\n\r\n  # If a comment line starts with at least this many consecutive hash\r\n  # characters, then don't lstrip() them off. This allows for lazy hash rulers\r\n  # where the first hash char is not separated by space\r\n  hashruler_min_length = 10\r\n\r\n  # If true, then insert a space between the first hash char and remaining hash\r\n  # chars in a hash ruler, and normalize its length to fill the column\r\n  canonicalize_hashrulers = True\r\n\r\n  # enable comment markup parsing and reflow\r\n  enable_markup = True\r\n\r\n# ----------------------------\r\n# Options affecting the linter\r\n# ----------------------------\r\nwith section(\"lint\"):\r\n\r\n  # a list of lint codes to disable\r\n  disabled_codes = []\r\n\r\n  # regular expression pattern describing valid function names\r\n  function_pattern = '[0-9a-z_]+'\r\n\r\n  # regular expression pattern describing valid macro names\r\n  macro_pattern = '[0-9A-Z_]+'\r\n\r\n  # regular expression pattern describing valid names for variables with global\r\n  # (cache) scope\r\n  global_var_pattern = '[A-Z][0-9A-Z_]+'\r\n\r\n  # regular expression pattern describing valid names for variables with global\r\n  # scope (but internal semantic)\r\n  internal_var_pattern = '_[A-Z][0-9A-Z_]+'\r\n\r\n  # regular expression pattern describing valid names for variables with local\r\n  # scope\r\n  local_var_pattern = '[a-z][a-z0-9_]+'\r\n\r\n  # regular expression pattern describing valid names for privatedirectory\r\n  # variables\r\n  private_var_pattern = '_[0-9a-z_]+'\r\n\r\n  # regular expression pattern describing valid names for public directory\r\n  # variables\r\n  public_var_pattern = '[A-Z][0-9A-Z_]+'\r\n\r\n  # regular expression pattern describing valid names for function/macro\r\n  # arguments and loop variables.\r\n  argument_var_pattern = '[a-z][a-z0-9_]+'\r\n\r\n  # regular expression pattern describing valid names for keywords used in\r\n  # functions or macros\r\n  keyword_pattern = '[A-Z][0-9A-Z_]+'\r\n\r\n  # In the heuristic for C0201, how many conditionals to match within a loop in\r\n  # before considering the loop a parser.\r\n  max_conditionals_custom_parser = 2\r\n\r\n  # Require at least this many newlines between statements\r\n  min_statement_spacing = 1\r\n\r\n  # Require no more than this many newlines between statements\r\n  max_statement_spacing = 2\r\n  max_returns = 6\r\n  max_branches = 12\r\n  max_arguments = 5\r\n  max_localvars = 15\r\n  max_statements = 50\r\n\r\n# -------------------------------\r\n# Options affecting file encoding\r\n# -------------------------------\r\nwith section(\"encode\"):\r\n\r\n  # If true, emit the unicode byte-order mark (BOM) at the start of the file\r\n  emit_byteorder_mark = False\r\n\r\n  # Specify the encoding of the input file. Defaults to utf-8\r\n  input_encoding = 'utf-8'\r\n\r\n  # Specify the encoding of the output file. Defaults to utf-8. Note that cmake\r\n  # only claims to support utf-8 so be careful when using anything else\r\n  output_encoding = 'utf-8'\r\n\r\n# -------------------------------------\r\n# Miscellaneous configurations options.\r\n# -------------------------------------\r\nwith section(\"misc\"):\r\n\r\n  # A dictionary containing any per-command configuration overrides. Currently\r\n  # only `command_case` is supported.\r\n  per_command = {}\r\n\r\n"
  },
  {
    "path": ".github/workflows/ccpp.yaml",
    "content": "name: C/C++ CI\n\non: [push, pull_request]\n\nenv:\n  VERBOSE: 1\n\njobs:\n  build_matrix:\n    strategy:\n      matrix:\n        config:\n          [\n            [windows-latest, x64-windows, OFF],\n            [macos-latest, x64-osx, ON],\n            [ubuntu-20.04, x64-linux, ON],\n          ]\n    runs-on: ${{ matrix.config[0] }}\n    steps:\n      - uses: actions/checkout@v1\n      - name: vcpkg build\n        uses: johnwason/vcpkg-action@v4\n        with:\n          pkgs: rapidjson catch2\n          triplet: ${{ matrix.config[1] }}\n          token: ${{ github.token }}\n      - name: configure\n        run: mkdir build && cd build && cmake -DSTATICJSON_ASAN=${{ matrix.config[2] }} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=${{ matrix.config[1] }} ..\n      - name: build\n        run: cmake --build build --config Debug\n      - name: test\n        run: cd build && ctest -V -C Debug\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n._*\nxcode/\n*.backup\n# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.appCMakeCache.txt\nCMakeFiles\nCMakeScripts\nMakefile\ncmake_install.cmake\ninstall_manifest.txt\nCTestTestfile.cmake\n\nrapidjson.tgz\nrapidjson*/\n\nbuild/\n.vscode/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\nsudo: required\ndist: trusty\nscript: \"sudo apt-get install -y cmake && cmake . && make && ctest -V\"\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.0)\nproject(StaticJSON)\n\noption(STATICJSON_ENABLE_TEST \"Enable building test for StaticJSON\" ON)\noption(STATICJSON_ASAN \"Enable address sanitizer on non-MSVC\" OFF)\n\nset(CMAKE_CXX_STANDARD_REQUIRED 0)\n\nif(NOT CMAKE_BUILD_TYPE)\n  set(CMAKE_BUILD_TYPE RelWithDebInfo)\nendif()\n\nif(MSVC)\n  add_compile_definitions(_CRT_SECURE_NO_WARNINGS=1)\nelse()\n  if(STATICJSON_ASAN)\n    add_compile_options(-fsanitize=address)\n    add_link_options(-fsanitize=address)\n  endif()\nendif()\n\nfind_path(RAPIDJSON_INCLUDE_DIR rapidjson/rapidjson.h)\n\nset(SOURCE_FILES src/staticjson.cpp)\nadd_library(staticjson ${SOURCE_FILES})\nset_property(TARGET staticjson PROPERTY CXX_STANDARD 11)\nadd_library(staticjson::staticjson ALIAS staticjson)\ntarget_include_directories(\n  staticjson\n  PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>\n         $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/autojsoncxx>\n         $<BUILD_INTERFACE:${RAPIDJSON_INCLUDE_DIR}>\n         $<INSTALL_INTERFACE:include>\n  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})\n\nif(STATICJSON_ENABLE_TEST)\n  set(TARGET test_staticjson)\n  file(GLOB SOURCES test/*.hpp test/*.cpp include/staticjson/*.hpp)\n  add_executable(${TARGET} ${SOURCES})\n  target_link_libraries(${TARGET} PRIVATE staticjson)\n  set_property(TARGET ${TARGET} PROPERTY CXX_STANDARD 17)\n\n  find_package(RapidJSON CONFIG REQUIRED)\n  target_link_libraries(${TARGET} PRIVATE rapidjson)\n  find_package(Catch2 CONFIG REQUIRED)\n  target_link_libraries(${TARGET} PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)\n\n  enable_testing()\n  add_test(\n    NAME ${TARGET}\n    COMMAND ${TARGET}\n    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test)\nendif()\n\ninclude(GNUInstallDirs)\n\ninstall(\n  TARGETS staticjson\n  EXPORT staticjson-targets\n  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}\n  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})\ninstall(DIRECTORY ${CMAKE_SOURCE_DIR}/include/staticjson\n        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\ninstall(\n  EXPORT staticjson-targets\n  FILE staticjson-targets.cmake\n  NAMESPACE staticjson::\n  DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/staticjson)\n\ninclude(CMakePackageConfigHelpers)\n\nconfigure_package_config_file(\n  ${CMAKE_SOURCE_DIR}/cmake/staticjson-config.cmake.in\n  ${CMAKE_BINARY_DIR}/cmake/staticjson-config.cmake\n  INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/staticjson)\n\ninstall(FILES ${CMAKE_BINARY_DIR}/cmake/staticjson-config.cmake\n        DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/staticjson)\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Siyuan Ren (netheril96@gmail.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# StaticJSON\n\nFast, direct and static typed parsing of JSON with C++.\n\n## Overview\n\nJSON is a popular format for data exchange. Reading and writing JSON in C++, however, is nontrivial. Even with the help of libraries, one still needs to write lots of boilerplate code, and it is extremely hard to guard against all possible errors, since JSON is dynamically typed while C++ employs static typing.\n\nMore importantly, manually writing such code is a violation of **DRY** principle. When manually written, the class definition, parsing and serialization code can easily become out of sync, leading to brittle code and subtle bugs.\n\n`StaticJSON` is an attempt to solve this problem by automating such process.\n\n## Usage\n\n`StaticJSON` requires a C++11 compiler.\n\n## Method 1: use [vcpkg](https://vcpkg.io)\n\nRun command `vcpkg install staticjson`, then in your `CMakeLists.txt`, add\n\n```cmake\n find_package(staticjson CONFIG REQUIRED)\n target_link_libraries(${YOUR_TARGET} PRIVATE staticjson::staticjson)\n```\n\n## Method 2: just build everything together\n\nJust drop the `include` and `src` directory into your own project and build along with other sources. It requires you to separately install [`rapidjson`](https://rapidjson.org).\n\n## Quick start\n\n### Builtin types\n\n```c++\n#include <staticjson/staticjson.hpp>\n\nint builtin_test() {\n    using namespace staticjson;\n    std::string a = to_json_string(std::vector<double>{1.0, 2.0, -3.1415});\n    std::string b = to_pretty_json_string(std::map<std::string, std::shared_ptr<std::list<bool>>>{});\n\n    std::vector<std::unordered_map<std::string, std::int64_t>> data;\n    const char* json_string = \"[{\\\" hello \\\": 535353, \\\" world \\\": 849},\"\n        \" {\\\" k \\\": -548343}]\";\n    assert(from_json_string(json_string, &data, nullptr));\n    assert(data.size() == 2);\n    assert(data[1][\" k \"] == -548343);\n\n    to_pretty_json_file(stdout, data);\n    return 0;\n}\n```\n\n### Register custom class types\n\nFor your own classes, you need to add some definitions first before you can use the `from_json` and `to_json` functions. There are two ways of doing this.\n\n#### Intrusive definition\n\nThis way requires you to implement a special method in the class prototyped `void staticjson_init(staticjson::ObjectHandler* h)`. Example definition\n\n```c++\nstruct Date\n{\n    int year, month, day;\n\n    void staticjson_init(ObjectHandler* h)\n    {\n        h->add_property(\"year\", &year);\n        h->add_property(\"month\", &month);\n        h->add_property(\"day\", &day);\n        h->set_flags(Flags::DisallowUnknownKey);\n    }\n};\n\nstruct BlockEvent\n{\n    std::uint64_t serial_number, admin_ID = 255;\n    Date date;\n    std::string description, details;\n\n    void staticjson_init(ObjectHandler* h)\n    {\n        h->add_property(\"serial_number\", &serial_number);\n        h->add_property(\"administrator ID\", &admin_ID, Flags::Optional);\n        h->add_property(\"date\", &date, Flags::Optional);\n        h->add_property(\"description\", &description, Flags::Optional);\n        h->add_property(\"details\", &details, Flags::Optional);\n    }\n};\n```\n\n### Non-intrusive definition\n\nThis requires you to overload a special function for your custom class. For example, the `Date` overload is written as\n\n```c++\nnamespace staticjson\n{\nvoid init(Date* d, ObjectHandler* h)\n{\n    h->add_property(\"year\", &d->year);\n    h->add_property(\"month\", &d->month);\n    h->add_property(\"day\", &d->day);\n    h->set_flags(Flags::DisallowUnknownKey);\n}\n}\n```\n\nYou may need to declare `staticjson::init` as a friend function in order to access private and protected members.\n\n### Register enumeration types\n\nExample\n\n```c++\nenum class CalendarType\n{\n    Gregorian,\n    Chinese,\n    Jewish,\n    Islam\n};\n\nSTATICJSON_DECLARE_ENUM(CalendarType,\n                        {\"Gregorian\", CalendarType::Gregorian},\n                        {\"Chinese\", CalendarType::Chinese},\n                        {\"Jewish\", CalendarType::Jewish},\n                        {\"Islam\", CalendarType::Islam})\n```\n\nThis will convert the enum type to/from strings, and signal error if the string is not in the list.\n\nNote that this macro must not be instantiated inside a namespace.\n\n## Custom conversion\n\nIf you want a type to be serialized in a different way, such as a custom `Date` object as an ISO8601 string or an arbitrary precision integer as a list of 32-bit integers, you can enable the custom conversion for the type. To do so, specialize the template class in namespace `staticjson`\n\n```c++\nnamespace staticjson\n{\ntemplate <>\nstruct Converter<Date>\n{\n    typedef std::string shadow_type; \n    // This typedef is a must. The shadow type is a C++ type \n    // that can be directly converted to and from JSON values.\n\n    static std::unique_ptr<ErrorBase> from_shadow(const shadow_type& shadow, Date& value)\n    {\n        bool success = value.parseISO8601(shadow);\n        if (success)\n            return nullptr;\n        return std::make_unique<CustomError>(\"Invalid ISO 8601 string\");\n    }\n\n    static void to_shadow(const Date& value, shadow_type& shadow)\n    {\n        shadow = value.toISO8601();\n    }\n};\n}\n\n```\n\n## Error handling\n\n`StaticJSON` strives not to let any mismatch between the C++ type specifications and the JSON object slip. It detects and reports all kinds of errors, including type mismatch, integer out of range, floating number precision loss, required fields missing, duplicate keys etc. Many of them can be tuned on or off. It also reports an stack trace in case of error (not actual C++ exception).\n\nThe third parameter of all `from_json` family of functions is a nullable pointer to `staticjson::ParseStatus` object. If present, the error information will be dumped into it. An example error message is\n\n```\nParsing failed at offset 1000 with error code 16:\nTerminate parsing due to Handler error.\n\nTraceback (last call first)\n* Type mismatch between expected type \"unsigned long long\" and actual type \"string\"\n* Error at object member with name \"serial_number\"\n* Error at array element at index 0\n* Error at object member with name \"dark_history\"\n* Error at array element at index 1\n```\n\n## List of builtin supported types\n\n* **Boolean types**: `bool`, `char`\n* **Integer types**: `int`, `unsigned int`, `long`, `unsigned long`, `long long`, `unsigned long long`\n* **Floating point types**: `float`, `double`\n* **String types**: `std::string`\n* **Array types**: `std::vector<•>`, `std::deque<•>`, `std::list<•>`, `std::array<•>`\n* **Nullable types**: `std::nullptr_t`, `std::unique_ptr<•>`, `std::shared_ptr<•>`\n* **Map types**: `std::{map, multimap, unordered_map, unordered_multimap}<std::string, •>`\n* **Tuple types**: `std::tuple<...>`\n\n## Dynamic typing\n\nIf you need occasional escape from the rigidity of C++'s static type system, but do not want complete dynamism, you can still find the middle ground in `StaticJSON`.\n\n* You can embed a `staticjson::Document` (alias of `rapidjson::Document`) in your class/struct, which allows static typing for some class members and dynamic typing for others. Note `Document` is already nullable so do not use a smart pointer to `Document`.\n* You can convert a `Document` or `Value` to and from a C++ type registered in `StaticJSON`. The functions are aptly named `from_json_value`, `from_json_document`, `to_json_value`, `to_json_document`.\n\n\n## Export as JSON Schema\n\nFunction `export_json_schema` allows you to export the validation rules used by `StaticJSON` as JSON schema. It can then be used in other languages to do the similar validation. Note the two rules are only approximate match, because certain rules cannot be expressed in JSON schema yet, and because some languages have different treatments of numbers from C++.\n\n## Misc\n\nThe project was originally named *autojsoncxx* and requires a code generator to run.\n"
  },
  {
    "path": "_clang-format",
    "content": "---\nLanguage:        Cpp\n# BasedOnStyle:  WebKit\nAccessModifierOffset: -4\nAlignAfterOpenBracket: true\nAlignEscapedNewlinesLeft: false\nAlignOperands:   false\nAlignTrailingComments: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: false\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLoopsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: All\nAlwaysBreakAfterDefinitionReturnType: false\nAlwaysBreakTemplateDeclarations: true\nAlwaysBreakBeforeMultilineStrings: false\nBreakBeforeBinaryOperators: All\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: true\nBinPackParameters: false\nBinPackArguments: false\nColumnLimit:     100\nConstructorInitializerAllOnOneLineOrOnePerLine: true\nConstructorInitializerIndentWidth: 4\nDerivePointerAlignment: false\nExperimentalAutoDetectBinPacking: false\nIndentCaseLabels: false\nIndentWrappedFunctionNames: false\nIndentFunctionDeclarationAfterType: false\nMaxEmptyLinesToKeep: 1\nKeepEmptyLinesAtTheStartOfBlocks: true\nNamespaceIndentation: Inner\nObjCBlockIndentWidth: 4\nObjCSpaceAfterProperty: true\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakBeforeFirstCallParameter: 19\nPenaltyBreakComment: 300\nPenaltyBreakString: 1000\nPenaltyBreakFirstLessLess: 120\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 60\nPointerAlignment: Left\nSpacesBeforeTrailingComments: 4\nCpp11BracedListStyle: true\nStandard:        Cpp11\nIndentWidth:     4\nTabWidth:        8\nUseTab:          Never\nBreakBeforeBraces: Allman\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nSpacesInAngles:  false\nSpaceInEmptyParentheses: false\nSpacesInCStyleCastParentheses: false\nSpaceAfterCStyleCast: false\nSpacesInContainerLiterals: true\nSpaceBeforeAssignmentOperators: true\nContinuationIndentWidth: 4\nCommentPragmas:  '^ IWYU pragma:'\nForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]\nSpaceBeforeParens: ControlStatements\nDisableFormat:   false\nFixNamespaceComments: false\n...\n\n"
  },
  {
    "path": "autojsoncxx/autojsoncxx.hpp",
    "content": "#pragma once\n\n#include <cstdio>\n#include <staticjson/staticjson.hpp>\n#include <string>\n\nnamespace autojsoncxx\n{\nusing ParsingResult = staticjson::ParseStatus;\n\nusing staticjson::to_json_file;\nusing staticjson::to_json_string;\nusing staticjson::to_pretty_json_file;\nusing staticjson::to_pretty_json_string;\n\nnamespace error = staticjson::error;\n\ntemplate <class ValueType>\ninline void to_json_string(std::string& output, const ValueType& value)\n{\n    output = to_json_string(value);\n}\n\ntemplate <class ValueType>\ninline void to_pretty_json_string(std::string& output, const ValueType& value)\n{\n    output = to_pretty_json_string(value);\n}\n\ntemplate <class ValueType>\ninline bool from_json_string(const char* str, ValueType& value, ParsingResult& err)\n{\n    return staticjson::from_json_string(str, &value, &err);\n}\n\ntemplate <class ValueType>\ninline bool from_json_string(const std::string& str, ValueType& value, ParsingResult& err)\n{\n    return staticjson::from_json_string(str.c_str(), &value, &err);\n}\n\ntemplate <class ValueType>\ninline bool from_json_file(const char* str, ValueType& value, ParsingResult& err)\n{\n    return staticjson::from_json_file(str, &value, &err);\n}\n\ntemplate <class ValueType>\ninline bool from_json_file(const std::string& str, ValueType& value, ParsingResult& err)\n{\n    return staticjson::from_json_file(str, &value, &err);\n}\n\ntemplate <class ValueType>\ninline bool from_json_file(std::FILE* fp, ValueType& value, ParsingResult& err)\n{\n    return staticjson::from_json_file(fp, &value, &err);\n}\n\ntemplate <class T>\nvoid to_document(const T& value, rapidjson::Document& doc)\n{\n    staticjson::to_json_document(&doc, value, nullptr);\n}\n\ntemplate <class T>\nbool from_document(T& value, const rapidjson::Document& doc, error::ErrorStack& errs)\n{\n    staticjson::ParseStatus status;\n    bool rc = staticjson::from_json_document(doc, &value, &status);\n    if (status.has_error())\n        errs.swap(status.error_stack());\n    return rc;\n}\n}\n"
  },
  {
    "path": "autojsoncxx/autojsoncxx.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n# The MIT License (MIT)\n#\n# Copyright (c) 2014 Siyuan Ren (netheril96@gmail.com)\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n\"\"\"\nThis script allows easier transition from StaticJSON's precursor `autojsoncxx`.\n\nGenerates compatible C++ header files using StaticJSON's library.\n\"\"\"\n\nfrom __future__ import unicode_literals\nfrom __future__ import print_function\n\nimport re\nimport argparse\nimport os\nimport string\nimport sys\nimport io\nfrom numbers import Number\n\n\n# Python 2/3 compatibility layer\nis_python2 = sys.version_info.major == 2\nif is_python2:\n    str = unicode\n\n# simplejson has the same interface as the standard json module, but with better error messages\ntry:\n    import simplejson as json\nexcept ImportError:\n    import json\n\n\n# base class for all custom exceptions in this unit\nclass InvalidDefinitionError(Exception):\n    pass\n\n\nclass InvalidIdentifier(InvalidDefinitionError):\n    def __init__(self, identifier):\n        self.identifier = identifier\n\n    def __str__(self):\n        return \"Invalid string for C++ identifier: \" + repr(self.identifier)\n\n\nclass InvalidNamespace(InvalidDefinitionError):\n    def __init__(self, namespace):\n        self.namespace = namespace\n\n    def __str__(self):\n        return \"Invalid namespace: \" + repr(self.namespace)\n\n\nclass UnrecognizedOption(InvalidDefinitionError):\n    def __init__(self, option):\n        self.option = option\n\n    def __str__(self):\n        return \"Unrecognized option: \" + repr(self.option)\n\n\nclass UnsupportedTypeError(InvalidDefinitionError):\n    def __init__(self, type_name):\n        self.type_name = type_name\n\n    def __str__(self):\n        return \"Unsupported C++ type: \" + repr(self.type_name)\n\n\nNOESCAPE_CHARACTERS = bytes(string.digits + string.ascii_letters + ' ', encoding='utf8')\n\n\ndef cstring_literal(byte_string):\n    \"\"\"convert arbitrary byte sequence into a C++ string literal by escaping every character\"\"\"\n    if all(c in NOESCAPE_CHARACTERS for c in byte_string):\n        return '\"' + byte_string.decode() + '\"'\n    return '\"' + ''.join('\\\\x{:02x}'.format(ord(char)) for char in byte_string) + '\"'\n\n\ndef check_identifier(identifier):\n    if not re.match(r'^[A-Za-z_]\\w*$', identifier):\n        raise InvalidIdentifier(identifier)\n\n\nclass ClassInfo(object):\n    accept_options = {\"name\", \"namespace\", \"parse_mode\", \"members\", \"constructor_code\", \"comment\", \"no_duplicates\"}\n\n    def __init__(self, record):\n        self._name = record['name']\n        self._members = [MemberInfo(r) for r in record['members']]\n        self._strict = record.get('parse_mode', '') == 'strict'\n        self._namespace = record.get(\"namespace\", None)\n        self._constructor_code = record.get(\"constructor_code\", \"\")\n        self._no_duplicates = record.get(\"no_duplicates\", False)\n\n        check_identifier(self._name)\n\n        if self._namespace is not None and not re.match(r'^(?:::)?[A-Za-z_]\\w*(?:::[A-Za-z_]\\w*)*$', self._namespace):\n            raise InvalidNamespace(self._namespace)\n\n        for op in record:\n            if op not in ClassInfo.accept_options:\n                raise UnrecognizedOption(op)\n\n    @property\n    def name(self):\n        return self._name\n\n    @property\n    def qualified_name(self):\n        if self.namespace is None:\n            return '::' + self.name\n        if self.namespace.startswith('::'):\n            return self.namespace + '::' + self.name\n        return '::' + self.namespace + '::' + self.name\n\n    @property\n    def members(self):\n        return self._members\n\n    @property\n    def strict_parsing(self):\n        return self._strict\n\n    @property\n    def namespace(self):\n        return self._namespace\n\n    @property\n    def constructor_code(self):\n        return self._constructor_code\n\n    @property\n    def no_duplicates(self):\n        return self._no_duplicates\n\n\nclass ClassDefinitionCodeGenerator(object):\n    def __init__(self, class_info):\n        self._class_info = class_info\n\n    @property\n    def class_info(self):\n        return self._class_info\n\n    def member_declarations(self):\n        return '\\n'.join(m.type_name + ' ' + m.variable_name + ';' for m in self.class_info.members)\n\n    def initializer_list(self):\n        return ', '.join('{0}({1})'.format(m.variable_name, m.constructor_args) for m in self.class_info.members)\n\n    def constructor(self):\n        return 'explicit {name}():{init} {{ {code} }}\\n'.format(name=self.class_info.name,\n                                                                init=self.initializer_list(),\n                                                                code=self.class_info.constructor_code)\n\n    def staticjson_init(self):\n        class_flags = 'staticjson::Flags::Default'\n        if not self.class_info.no_duplicates:\n            class_flags += ' | staticjson::Flags::AllowDuplicateKey'\n        if self.class_info.strict_parsing:\n            class_flags += ' | staticjson::Flags::DisallowUnknownKey'\n\n        return \"\"\"\n            void staticjson_init(staticjson::ObjectHandler* h) {{\n                {member_flag_settings}\n                h->set_flags({class_flags});\n             }}\n         \"\"\".format(\n            class_flags=class_flags,\n            member_flag_settings=''.join(m.add_property_statement('h') for m in self.class_info.members)\n        )\n\n    def class_definition(self):\n        class_def = 'struct {name} {{\\n {declarations}\\n\\n{constructor}\\n{staticjson_init}\\n \\n}};' \\\n            .format(name=self.class_info.name, declarations=self.member_declarations(),\n                    constructor=self.constructor(),\n                    staticjson_init=self.staticjson_init())\n\n        if self.class_info.namespace is not None:\n            for space in reversed(self.class_info.namespace.split('::')):\n                if space:\n                    class_def = 'namespace {} {{ {} }}\\n'.format(space, class_def)\n        return class_def\n\n\nclass MemberInfo(object):\n    accept_options = {'default', 'required', 'json_key', 'comment'}\n\n    def __init__(self, record):\n        self._record = record\n\n        if '*' in self.type_name or '&' in self.type_name:\n            raise UnsupportedTypeError(self.type_name)\n\n        check_identifier(self.variable_name)\n\n        if len(record) > 3:\n            raise UnrecognizedOption(record[3:])\n\n        if len(record) == 3:\n            for op in record[2]:\n                if op not in MemberInfo.accept_options:\n                    raise UnrecognizedOption(op)\n\n    @property\n    def type_name(self):\n        return self._record[0]\n\n    @property\n    def variable_name(self):\n        return self._record[1]\n\n    @property\n    def json_key(self):\n        try:\n            return self._record[2]['json_key'].encode('utf-8')\n        except (IndexError, KeyError):\n            return self.variable_name.encode('utf-8')\n\n    @property\n    def is_required(self):\n        try:\n            return self._record[2]['required']\n        except (IndexError, KeyError):\n            return False\n\n    @property\n    def default(self):\n        try:\n            return self._record[2]['default']\n        except (IndexError, KeyError):\n            return None\n\n    @property\n    def constructor_args(self):\n        return MemberInfo.cpp_repr(self.default)\n\n    def add_property_statement(self, handler_name):\n        return '{}->add_property({}, &this->{}, {});\\n'.format(\n            handler_name, cstring_literal(self.json_key), self.variable_name,\n            'staticjson::Flags::Default' if self.is_required else 'staticjson::Flags::Optional')\n\n    @staticmethod\n    def cpp_repr(args):\n        if args is None:\n            return ''\n        elif args is True:\n            return 'true'\n        elif args is False:\n            return 'false'\n        elif isinstance(args, str):\n            return cstring_literal(args.encode('utf-8'))\n        elif isinstance(args, Number):\n            return str(args)\n        elif isinstance(args, bytes):\n            return cstring_literal(args)\n        else:\n            raise UnrecognizedOption(\"default=\" + repr(args))\n\n\ndef read_utf8(filename):\n    with io.open(filename, 'rt', encoding='utf-8') as f:\n        text = f.read()\n    if text.startswith(u'\\ufeff'): # Skip BOM\n        text = text[1:]\n    return text\n\n\ndef main():\n    parser = argparse.ArgumentParser(description='`autojsoncxx` code generator (compatibility mode)\\n'\n                                                 '(visit https://github.com/netheril96/StaticJSON for details)')\n\n    parser.add_argument('-c', '--check', help='Compatibility flag; does nothing',\n                        action='store_true', default=False)\n    parser.add_argument('-i', '--input', help='input name for the definition file for classes', required=True)\n    parser.add_argument('-o', '--output', help='output name for the header file', default=None)\n    parser.add_argument('--template', help='Compatibility flag; does nothing', default=None)\n    args = parser.parse_args()\n\n    if args.output is None:\n        args.output = os.path.basename(args.input)\n        args.output = os.path.splitext(args.output)[0] + '.hpp'\n\n    raw_record = json.loads(read_utf8(args.input))\n\n    with io.open(args.output, 'w', encoding='utf-8') as output:\n        output.write('#pragma once\\n\\n')\n\n        def output_class(class_record):\n            output.write(ClassDefinitionCodeGenerator(ClassInfo(class_record)).class_definition())\n            output.write('\\n\\n')\n\n        if isinstance(raw_record, list):\n            for r in raw_record:\n                output_class(r)\n        else:\n            output_class(raw_record)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "autojsoncxx/examples/failure/duplicate_key.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\",\n            \"note\": \"the duplicate key error only occurs if your map types does not support duplicate key, e.g. `std::map`\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/failure/duplicate_key_user.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n\t\"ID\": 3399510046441,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/failure/hard.json",
    "content": "[{\"serial_number\": 90049710466114, \"details\": \"unknown\"}, -65535, null, 2.718281828459045, {\"Second\": {\"ID\": 13478355757133566847, \"optional_attributes\": {\"Open ID\": \"something@somewhere.com\", \"Self description\": \"Can you handle characters above Basic Multilingual Plane?\\ud83d\\ude04\\ud83c\\udf85 \\ud83c\\udf81\\ud83d\\udc31\\u2708\\ufe0f\\ud83d\\udc18\\ud83d\\udd22\\ud840\\udc46\\ud841\\udf7b\\ud844\\udfa6\\ud844\\udf20\", \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"}, \"block_event\": null, \"Third\": null, \"dark_history\": [{\"date\": {\"month\": 3, \"day\": 8, \"year\": 2013}, \"serial_number\": 11932018656737597978, \"details\": null, \"administrator ID\": 8027685536805674999, \"description\": \"copyright infringement\"}], \"birthday\": {\"month\": 1, \"day\": 23, \"year\": 2001}, \"nickname\": \"\\u2192\\u261b\\u2205\\u2206\\u2135\"}, \"First\": {\"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\", \"ID\": 7947402710862746952, \"nickname\": \"bigger than bigger\", \"birthday\": {\"month\": 9, \"day\": 2, \"year\": 1984}, \"block_event\": {\"date\": {\"month\": 12, \"day\": 31, \"year\": 1970}, \"serial_number\": 9097588792683265916, \"details\": \"most likely a troll\", \"administrator ID\": 10720293540521355122, \"description\": \"advertisement\"}}}, false]\n\n"
  },
  {
    "path": "autojsoncxx/examples/failure/integer_string.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": \"0xa5970bbff02d9a1a\",\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/failure/map_element_mismatch.json",
    "content": "{\n\"First\":    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n\"Second\": {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    },\n\"Third\": false\n}\n"
  },
  {
    "path": "autojsoncxx/examples/failure/missing_required.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        }\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/failure/null_in_key.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\\u0000 I am invisible because I am behind a null\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/failure/out_of_range.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 162751169614016163\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/failure/single_object.json",
    "content": "\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        }\n    }\n"
  },
  {
    "path": "autojsoncxx/examples/failure/unknown_field.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31,\n                \"hour\": 21,\n                \"minute\": 33,\n                \"second\": 2\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        }\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/success/hard.json",
    "content": "[{\"serial_number\": 90049710466114, \"details\": \"unknown\"}, -65535, null, 2.718281828459045, {\"Second\": {\"ID\": 13478355757133566847, \"optional_attributes\": {\"Open ID\": \"something@somewhere.com\", \"Self description\": \"Can you handle characters above Basic Multilingual Plane?\\ud83d\\ude04\\ud83c\\udf85 \\ud83c\\udf81\\ud83d\\udc31\\u2708\\ufe0f\\ud83d\\udc18\\ud83d\\udd22\\ud840\\udc46\\ud841\\udf7b\\ud844\\udfa6\\ud844\\udf20\", \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"}, \"block_event\": null, \"Third\": null, \"dark_history\": [{\"date\": {\"month\": 3, \"day\": 8, \"year\": 2013}, \"serial_number\": 11932018656737597978, \"details\": \"\", \"administrator ID\": 8027685536805674999, \"description\": \"copyright infringement\"}], \"birthday\": {\"month\": 1, \"day\": 23, \"year\": 2001}, \"nickname\": \"\\u2192\\u261b\\u2205\\u2206\\u2135\"}, \"First\": {\"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\", \"ID\": 7947402710862746952, \"nickname\": \"bigger than bigger\", \"birthday\": {\"month\": 9, \"day\": 2, \"year\": 1984}, \"block_event\": {\"date\": {\"month\": 12, \"day\": 31, \"year\": 1970}, \"serial_number\": 9097588792683265916, \"details\": \"most likely a troll\", \"administrator ID\": 10720293540521355122, \"description\": \"advertisement\"}}}, false]\n"
  },
  {
    "path": "autojsoncxx/examples/success/user_array.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "autojsoncxx/examples/success/user_array_compact.json",
    "content": "[{\"ID\":7947402710862746952,\"nickname\":\"bigger than bigger\",\"birthday\":{\"year\":1984,\"month\":9,\"day\":2},\"block_event\":{\"serial_number\":9097588792683265916,\"administrator ID\":10720293540521355122,\"date\":{\"year\":1970,\"month\":12,\"day\":31},\"description\":\"advertisement\",\"details\":\"most likely a troll\"},\"dark_history\":[],\"optional_attributes\":{}},{\"ID\":13478355757133566847,\"nickname\":\"→☛∅∆ℵ\",\"birthday\":{\"year\":2001,\"month\":1,\"day\":23},\"block_event\":null,\"dark_history\":[{\"serial_number\":11932018656737597978,\"administrator ID\":8027685536805674999,\"date\":{\"year\":2013,\"month\":3,\"day\":8},\"description\":\"copyright infringement\",\"details\":\"\"}],\"optional_attributes\":{\"Auth-Token\":\"45F13704-A60D-4D44-B161-89BAB88E528C\",\"Open ID\":\"something@somewhere.com\",\"Self description\":\"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\"}}]"
  },
  {
    "path": "autojsoncxx/examples/success/user_map.json",
    "content": "{\n\"First\":    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n\"Second\": {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n}\n"
  },
  {
    "path": "autojsoncxx/userdef.hpp",
    "content": "#pragma once\n\nnamespace config\n{\nstruct Date\n{\n    int year;\n    int month;\n    int day;\n\n    explicit Date() : year(), month(), day() {}\n\n    void staticjson_init(staticjson::ObjectHandler* h)\n    {\n        h->add_property(\"year\", &this->year, staticjson::Flags::Default);\n        h->add_property(\"month\", &this->month, staticjson::Flags::Default);\n        h->add_property(\"day\", &this->day, staticjson::Flags::Default);\n\n        h->set_flags(staticjson::Flags::Default | staticjson::Flags::AllowDuplicateKey\n                     | staticjson::Flags::DisallowUnknownKey);\n    }\n};\n}\n\nnamespace config\n{\nnamespace event\n{\n    struct BlockEvent\n    {\n        unsigned long long serial_number;\n        unsigned long long admin_ID;\n        Date date;\n        std::string description;\n        std::string details;\n\n        explicit BlockEvent()\n            : serial_number()\n            , admin_ID(255)\n            , date()\n            , description(\"\\x2f\\x2a\\x20\\x69\\x6e\\x69\\x74\\x20\\x2a\\x2f\\x20\\x74\\x72\\x79\\x69\\x6e\\x67\\x20\"\n                          \"\\x74\\x6f\\x20\\x6d\\x65\\x73\\x73\\x20\\x75\\x70\\x20\\x77\\x69\\x74\\x68\\x20\\x74\\x68\"\n                          \"\\x65\\x20\\x63\\x6f\\x64\\x65\\x20\\x67\\x65\\x6e\\x65\\x72\\x61\\x74\\x6f\\x72\")\n            , details()\n        {\n            date.year = 1970;\n            date.month = 1;\n            date.day = 1; /* Assign date to the UNIX epoch */\n        }\n\n        void staticjson_init(staticjson::ObjectHandler* h)\n        {\n            h->add_property(\"\\x73\\x65\\x72\\x69\\x61\\x6c\\x5f\\x6e\\x75\\x6d\\x62\\x65\\x72\",\n                            &this->serial_number,\n                            staticjson::Flags::Default);\n            h->add_property(\"administrator ID\", &this->admin_ID, staticjson::Flags::Optional);\n            h->add_property(\"date\", &this->date, staticjson::Flags::Optional);\n            h->add_property(\"description\", &this->description, staticjson::Flags::Optional);\n            h->add_property(\"details\", &this->details, staticjson::Flags::Optional);\n\n            h->set_flags(staticjson::Flags::Default | staticjson::Flags::AllowDuplicateKey);\n        }\n    };\n}\n}\n\nnamespace config\n{\nstruct User\n{\n    unsigned long long ID;\n    std::string nickname;\n    Date birthday;\n    std::shared_ptr<config::event::BlockEvent> block_event;\n    std::vector<config::event::BlockEvent> dark_history;\n    std::map<std::string, std::string> optional_attributes;\n\n    explicit User()\n        : ID()\n        , nickname(\"\\xe2\\x9d\\xb6\\xe2\\x9d\\xb7\\xe2\\x9d\\xb8\")\n        , birthday()\n        , block_event()\n        , dark_history()\n        , optional_attributes()\n    {\n    }\n\n    void staticjson_init(staticjson::ObjectHandler* h)\n    {\n        h->add_property(\"ID\", &this->ID, staticjson::Flags::Default);\n        h->add_property(\"nickname\", &this->nickname, staticjson::Flags::Default);\n        h->add_property(\"birthday\", &this->birthday, staticjson::Flags::Optional);\n        h->add_property(\"\\x62\\x6c\\x6f\\x63\\x6b\\x5f\\x65\\x76\\x65\\x6e\\x74\",\n                        &this->block_event,\n                        staticjson::Flags::Optional);\n        h->add_property(\"\\x64\\x61\\x72\\x6b\\x5f\\x68\\x69\\x73\\x74\\x6f\\x72\\x79\",\n                        &this->dark_history,\n                        staticjson::Flags::Optional);\n        h->add_property(\n            \"\\x6f\\x70\\x74\\x69\\x6f\\x6e\\x61\\x6c\\x5f\\x61\\x74\\x74\\x72\\x69\\x62\\x75\\x74\\x65\\x73\",\n            &this->optional_attributes,\n            staticjson::Flags::Optional);\n\n        h->set_flags(staticjson::Flags::Default);\n    }\n};\n}\n"
  },
  {
    "path": "autojsoncxx/userdef.json",
    "content": "[\n{\n    \"name\": \"Date\",\n    \"namespace\": \"config\",\n    \"parse_mode\": \"strict\",\n    \"members\": [\n        [\"int\", \"year\", {\"required\": true}],\n        [\"int\", \"month\", {\"required\": true}],\n        [\"int\", \"day\", {\"required\": true}]\n    ]\n},\n\n{\n    \"name\": \"BlockEvent\",\n    \"namespace\": \"config::event\",\n    \"members\": [\n        [\"unsigned long long\", \"serial_number\", {\"required\": true}],\n        [\"unsigned long long\", \"admin_ID\", {\"json_key\": \"administrator ID\", \"default\": 255}],\n        [\"Date\", \"date\"],\n        [\"std::string\", \"description\", {\"default\": \"/* init */ trying to mess up with the code generator\"}],\n        [\"std::string\", \"details\"]\n    ],\n    \"constructor_code\": \"date.year = 1970; date.month = 1; date.day = 1; /* Assign date to the UNIX epoch */\"\n},\n\n{\n    \"name\": \"User\",\n    \"namespace\": \"config\",\n    \"no_duplicates\": true,\n    \"members\": [\n        [\"unsigned long long\", \"ID\", {\"required\": true}],\n        [\"std::string\", \"nickname\", {\"required\": true, \"default\": \"❶❷❸\"} ],\n        [\"Date\", \"birthday\"],\n        [\"std::shared_ptr<config::event::BlockEvent>\", \"block_event\"],\n        [\"std::vector<config::event::BlockEvent>\", \"dark_history\"],\n        [\"std::map<std::string, std::string>\", \"optional_attributes\"]\n    ]\n}\n]\n"
  },
  {
    "path": "cmake/staticjson-config.cmake.in",
    "content": "@PACKAGE_INIT@\ninclude(CMakeFindDependencyMacro)\nfind_dependency(rapidjson CONFIG)\n\nif(NOT TARGET staticjson::staticjson)\n    include(${CMAKE_CURRENT_LIST_DIR}/staticjson-targets.cmake)\nendif()\n"
  },
  {
    "path": "examples/failure/duplicate_key.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\",\n            \"note\": \"the duplicate key error only occurs if your map types does not support duplicate key, e.g. `std::map`\"\n        }\n    }\n]\n"
  },
  {
    "path": "examples/failure/duplicate_key_user.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n\t\"ID\": 3399510046441,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "examples/failure/hard.json",
    "content": "[{\"serial_number\": 90049710466114, \"details\": \"unknown\"}, -65535, null, 2.718281828459045, {\"Second\": {\"ID\": 13478355757133566847, \"optional_attributes\": {\"Open ID\": \"something@somewhere.com\", \"Self description\": \"Can you handle characters above Basic Multilingual Plane?\\ud83d\\ude04\\ud83c\\udf85 \\ud83c\\udf81\\ud83d\\udc31\\u2708\\ufe0f\\ud83d\\udc18\\ud83d\\udd22\\ud840\\udc46\\ud841\\udf7b\\ud844\\udfa6\\ud844\\udf20\", \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"}, \"block_event\": null, \"Third\": null, \"dark_history\": [{\"date\": {\"month\": 3, \"day\": 8, \"year\": 2013}, \"serial_number\": 11932018656737597978, \"details\": null, \"administrator ID\": 8027685536805674999, \"description\": \"copyright infringement\"}], \"birthday\": {\"month\": 1, \"day\": 23, \"year\": 2001}, \"nickname\": \"\\u2192\\u261b\\u2205\\u2206\\u2135\"}, \"First\": {\"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\", \"ID\": 7947402710862746952, \"nickname\": \"bigger than bigger\", \"birthday\": {\"month\": 9, \"day\": 2, \"year\": 1984}, \"block_event\": {\"date\": {\"month\": 12, \"day\": 31, \"year\": 1970}, \"serial_number\": 9097588792683265916, \"details\": \"most likely a troll\", \"administrator ID\": 10720293540521355122, \"description\": \"advertisement\"}}}, false]\n\n"
  },
  {
    "path": "examples/failure/integer_string.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": \"0xa5970bbff02d9a1a\",\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "examples/failure/invalid_enum.json",
    "content": "{\n\"First\":    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"dark_event\": {\n            \"serial_number\": 9876543210123456789,\n            \"administrator ID\": 11223344556677889900,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"promote\",\n            \"details\": \"at least like a troll\",\n            \"flags\": null\n        },\n        \"alternate_history\": [\n            null,\n            {\n                \"serial_number\": 1123581321345589,\n                \"administrator ID\": 1123581321345589,\n                \"date\": {\n                    \"year\": 1970,\n                    \"month\": 12,\n                    \"day\": 31\n                },\n                \"description\": \"redacted\",\n                \"details\": \"redacted\",\n                \"flags\": \"x\"\n            }\n        ],\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n\"Second\": {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8,\n                    \"type\": \"West\"\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n}\n"
  },
  {
    "path": "examples/failure/map_element_mismatch.json",
    "content": "{\n\"First\":    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n\"Second\": {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    },\n\"Third\": false\n}\n"
  },
  {
    "path": "examples/failure/missing_required.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        }\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "examples/failure/null_in_key.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\\u0000 I am invisible because I am behind a null\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "examples/failure/out_of_range.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 162751169614016163\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "examples/failure/single_object.json",
    "content": "\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        }\n    }\n"
  },
  {
    "path": "examples/failure/tensor_length_error.json",
    "content": "[\n    []\n]\n"
  },
  {
    "path": "examples/failure/tensor_type_mismatch.json",
    "content": "[\n\t\t[\"1\", 2, 3]\n]\n"
  },
  {
    "path": "examples/failure/unknown_field.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31,\n                \"hour\": 21,\n                \"minute\": 33,\n                \"second\": 2\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        }\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n]\n"
  },
  {
    "path": "examples/success/hard.json",
    "content": "[{\"serial_number\": 90049710466114, \"details\": \"unknown\"}, -65535, null, 2.718281828459045, {\"Second\": {\"ID\": 13478355757133566847, \"optional_attributes\": {\"Open ID\": \"something@somewhere.com\", \"Self description\": \"Can you handle characters above Basic Multilingual Plane?\\ud83d\\ude04\\ud83c\\udf85 \\ud83c\\udf81\\ud83d\\udc31\\u2708\\ufe0f\\ud83d\\udc18\\ud83d\\udd22\\ud840\\udc46\\ud841\\udf7b\\ud844\\udfa6\\ud844\\udf20\", \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"}, \"block_event\": null, \"Third\": null, \"dark_history\": [{\"date\": {\"month\": 3, \"day\": 8, \"year\": 2013}, \"serial_number\": 11932018656737597978, \"details\": \"\", \"administrator ID\": 8027685536805674999, \"description\": \"copyright infringement\"}], \"birthday\": {\"month\": 1, \"day\": 23, \"year\": 2001}, \"nickname\": \"\\u2192\\u261b\\u2205\\u2206\\u2135\"}, \"First\": {\"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\", \"ID\": 7947402710862746952, \"nickname\": \"bigger than bigger\", \"birthday\": {\"month\": 9, \"day\": 2, \"year\": 1984}, \"block_event\": {\"date\": {\"month\": 12, \"day\": 31, \"year\": 1970}, \"serial_number\": 9097588792683265916, \"details\": \"most likely a troll\", \"administrator ID\": 10720293540521355122, \"description\": \"advertisement\"}}}, false]\n"
  },
  {
    "path": "examples/success/tensor.json",
    "content": "[\n\t\t[\n\t\t\t\t[1, 2, 3],\n\t\t\t\t[4, 5, 6],\n\t\t\t\t[7, 8, 0]\n\t\t],\n\t\t[\n\t\t\t\t[1.0, 2.0],\n\t\t\t\t[3.0, 4.0],\n\t\t\t\t[5.0, 6.0]\n\t\t],\n\t\t[\n\t\t\t\t[4.44],\n\t\t\t\t[0.9],\n\t\t\t\t[8.024]\n\t\t],\n\t\t[[], [], []]\n]\n"
  },
  {
    "path": "examples/success/user_array.json",
    "content": "[\n    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2,\n            \"type\": \"Jewish\"\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31,\n                \"type\": \"Chinese\"\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"dark_event\": {\n            \"serial_number\": 9876543210123456789,\n            \"administrator ID\": 11223344556677889900,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"promote\",\n            \"details\": \"at least like a troll\",\n            \"flags\": null\n        },\n        \"alternate_history\": [\n            null,\n            {\n                \"serial_number\": 1123581321345589,\n                \"administrator ID\": 1123581321345589,\n                \"date\": {\n                    \"year\": 1970,\n                    \"month\": 12,\n                    \"day\": 31\n                },\n                \"description\": \"redacted\",\n                \"details\": \"redacted\",\n                \"flags\": \"x\"\n            }\n        ],\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n    {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    },\n\t{\n        \"ID\": 994851,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 75350019499420,\n            \"administrator ID\": 1072029354,\n            \"date\": {\n                \"year\": 1993,\n                \"month\": 9,\n                \"day\": 7\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"hehe\"\n\t\t},\n        \"auxiliary\": [\n            3, [[4.0, 5.0], [9.2, 3.3]], true\n        ]\n    }\n]\n"
  },
  {
    "path": "examples/success/user_array_compact.json",
    "content": "[{\"ID\":7947402710862746952,\"nickname\":\"bigger than bigger\",\"birthday\":{\"year\":1984,\"month\":9,\"day\":2},\"block_event\":{\"serial_number\":9097588792683265916,\"administrator ID\":10720293540521355122,\"date\":{\"year\":1970,\"month\":12,\"day\":31},\"description\":\"advertisement\",\"details\":\"most likely a troll\"},\"dark_history\":[],\"optional_attributes\":{}},{\"ID\":13478355757133566847,\"nickname\":\"→☛∅∆ℵ\",\"birthday\":{\"year\":2001,\"month\":1,\"day\":23},\"block_event\":null,\"dark_history\":[{\"serial_number\":11932018656737597978,\"administrator ID\":8027685536805674999,\"date\":{\"year\":2013,\"month\":3,\"day\":8},\"description\":\"copyright infringement\",\"details\":\"\"}],\"optional_attributes\":{\"Auth-Token\":\"45F13704-A60D-4D44-B161-89BAB88E528C\",\"Open ID\":\"something@somewhere.com\",\"Self description\":\"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\"}}]"
  },
  {
    "path": "examples/success/user_map.json",
    "content": "{\n\"First\":    {\n        \"ID\": 7947402710862746952,\n        \"nickname\": \"bigger than bigger\",\n        \"birthday\": {\n            \"year\": 1984,\n            \"month\": 9,\n            \"day\": 2\n        },\n        \"block_event\": {\n            \"serial_number\": 9097588792683265916,\n            \"administrator ID\": 10720293540521355122,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"advertisement\",\n            \"details\": \"most likely a troll\"\n        },\n        \"dark_event\": {\n            \"serial_number\": 9876543210123456789,\n            \"administrator ID\": 11223344556677889900,\n            \"date\": {\n                \"year\": 1970,\n                \"month\": 12,\n                \"day\": 31\n            },\n            \"description\": \"promote\",\n            \"details\": \"at least like a troll\",\n            \"flags\": null\n        },\n        \"alternate_history\": [\n            null,\n            {\n                \"serial_number\": 1123581321345589,\n                \"administrator ID\": 1123581321345589,\n                \"date\": {\n                    \"year\": 1970,\n                    \"month\": 12,\n                    \"day\": 31\n                },\n                \"description\": \"redacted\",\n                \"details\": \"redacted\",\n                \"flags\": \"x\"\n            }\n        ],\n        \"comment\": \"This field is not specified by our class; but it is silently skipped because the parse_mode of class `User` is not `strict`\"\n    },\n\"Second\": {\n        \"ID\": 13478355757133566847,\n        \"nickname\": \"→☛∅∆ℵ\",\n        \"birthday\": {\n            \"year\": 2001,\n            \"month\": 1,\n            \"day\": 23\n        },\n        \"block_event\": null,\n        \"dark_history\": [\n            {\n                \"serial_number\": 11932018656737597978,\n                \"administrator ID\": 8027685536805674999,\n                \"date\": {\n                    \"year\": 2013,\n                    \"month\": 3,\n                    \"day\": 8\n                },\n                \"description\": \"copyright infringement\",\n                \"details\": \"\"\n            }\n        ],\n        \"optional_attributes\": {\n            \"Self description\": \"Can you handle characters above Basic Multilingual Plane?😄🎅 🎁🐱✈️🐘🔢𠁆𠝻𡎦𡌠\",\n            \"Open ID\": \"something@somewhere.com\",\n            \"Auth-Token\": \"45F13704-A60D-4D44-B161-89BAB88E528C\"\n        }\n    }\n}\n"
  },
  {
    "path": "format.sh",
    "content": "#!/bin/sh\ncd $(dirname $0)\nGLOBIGNORE=\"include/staticjson/optional_support.hpp\"\nclang-format -i --style=File autojsoncxx/*.hpp include/staticjson/*.hpp src/*.cpp test/*.cpp test/myarray.hpp\n"
  },
  {
    "path": "include/staticjson/basic.hpp",
    "content": "#pragma once\n\n#include <rapidjson/document.h>\n#include <staticjson/error.hpp>\n\n#include <climits>\n#include <cstddef>\n#include <cstdint>\n#include <map>\n#include <memory>\n#include <stack>\n#include <type_traits>\n\nnamespace staticjson\n{\nstruct NonMobile\n{\n    NonMobile() {}\n    ~NonMobile() {}\n    NonMobile(const NonMobile&) = delete;\n    NonMobile(NonMobile&&) = delete;\n    NonMobile& operator=(const NonMobile&) = delete;\n    NonMobile& operator=(NonMobile&&) = delete;\n};\n\ntypedef unsigned int SizeType;\n\n// This class is not thread safe, so please set all values at startup or when single threaded.\nclass GlobalConfig : private NonMobile\n{\npublic:\n    static GlobalConfig* getInstance() noexcept;\n    SizeType getMemoryChunkSize() const noexcept { return memoryChunkSize; }\n    void setMemoryChunkSize(SizeType value) noexcept { memoryChunkSize = value; }\n    void setMaxLeaves(SizeType maxNum) noexcept\n    {\n        maxLeaves = maxNum;\n        _isMaxLeavesSet = true;\n    }\n    void setMaxDepth(SizeType maxDep) noexcept\n    {\n        maxDepth = maxDep;\n        _isMaxDepthSet = true;\n    }\n    SizeType getMaxDepth() const noexcept { return maxDepth; }\n    SizeType getMaxLeaves() const noexcept { return maxLeaves; }\n    bool isMaxLeavesSet() const noexcept { return _isMaxLeavesSet; }\n    bool isMaxDepthSet() const noexcept { return _isMaxDepthSet; }\n    void unsetMaxLeavesFlag() noexcept\n    {\n        _isMaxLeavesSet = false;\n        maxLeaves = UINT_MAX;\n    }\n    void unsetMaxDepthFlag() noexcept\n    {\n        _isMaxDepthSet = false;\n        maxDepth = UINT_MAX;\n    }\n\nprivate:\n    GlobalConfig() {}\n    bool _isMaxLeavesSet = false;\n    bool _isMaxDepthSet = false;\n    SizeType maxLeaves = UINT_MAX;\n    SizeType maxDepth = UINT_MAX;\n    SizeType memoryChunkSize = 1000;\n};\n\nclass IHandler\n{\npublic:\n    IHandler() {}\n\n    virtual ~IHandler();\n\n    virtual bool Null() = 0;\n\n    virtual bool Bool(bool) = 0;\n\n    virtual bool Int(int) = 0;\n\n    virtual bool Uint(unsigned) = 0;\n\n    virtual bool Int64(std::int64_t) = 0;\n\n    virtual bool Uint64(std::uint64_t) = 0;\n\n    virtual bool Double(double) = 0;\n\n    virtual bool String(const char*, SizeType, bool) = 0;\n\n    virtual bool StartObject() = 0;\n\n    virtual bool Key(const char*, SizeType, bool) = 0;\n\n    virtual bool EndObject(SizeType) = 0;\n\n    virtual bool StartArray() = 0;\n\n    virtual bool EndArray(SizeType) = 0;\n\n    virtual bool RawNumber(const char*, SizeType, bool);\n\n    virtual void prepare_for_reuse() = 0;\n};\n\nusing rapidjson::Document;\nusing rapidjson::Value;\n\ntypedef rapidjson::MemoryPoolAllocator<> MemoryPoolAllocator;\n\nclass BaseHandler : public IHandler, private NonMobile\n{\n    friend class NullableHandler;\n\nprotected:\n    std::unique_ptr<ErrorBase> the_error;\n    bool parsed = false;\n\nprotected:\n    bool set_out_of_range(const char* actual_type);\n    bool set_type_mismatch(const char* actual_type);\n\n    virtual void reset() {}\n\npublic:\n    BaseHandler() {}\n\n    virtual ~BaseHandler();\n\n    virtual std::string type_name() const = 0;\n\n    virtual bool Null() override { return set_type_mismatch(\"null\"); }\n\n    virtual bool Bool(bool) override { return set_type_mismatch(\"bool\"); }\n\n    virtual bool Int(int) override { return set_type_mismatch(\"int\"); }\n\n    virtual bool Uint(unsigned) override { return set_type_mismatch(\"unsigned\"); }\n\n    virtual bool Int64(std::int64_t) override { return set_type_mismatch(\"int64_t\"); }\n\n    virtual bool Uint64(std::uint64_t) override { return set_type_mismatch(\"uint64_t\"); }\n\n    virtual bool Double(double) override { return set_type_mismatch(\"double\"); }\n\n    virtual bool String(const char*, SizeType, bool) override\n    {\n        return set_type_mismatch(\"string\");\n    }\n\n    virtual bool StartObject() override { return set_type_mismatch(\"object\"); }\n\n    virtual bool Key(const char*, SizeType, bool) override { return set_type_mismatch(\"object\"); }\n\n    virtual bool EndObject(SizeType) override { return set_type_mismatch(\"object\"); }\n\n    virtual bool StartArray() override { return set_type_mismatch(\"array\"); }\n\n    virtual bool EndArray(SizeType) override { return set_type_mismatch(\"array\"); }\n\n    virtual bool has_error() const { return bool(the_error); }\n\n    virtual bool reap_error(ErrorStack& errs)\n    {\n        if (!the_error)\n            return false;\n        errs.push(the_error.release());\n        return true;\n    }\n\n    bool is_parsed() const { return parsed; }\n\n    void prepare_for_reuse() override\n    {\n        the_error.reset();\n        parsed = false;\n        reset();\n    }\n\n    virtual bool write(IHandler* output) const = 0;\n\n    virtual void generate_schema(Value& output, MemoryPoolAllocator& alloc) const = 0;\n};\n\nstruct Flags\n{\n    static const unsigned Default = 0x0, AllowDuplicateKey = 0x1, Optional = 0x2, IgnoreRead = 0x4,\n                          IgnoreWrite = 0x8, DisallowUnknownKey = 0x10;\n};\n\n// Forward declaration\ntemplate <class T>\nclass Handler;\n\nnamespace mempool\n{\n    [[noreturn]] void throw_bad_alloc();\n    rapidjson::CrtAllocator& get_crt_allocator() noexcept;\n\n    template <class T>\n    class PooledAllocator\n    {\n    private:\n        MemoryPoolAllocator* pool;\n\n        template <class U>\n        friend class PooledAllocator;\n\n    public:\n        using value_type = T;\n        using propagate_on_container_copy_assignment = std::true_type;\n        using propagate_on_container_move_assignment = std::true_type;\n        using propagate_on_container_swap = std::true_type;\n\n        explicit PooledAllocator(MemoryPoolAllocator* pool) noexcept : pool(pool) {}\n\n        template <class U>\n        PooledAllocator(const PooledAllocator<U>& other) noexcept : pool(other.pool)\n        {\n        }\n        template <class U>\n        bool operator==(const PooledAllocator<U>& other) const noexcept\n        {\n            return pool == other.pool;\n        }\n        template <class U>\n        bool operator!=(const PooledAllocator<U>& other) const noexcept\n        {\n            return pool != other.pool;\n        }\n        T* allocate(const size_t n) const\n        {\n            if (!n)\n            {\n                return nullptr;\n            }\n            auto ptr = static_cast<T*>(pool->Malloc(n * sizeof(T)));\n            if (!ptr)\n            {\n                throw_bad_alloc();\n            }\n            return ptr;\n        }\n        void deallocate(T* const p, size_t) const noexcept\n        {\n            if (p)\n            {\n                pool->Free(p);\n            }\n        }\n    };\n\n    template <class K, class V>\n    using Map = std::map<K, V, std::less<K>, PooledAllocator<std::pair<const K, V>>>;\n\n    template <class T>\n    using Stack = std::stack<T, std::deque<T, PooledAllocator<T>>>;\n\n    using String = std::basic_string<char, std::char_traits<char>, PooledAllocator<char>>;\n\n    inline std::string to_std_string(const String& str) { return {str.data(), str.size()}; }\n\n    template <class T>\n    struct PooledDeleter\n    {\n        void operator()(T* ptr) const noexcept\n        {\n            if (!ptr)\n            {\n                return;\n            }\n            ptr->~T();\n            static_assert(!MemoryPoolAllocator::kNeedFree,\n                          \"MemoryPoolAllocator must not need freeing\");\n        }\n    };\n\n    template <class T>\n    using UniquePtr = std::unique_ptr<T, PooledDeleter<T>>;\n\n    template <typename T, typename... Args>\n    T* pooled_new(MemoryPoolAllocator& pool, Args&&... args)\n    {\n        auto storage = pool.Malloc(sizeof(T));\n        static_assert(!MemoryPoolAllocator::kNeedFree,\n                      \"MemoryPoolAllocator must not need freeing or we will need to handle \"\n                      \"potential exceptions in the construction of T\");\n        new (storage) T(std::forward<Args>(args)...);\n        return static_cast<T*>(storage);\n    }\n}\n\nclass ObjectHandler : public BaseHandler\n{\nprotected:\n    struct FlaggedHandler\n    {\n        mempool::UniquePtr<BaseHandler> handler;\n        unsigned flags;\n    };\n\nprotected:\n    MemoryPoolAllocator memory_pool_allocator;\n    mempool::Map<mempool::String, FlaggedHandler> internals;\n    FlaggedHandler* current = nullptr;\n    mempool::String current_name;\n    int depth = 0;\n    unsigned flags = Flags::Default;\n    unsigned int jsonDepth = 0;\n    // true if last symbol is '[', otherwise false\n    bool lastLeafStat = false;\n    SizeType totalLeaves = 0;\n    // save the number of object or array\n    mempool::Stack<SizeType> leavesStack;\n\nprotected:\n    void postinit();\n    bool precheck(const char* type);\n    bool postcheck(bool success);\n    void set_missing_required(const std::string& name);\n    void add_handler(mempool::String&&, FlaggedHandler&&);\n    void reset() override;\n\nprivate:\n    bool StartCheckMaxDepthMaxLeaves(bool isArray);\n    bool EndCheckMaxDepthMaxLeaves(SizeType sz, bool isArray);\n\n    template <class T>\n    void add_property(mempool::String name, T* pointer, unsigned flags_ = Flags::Default)\n    {\n        FlaggedHandler fh;\n        fh.handler.reset(mempool::pooled_new<Handler<T>>(memory_pool_allocator, pointer));\n        fh.flags = flags_;\n        add_handler(std::move(name), std::move(fh));\n    }\n\npublic:\n    ObjectHandler();\n\n    ~ObjectHandler();\n\n    std::string type_name() const override;\n\n    virtual bool Null() override;\n\n    virtual bool Bool(bool) override;\n\n    virtual bool Int(int) override;\n\n    virtual bool Uint(unsigned) override;\n\n    virtual bool Int64(std::int64_t) override;\n\n    virtual bool Uint64(std::uint64_t) override;\n\n    virtual bool Double(double) override;\n\n    virtual bool String(const char*, SizeType, bool) override;\n\n    virtual bool StartObject() override;\n\n    virtual bool Key(const char*, SizeType, bool) override;\n\n    virtual bool EndObject(SizeType) override;\n\n    virtual bool StartArray() override;\n\n    virtual bool EndArray(SizeType) override;\n\n    virtual bool reap_error(ErrorStack&) override;\n\n    virtual bool write(IHandler* output) const override;\n\n    virtual void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override;\n\n    unsigned get_flags() const { return flags; }\n\n    void set_flags(unsigned f) { flags = f; }\n\n    const MemoryPoolAllocator& get_memory_pool() const noexcept { return memory_pool_allocator; }\n\n    template <class T>\n    void add_property(const std::string& name, T* pointer, unsigned flags_ = Flags::Default)\n    {\n        add_property(mempool::String(name.data(),\n                                     name.size(),\n                                     mempool::String::allocator_type(&memory_pool_allocator)),\n                     pointer,\n                     flags_);\n    }\n\n    template <class T>\n    void add_property(const char* name, T* pointer, unsigned flags_ = Flags::Default)\n    {\n        add_property(mempool::String(name, mempool::String::allocator_type(&memory_pool_allocator)),\n                     pointer,\n                     flags_);\n    }\n};\n\ntemplate <class T>\nstruct Converter\n{\n    typedef T shadow_type;\n\n    static std::unique_ptr<ErrorBase> from_shadow(const shadow_type& shadow, T& value)\n    {\n        (void)shadow;\n        (void)value;\n        return nullptr;\n    }\n\n    static void to_shadow(const T& value, shadow_type& shadow)\n    {\n        (void)shadow;\n        (void)value;\n    }\n\n    static std::string type_name() { return \"T\"; }\n\n    static constexpr bool has_specialized_type_name = false;\n};\n\ntemplate <class T>\nvoid init(T* t, ObjectHandler* h)\n{\n    t->staticjson_init(h);\n}\n\ntemplate <class T>\nclass ObjectTypeHandler : public ObjectHandler\n{\npublic:\n    explicit ObjectTypeHandler(T* t)\n    {\n        init(t, this);\n        postinit();\n    }\n};\n\ntemplate <class T>\nclass ConversionHandler : public BaseHandler\n{\nprivate:\n    typedef typename Converter<T>::shadow_type shadow_type;\n    typedef Handler<shadow_type> internal_type;\n\nprivate:\n    shadow_type shadow;\n    internal_type internal;\n    T* m_value;\n\nprotected:\n    bool postprocess(bool success)\n    {\n        if (!success)\n        {\n            return false;\n        }\n        if (!internal.is_parsed())\n            return true;\n        this->parsed = true;\n        auto err = Converter<T>::from_shadow(shadow, *m_value);\n        if (err)\n        {\n            this->the_error.swap(err);\n            return false;\n        }\n        return true;\n    }\n\n    void reset() override\n    {\n        shadow = shadow_type();\n        internal.prepare_for_reuse();\n    }\n\npublic:\n    explicit ConversionHandler(T* t) : shadow(), internal(&shadow), m_value(t) {}\n\n    std::string type_name() const override\n    {\n        // if (Converter<T>::has_specialized_type_name)\n        //  return Converter<T>::type_name();\n        return internal.type_name();\n    }\n\n    virtual bool Null() override { return postprocess(internal.Null()); }\n\n    virtual bool Bool(bool b) override { return postprocess(internal.Bool(b)); }\n\n    virtual bool Int(int i) override { return postprocess(internal.Int(i)); }\n\n    virtual bool Uint(unsigned u) override { return postprocess(internal.Uint(u)); }\n\n    virtual bool Int64(std::int64_t i) override { return postprocess(internal.Int64(i)); }\n\n    virtual bool Uint64(std::uint64_t u) override { return postprocess(internal.Uint64(u)); }\n\n    virtual bool Double(double d) override { return postprocess(internal.Double(d)); }\n\n    virtual bool String(const char* str, SizeType size, bool copy) override\n    {\n        return postprocess(internal.String(str, size, copy));\n    }\n\n    virtual bool StartObject() override { return postprocess(internal.StartObject()); }\n\n    virtual bool Key(const char* str, SizeType size, bool copy) override\n    {\n        return postprocess(internal.Key(str, size, copy));\n    }\n\n    virtual bool EndObject(SizeType sz) override { return postprocess(internal.EndObject(sz)); }\n\n    virtual bool StartArray() override { return postprocess(internal.StartArray()); }\n\n    virtual bool EndArray(SizeType sz) override { return postprocess(internal.EndArray(sz)); }\n\n    virtual bool has_error() const override\n    {\n        return BaseHandler::has_error() || internal.has_error();\n    }\n\n    bool reap_error(ErrorStack& errs) override\n    {\n        return BaseHandler::reap_error(errs) || internal.reap_error(errs);\n    }\n\n    virtual bool write(IHandler* output) const override\n    {\n        Converter<T>::to_shadow(*m_value, const_cast<shadow_type&>(shadow));\n        return internal.write(output);\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        return internal.generate_schema(output, alloc);\n    }\n};\n\nnamespace helper\n{\n    template <class T, bool no_conversion>\n    class DispatchHandler;\n    template <class T>\n    class DispatchHandler<T, true> : public ::staticjson::ObjectTypeHandler<T>\n    {\n    public:\n        explicit DispatchHandler(T* t) : ::staticjson::ObjectTypeHandler<T>(t) {}\n    };\n\n    template <class T>\n    class DispatchHandler<T, false> : public ::staticjson::ConversionHandler<T>\n    {\n    public:\n        explicit DispatchHandler(T* t) : ::staticjson::ConversionHandler<T>(t) {}\n    };\n}\n\ntemplate <class T>\nclass Handler\n    : public helper::DispatchHandler<T, std::is_same<typename Converter<T>::shadow_type, T>::value>\n{\npublic:\n    typedef helper::DispatchHandler<T, std::is_same<typename Converter<T>::shadow_type, T>::value>\n        base_type;\n    explicit Handler(T* t) : base_type(t) {}\n};\n}\n"
  },
  {
    "path": "include/staticjson/document.hpp",
    "content": "#pragma once\n#include <staticjson/basic.hpp>\n\n#include <rapidjson/document.h>\n\n#include <vector>\n\nnamespace staticjson\n{\nclass JSONHandler : public BaseHandler\n{\nprotected:\n    static const int MAX_DEPTH = 32;\n\n    std::vector<Value> m_stack;\n    Value* m_value;\n    MemoryPoolAllocator* m_alloc;\n\nprivate:\n    bool stack_push();\n    void stack_pop();\n    Value& stack_top();\n    bool postprocess();\n    bool set_corrupted_dom();\n\npublic:\n    explicit JSONHandler(Value* v, MemoryPoolAllocator* a);\n\n    std::string type_name() const override;\n\n    virtual bool Null() override;\n\n    virtual bool Bool(bool) override;\n\n    virtual bool Int(int) override;\n\n    virtual bool Uint(unsigned) override;\n\n    virtual bool Int64(std::int64_t) override;\n\n    virtual bool Uint64(std::uint64_t) override;\n\n    virtual bool Double(double) override;\n\n    virtual bool String(const char*, SizeType, bool) override;\n\n    virtual bool StartObject() override;\n\n    virtual bool Key(const char*, SizeType, bool) override;\n\n    virtual bool EndObject(SizeType) override;\n\n    virtual bool StartArray() override;\n\n    virtual bool EndArray(SizeType) override;\n\n    virtual bool write(IHandler* output) const override;\n\n    virtual void reset() override;\n\n    void reset(MemoryPoolAllocator* a);\n\n    void generate_schema(Value& output, MemoryPoolAllocator&) const override { output.SetObject(); }\n};\n\ntemplate <>\nclass Handler<Document> : public JSONHandler\n{\npublic:\n    explicit Handler(Document* h) : JSONHandler(h, &h->GetAllocator()) {}\n    virtual void reset() override\n    {\n        JSONHandler::reset(&(static_cast<Document*>(this->m_value)->GetAllocator()));\n    }\n};\n\nnamespace nonpublic\n{\n    bool write_value(const Value& v, BaseHandler* out, ParseStatus* status);\n    bool\n    read_value(Value* v, MemoryPoolAllocator* alloc, const BaseHandler* input, ParseStatus* status);\n}\n\ntemplate <class T>\nbool from_json_value(const Value& v, T* t, ParseStatus* status)\n{\n    Handler<T> h(t);\n    return nonpublic::write_value(v, &h, status);\n}\n\ntemplate <class T>\nbool from_json_document(const Document& d,\n                        T* t,\n                        ParseStatus* status)    // for consistency in API\n{\n    return from_json_value(d, t, status);\n}\n\ntemplate <class T>\nbool to_json_value(Value* v, MemoryPoolAllocator* alloc, const T& t, ParseStatus* status)\n{\n    Handler<T> h(const_cast<T*>(&t));\n    return nonpublic::read_value(v, alloc, &h, status);\n}\n\ntemplate <class T>\nbool to_json_document(Document* d, const T& t, ParseStatus* status)\n{\n    return to_json_value(d, &d->GetAllocator(), t, status);\n}\n}\n"
  },
  {
    "path": "include/staticjson/enum.hpp",
    "content": "#pragma once\n\n#include <staticjson/primitive_types.hpp>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace staticjson\n{\ntemplate <class Enum, class Derived>\nclass EnumHandler : public BaseHandler\n{\nprivate:\n    Enum* m_value;\n\n    static const std::vector<std::pair<std::string, Enum>>& get_mapping()\n    {\n        return Derived::get_mapping();\n    };\n\npublic:\n    explicit EnumHandler(Enum* value) : m_value(value) {}\n\n    bool String(const char* str, SizeType sz, bool) override\n    {\n        const auto& mapping = get_mapping();\n        for (const std::pair<std::string, Enum>& pair : mapping)\n        {\n            if (pair.first.size() == sz && memcmp(pair.first.data(), str, sz) == 0)\n            {\n                *m_value = pair.second;\n                this->parsed = true;\n                return true;\n            }\n        }\n        the_error.reset(new error::InvalidEnumError(std::string(str, str + sz)));\n        return false;\n    }\n\n    bool write(IHandler* output) const override\n    {\n        const auto& mapping = get_mapping();\n        for (const std::pair<std::string, Enum>& pair : mapping)\n        {\n            if (*m_value == pair.second)\n            {\n                output->String(pair.first.data(), static_cast<SizeType>(pair.first.size()), false);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"string\"), alloc);\n        Value enumerations(rapidjson::kArrayType);\n        const auto& mapping = get_mapping();\n        for (const std::pair<std::string, Enum>& pair : mapping)\n        {\n            enumerations.PushBack(rapidjson::StringRef(pair.first.data(), pair.first.size()),\n                                  alloc);\n        }\n        output.AddMember(rapidjson::StringRef(\"enum\"), enumerations, alloc);\n    }\n};\n}\n\n#define STATICJSON_DECLARE_ENUM(type, ...)                                                         \\\n    namespace staticjson                                                                           \\\n    {                                                                                              \\\n        template <>                                                                                \\\n        class Handler<type> : public EnumHandler<type, Handler<type>>                              \\\n        {                                                                                          \\\n        public:                                                                                    \\\n            explicit Handler(type* value) : EnumHandler<type, Handler<type>>(value) {}             \\\n            std::string type_name() const override { return #type; }                               \\\n            static const std::vector<std::pair<std::string, type>>& get_mapping()                  \\\n            {                                                                                      \\\n                static std::vector<std::pair<std::string, type>> mapping{__VA_ARGS__};             \\\n                return mapping;                                                                    \\\n            }                                                                                      \\\n        };                                                                                         \\\n    }\n"
  },
  {
    "path": "include/staticjson/error.hpp",
    "content": "#pragma once\n\n#include <algorithm>\n#include <cstddef>\n#include <iterator>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace staticjson\n{\nstd::string quote(const std::string& str);\n\nclass ErrorStack;\nclass ErrorBase;\n\nnamespace error\n{\n    namespace internal\n    {\n        class error_stack_const_iterator;\n    }\n    using staticjson::ErrorBase;\n    using staticjson::ErrorStack;\n}\n\nclass ErrorBase\n{\nprotected:\n    explicit ErrorBase() : next(0) {}\n\nprivate:\n    ErrorBase* next;\n\n    friend class ErrorStack;\n    friend class error::internal::error_stack_const_iterator;\n\npublic:\n    virtual int type() const = 0;\n    virtual bool is_intermediate() const { return false; }\n    virtual ~ErrorBase() {}\n    virtual std::string description() const = 0;\n};\n\nnamespace error\n{\n    typedef int error_type;\n\n    static const error_type SUCCESS = 0, OBJECT_MEMBER = 1, ARRAY_ELEMENT = 2, MISSING_REQUIRED = 3,\n                            TYPE_MISMATCH = 4, NUMBER_OUT_OF_RANGE = 5, ARRAY_LENGTH_MISMATCH = 6,\n                            UNKNOWN_FIELD = 7, DUPLICATE_KEYS = 8, CORRUPTED_DOM = 9,\n                            TOO_DEEP_RECURSION = 10, INVALID_ENUM = 11, TOO_MANY_LEAVES = 12,\n                            CUSTOM = -1;\n\n    class Success : public ErrorBase\n    {\n    public:\n        explicit Success() {}\n        std::string description() const;\n        error_type type() const { return SUCCESS; }\n    };\n\n    class IntermediateError : public ErrorBase\n    {\n    public:\n        bool is_intermediate() const { return true; }\n    };\n\n    class ObjectMemberError : public IntermediateError\n    {\n    private:\n        std::string m_member_name;\n\n    public:\n        explicit ObjectMemberError(std::string memberName) { m_member_name.swap(memberName); }\n\n        const std::string& member_name() const { return m_member_name; }\n\n        std::string description() const;\n\n        error_type type() const { return OBJECT_MEMBER; }\n    };\n\n    class ArrayElementError : public IntermediateError\n    {\n    private:\n        std::size_t m_index;\n\n    public:\n        explicit ArrayElementError(std::size_t idx) : m_index(idx) {}\n\n        std::size_t index() const { return m_index; }\n\n        std::string description() const;\n\n        error_type type() const { return ARRAY_ELEMENT; }\n    };\n\n    class RequiredFieldMissingError : public ErrorBase\n    {\n    private:\n        std::vector<std::string> m_missing_members;\n\n    public:\n        explicit RequiredFieldMissingError() {}\n\n        std::vector<std::string>& missing_members() { return m_missing_members; };\n\n        const std::vector<std::string>& missing_members() const { return m_missing_members; }\n\n        std::string description() const;\n\n        error_type type() const { return MISSING_REQUIRED; }\n    };\n\n    class TypeMismatchError : public ErrorBase\n    {\n    private:\n        std::string m_expected_type;\n        std::string m_actual_type;\n\n    public:\n        explicit TypeMismatchError(std::string expectedType, std::string actualType)\n        {\n            m_expected_type.swap(expectedType);\n            m_actual_type.swap(actualType);\n        }\n\n        const std::string& expected_type() const { return m_expected_type; }\n\n        const std::string& actual_type() const { return m_actual_type; }\n\n        std::string description() const;\n\n        error_type type() const { return TYPE_MISMATCH; }\n    };\n\n    class RecursionTooDeepError : public ErrorBase\n    {\n        std::string description() const override;\n        error_type type() const override { return TOO_DEEP_RECURSION; }\n    };\n    class TooManyLeavesError : public ErrorBase\n    {\n        std::string description() const override;\n        error_type type() const override { return TOO_MANY_LEAVES; }\n    };\n    class NumberOutOfRangeError : public ErrorBase\n    {\n        std::string m_expected_type;\n        std::string m_actual_type;\n\n    public:\n        explicit NumberOutOfRangeError(std::string expectedType, std::string actualType)\n        {\n            m_expected_type.swap(expectedType);\n            m_actual_type.swap(actualType);\n        }\n\n        const std::string& expected_type() const { return m_expected_type; }\n\n        const std::string& actual_type() const { return m_actual_type; }\n\n        std::string description() const;\n\n        error_type type() const { return NUMBER_OUT_OF_RANGE; }\n    };\n\n    class DuplicateKeyError : public ErrorBase\n    {\n    private:\n        std::string key_name;\n\n    public:\n        explicit DuplicateKeyError(std::string name) { key_name.swap(name); }\n\n        const std::string& key() const { return key_name; }\n\n        error_type type() const { return DUPLICATE_KEYS; }\n\n        std::string description() const;\n    };\n\n    class UnknownFieldError : public ErrorBase\n    {\n    private:\n        std::string m_name;\n\n    public:\n        explicit UnknownFieldError(const char* name, std::size_t length) : m_name(name, length) {}\n\n        const std::string& field_name() const { return m_name; }\n\n        error_type type() const { return UNKNOWN_FIELD; }\n\n        std::string description() const;\n    };\n\n    class CorruptedDOMError : public ErrorBase\n    {\n    public:\n        std::string description() const;\n\n        error_type type() const { return CORRUPTED_DOM; }\n    };\n\n    class ArrayLengthMismatchError : public ErrorBase\n    {\n    public:\n        std::string description() const;\n\n        error_type type() const { return ARRAY_LENGTH_MISMATCH; }\n    };\n\n    class InvalidEnumError : public ErrorBase\n    {\n    private:\n        std::string m_name;\n\n    public:\n        explicit InvalidEnumError(std::string name) { m_name.swap(name); }\n        std::string description() const;\n        error_type type() const { return INVALID_ENUM; }\n    };\n\n    class CustomError : public ErrorBase\n    {\n    private:\n        std::string m_message;\n\n    public:\n        explicit CustomError(std::string message) { m_message.swap(message); }\n        std::string description() const;\n        error_type type() const { return CUSTOM; }\n    };\n\n    namespace internal\n    {\n\n        class error_stack_const_iterator\n        {\n        private:\n            const ErrorBase* e;\n\n        public:\n            using iterator_category = std::forward_iterator_tag;\n            using value_type = const ErrorBase;\n            using difference_type = ptrdiff_t;\n            using pointer = const ErrorBase*;\n            using reference = const ErrorBase&;\n\n        public:\n            explicit error_stack_const_iterator(const ErrorBase* p) : e(p) {}\n            reference operator*() const { return *e; }\n\n            pointer operator->() const { return e; }\n\n            error_stack_const_iterator& operator++()\n            {\n                e = e->next;\n                return *this;\n            }\n\n            bool operator==(error_stack_const_iterator that) const { return e == that.e; }\n\n            bool operator!=(error_stack_const_iterator that) const { return e != that.e; }\n        };\n    }\n}\n\nclass ErrorStack\n{\nprivate:\n    ErrorBase* head;\n    std::size_t m_size;\n\n    ErrorStack(const ErrorStack&);\n    ErrorStack& operator=(const ErrorStack&);\n\npublic:\n    typedef error::internal::error_stack_const_iterator const_iterator;\n\n    explicit ErrorStack() : head(0), m_size(0) {}\n\n    const_iterator begin() const { return const_iterator(head); }\n\n    const_iterator end() const { return const_iterator(0); }\n\n    // This will take the ownership of e\n    // Requires it to be dynamically allocated\n    void push(ErrorBase* e)\n    {\n        if (e)\n        {\n            e->next = head;\n            head = e;\n            ++m_size;\n        }\n    }\n\n    // The caller will take the responsibility of deleting the returned pointer\n    // Returns NULL when empty\n    ErrorBase* pop()\n    {\n        if (head)\n        {\n            ErrorBase* result = head;\n            head = head->next;\n            --m_size;\n            return result;\n        }\n        return 0;\n    }\n\n    bool empty() const { return head == 0; }\n\n    explicit operator bool() const { return !empty(); }\n\n    bool operator!() const { return empty(); }\n\n    std::size_t size() const { return m_size; }\n\n    ~ErrorStack()\n    {\n        while (head)\n        {\n            ErrorBase* next = head->next;\n            delete head;\n            head = next;\n        }\n    }\n\n    void swap(ErrorStack& other) noexcept\n    {\n        std::swap(head, other.head);\n        std::swap(m_size, other.m_size);\n    }\n\n    ErrorStack(ErrorStack&& other) : head(other.head), m_size(other.m_size)\n    {\n        other.head = 0;\n        other.m_size = 0;\n    }\n\n    ErrorStack& operator==(ErrorStack&& other)\n    {\n        swap(other);\n        return *this;\n    }\n};\n\n// For argument dependent lookup\ninline void swap(ErrorStack& s1, ErrorStack& s2) { s1.swap(s2); }\n\nclass ParseStatus\n{\nprivate:\n    ErrorStack m_stack;\n    std::size_t m_offset;\n    int m_code;\n\npublic:\n    explicit ParseStatus() : m_stack(), m_offset(), m_code() {}\n\n    void set_result(int err, std::size_t off)\n    {\n        m_code = err;\n        m_offset = off;\n    }\n\n    int error_code() const { return m_code; }\n\n    std::size_t offset() const { return m_offset; }\n\n    std::string short_description() const;\n\n    ErrorStack& error_stack() { return m_stack; }\n\n    const ErrorStack& error_stack() const { return m_stack; }\n\n    typedef ErrorStack::const_iterator const_iterator;\n\n    const_iterator begin() const { return m_stack.begin(); }\n\n    const_iterator end() const { return m_stack.end(); }\n\n    bool has_error() const { return m_code != 0 || !m_stack.empty(); }\n\n    std::string description() const;\n\n    void swap(ParseStatus& other) noexcept\n    {\n        std::swap(m_code, other.m_code);\n        std::swap(m_offset, other.m_offset);\n        m_stack.swap(other.m_stack);\n    }\n\n    bool operator!() const { return has_error(); }\n\n    explicit operator bool() const { return !has_error(); }\n\n    ParseStatus(ParseStatus&& other) noexcept : m_stack(), m_offset(), m_code() { swap(other); }\n\n    ParseStatus& operator==(ParseStatus&& other) noexcept\n    {\n        swap(other);\n        return *this;\n    }\n};\n\n// For argument dependent lookup\ninline void swap(ParseStatus& r1, ParseStatus& r2) { r1.swap(r2); }\n}\n"
  },
  {
    "path": "include/staticjson/forward_declarations.hpp",
    "content": "#pragma once\n\nnamespace staticjson\n{\ntypedef unsigned int SizeType;\n\nclass IHandler;\n\nclass BaseHandler;\n\nclass ObjectHandler;\n\ntemplate <class T>\nclass Handler;\n}\n"
  },
  {
    "path": "include/staticjson/io.hpp",
    "content": "#pragma once\n\n#include <staticjson/basic.hpp>\n\n#include <cstdio>\n#include <string>\n\nnamespace staticjson\n{\n\nnamespace nonpublic\n{\n    bool parse_json_string(const char* str, BaseHandler* handler, ParseStatus* status);\n    bool parse_json_file(std::FILE* fp, BaseHandler* handler, ParseStatus* status);\n    std::string serialize_json_string(const BaseHandler* handler);\n    bool serialize_json_file(std::FILE* fp, const BaseHandler* handler);\n    std::string serialize_pretty_json_string(const BaseHandler* handler);\n    bool serialize_pretty_json_file(std::FILE* fp, const BaseHandler* handler);\n\n    struct FileGuard : private NonMobile\n    {\n        std::FILE* fp;\n\n        explicit FileGuard(std::FILE* fp) : fp(fp) {}\n        ~FileGuard()\n        {\n            if (fp)\n                std::fclose(fp);\n        }\n    };\n}\n\ntemplate <class T>\ninline bool from_json_string(const char* str, T* value, ParseStatus* status)\n{\n    Handler<T> h(value);\n    return nonpublic::parse_json_string(str, &h, status);\n}\n\ntemplate <class T>\ninline bool from_json_file(std::FILE* fp, T* value, ParseStatus* status)\n{\n    Handler<T> h(value);\n    return nonpublic::parse_json_file(fp, &h, status);\n}\n\ntemplate <class T>\ninline bool from_json_file(const char* filename, T* value, ParseStatus* status)\n{\n    nonpublic::FileGuard fg(std::fopen(filename, \"r\"));\n    return from_json_file(fg.fp, value, status);\n}\n\ntemplate <class T>\ninline bool from_json_file(const std::string& filename, T* value, ParseStatus* status)\n{\n    return from_json_file(filename.c_str(), value, status);\n}\n\ntemplate <class T>\ninline std::string to_json_string(const T& value)\n{\n    Handler<T> h(const_cast<T*>(&value));\n    return nonpublic::serialize_json_string(&h);\n}\n\ntemplate <class T>\ninline bool to_json_file(std::FILE* fp, const T& value)\n{\n    Handler<T> h(const_cast<T*>(&value));\n    return nonpublic::serialize_json_file(fp, &h);\n}\n\ntemplate <class T>\ninline bool to_json_file(const char* filename, const T& value)\n{\n    nonpublic::FileGuard fg(std::fopen(filename, \"wb\"));\n    return to_json_file(fg.fp, value);\n}\n\ntemplate <class T>\ninline bool to_json_file(const std::string& filename, const T& value)\n{\n    return to_json_file(filename.c_str(), value);\n}\n\ntemplate <class T>\ninline std::string to_pretty_json_string(const T& value)\n{\n    Handler<T> h(const_cast<T*>(&value));\n    return nonpublic::serialize_pretty_json_string(&h);\n}\n\ntemplate <class T>\ninline bool to_pretty_json_file(std::FILE* fp, const T& value)\n{\n    Handler<T> h(const_cast<T*>(&value));\n    return nonpublic::serialize_pretty_json_file(fp, &h);\n}\n\ntemplate <class T>\ninline bool to_pretty_json_file(const char* filename, const T& value)\n{\n    nonpublic::FileGuard fg(std::fopen(filename, \"wb\"));\n    return to_pretty_json_file(fg.fp, value);\n}\n\ntemplate <class T>\ninline bool to_pretty_json_file(const std::string& filename, const T& value)\n{\n    return to_pretty_json_file(filename.c_str(), value);\n}\n\ntemplate <class T>\ninline Document export_json_schema(T* value, Document::AllocatorType* allocator = nullptr)\n{\n    Handler<T> h(value);\n    Document d;\n    h.generate_schema(d, allocator ? *allocator : d.GetAllocator());\n    return d;\n}\n}\n"
  },
  {
    "path": "include/staticjson/optional_support.hpp",
    "content": "#pragma once\n\n#include \"stl_types.hpp\"\n\n#ifdef __has_include\n#if __has_include(<optional>)\n#include <optional>\n\nnamespace staticjson\n{\n    template <typename T>\n    using optional = std::optional<T>;\n\n    using std::nullopt;\n}\n\n#elif __has_include(<experimental/optional>)\n#include <experimental/optional>\n\nnamespace staticjson\n{\n    template <typename T>\n    using optional = std::experimental::optional<T>;\n\n    using std::experimental::nullopt;\n}\n\n#else\n#error \"Missing <optional>\"\n#endif\n#else\n#error \"Missing <optional>\"\n#endif\n\nnamespace staticjson\n{\n\ntemplate <class T>\nclass Handler<optional<T>> : public BaseHandler\n{\npublic:\n    using ElementType = T;\n\nprotected:\n    mutable optional<T>* m_value;\n    mutable optional<Handler<ElementType>> internal_handler;\n    int depth = 0;\n\npublic:\n    explicit Handler(optional<T>* value) : m_value(value) {}\n\nprotected:\n    void initialize()\n    {\n        if (!internal_handler)\n        {\n            m_value->emplace();\n            internal_handler.emplace(&(**m_value));\n        }\n    }\n\n    void reset() override\n    {\n        depth = 0;\n        internal_handler = nullopt;\n        *m_value = nullopt;\n    }\n\n    bool postcheck(bool success)\n    {\n        if (success)\n            this->parsed = internal_handler->is_parsed();\n        return success;\n    }\n\npublic:\n    bool Null() override\n    {\n        if (depth == 0)\n        {\n            *m_value = nullopt;\n            this->parsed = true;\n            return true;\n        }\n        else\n        {\n            initialize();\n            return postcheck(internal_handler->Null());\n        }\n    }\n\n    bool write(IHandler* out) const override\n    {\n        if (!m_value || !(*m_value))\n        {\n            return out->Null();\n        }\n        if (!internal_handler)\n        {\n            internal_handler.emplace(&(**m_value));\n        }\n        return internal_handler->write(out);\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        const_cast<Handler<optional<T>>*>(this)->initialize();\n        output.SetObject();\n        Value anyOf(rapidjson::kArrayType);\n        Value nullDescriptor(rapidjson::kObjectType);\n        nullDescriptor.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"null\"), alloc);\n        Value descriptor;\n        internal_handler->generate_schema(descriptor, alloc);\n        anyOf.PushBack(nullDescriptor, alloc);\n        anyOf.PushBack(descriptor, alloc);\n        output.AddMember(rapidjson::StringRef(\"anyOf\"), anyOf, alloc);\n    }\n\n    bool Bool(bool b) override\n    {\n        initialize();\n        return postcheck(internal_handler->Bool(b));\n    }\n\n    bool Int(int i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Int(i));\n    }\n\n    bool Uint(unsigned i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Uint(i));\n    }\n\n    bool Int64(std::int64_t i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Int64(i));\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Uint64(i));\n    }\n\n    bool Double(double i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Double(i));\n    }\n\n    bool String(const char* str, SizeType len, bool copy) override\n    {\n        initialize();\n        return postcheck(internal_handler->String(str, len, copy));\n    }\n\n    bool Key(const char* str, SizeType len, bool copy) override\n    {\n        initialize();\n        return postcheck(internal_handler->Key(str, len, copy));\n    }\n\n    bool StartObject() override\n    {\n        initialize();\n        ++depth;\n        return internal_handler->StartObject();\n    }\n\n    bool EndObject(SizeType len) override\n    {\n        initialize();\n        --depth;\n        return postcheck(internal_handler->EndObject(len));\n    }\n\n    bool StartArray() override\n    {\n        initialize();\n        ++depth;\n        return postcheck(internal_handler->StartArray());\n    }\n\n    bool EndArray(SizeType len) override\n    {\n        initialize();\n        --depth;\n        return postcheck(internal_handler->EndArray(len));\n    }\n\n    bool has_error() const override { return internal_handler && internal_handler->has_error(); }\n\n    bool reap_error(ErrorStack& stk) override\n    {\n        return internal_handler && internal_handler->reap_error(stk);\n    }\n\n    std::string type_name() const override\n    {\n        if (this->internal_handler)\n        {\n            return \"std::optional<\" + this->internal_handler->type_name() + \">\";\n        }\n        return \"std::optional\";\n    }\n};\n}\n"
  },
  {
    "path": "include/staticjson/primitive_types.hpp",
    "content": "#pragma once\n#include <staticjson/basic.hpp>\n\n#include <limits>\n#include <string>\n#include <type_traits>\n\nnamespace staticjson\n{\n\ntemplate <class IntType>\nclass IntegerHandler : public BaseHandler\n{\n    static_assert(std::is_arithmetic<IntType>::value, \"Only arithmetic types are allowed\");\n\nprotected:\n    IntType* m_value;\n\n    template <class AnotherIntType>\n    static constexpr typename std::enable_if<std::is_integral<AnotherIntType>::value, bool>::type\n    is_out_of_range(AnotherIntType a)\n    {\n        typedef typename std::common_type<IntType, AnotherIntType>::type CommonType;\n        typedef typename std::numeric_limits<IntType> this_limits;\n        typedef typename std::numeric_limits<AnotherIntType> that_limits;\n\n        // The extra logic related to this_limits::min/max allows the compiler to\n        // short circuit this check at compile time. For instance, a `uint32_t`\n        // will NEVER be out of range for an `int64_t`\n        return ((this_limits::is_signed == that_limits::is_signed)\n                    ? ((CommonType(this_limits::min()) > CommonType(a)\n                        || CommonType(this_limits::max()) < CommonType(a)))\n                    : (this_limits::is_signed)\n                        ? (CommonType(this_limits::max()) < CommonType(a))\n                        : (a < 0 || CommonType(a) > CommonType(this_limits::max())));\n    }\n\n    template <class FloatType>\n    static constexpr typename std::enable_if<std::is_floating_point<FloatType>::value, bool>::type\n    is_out_of_range(FloatType f)\n    {\n        return static_cast<FloatType>(static_cast<IntType>(f)) != f;\n    }\n\n    template <class ReceiveNumType>\n    bool receive(ReceiveNumType r, const char* actual_type)\n    {\n        if (is_out_of_range(r))\n            return set_out_of_range(actual_type);\n        *m_value = static_cast<IntType>(r);\n        this->parsed = true;\n        return true;\n    }\n\npublic:\n    explicit IntegerHandler(IntType* value) : m_value(value) {}\n\n    bool Int(int i) override { return receive(i, \"int\"); }\n\n    bool Uint(unsigned i) override { return receive(i, \"unsigned int\"); }\n\n    bool Int64(std::int64_t i) override { return receive(i, \"std::int64_t\"); }\n\n    bool Uint64(std::uint64_t i) override { return receive(i, \"std::uint64_t\"); }\n\n    bool Double(double d) override { return receive(d, \"double\"); }\n\n    bool write(IHandler* output) const override\n    {\n        if (std::numeric_limits<IntType>::is_signed)\n        {\n            return output->Int64(*m_value);\n        }\n        else\n        {\n            return output->Uint64(*m_value);\n        }\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"integer\"), alloc);\n        Value minimum, maximum;\n        if (std::numeric_limits<IntType>::is_signed)\n        {\n            minimum.SetInt64(std::numeric_limits<IntType>::min());\n            maximum.SetInt64(std::numeric_limits<IntType>::max());\n        }\n        else\n        {\n            minimum.SetUint64(std::numeric_limits<IntType>::min());\n            maximum.SetUint64(std::numeric_limits<IntType>::max());\n        }\n        output.AddMember(rapidjson::StringRef(\"minimum\"), minimum, alloc);\n        output.AddMember(rapidjson::StringRef(\"maximum\"), maximum, alloc);\n    }\n};\n\ntemplate <>\nclass Handler<std::nullptr_t> : public BaseHandler\n{\npublic:\n    explicit Handler(std::nullptr_t*) {}\n\n    bool Null() override\n    {\n        this->parsed = true;\n        return true;\n    }\n\n    std::string type_name() const override { return \"null\"; }\n\n    bool write(IHandler* output) const override { return output->Null(); }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"null\"), alloc);\n    }\n};\n\ntemplate <>\nclass Handler<bool> : public BaseHandler\n{\nprivate:\n    bool* m_value;\n\npublic:\n    explicit Handler(bool* value) : m_value(value) {}\n\n    bool Bool(bool v) override\n    {\n        *m_value = v;\n        this->parsed = true;\n        return true;\n    }\n\n    std::string type_name() const override { return \"bool\"; }\n\n    bool write(IHandler* output) const override { return output->Bool(*m_value); }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"boolean\"), alloc);\n    }\n};\n\ntemplate <>\nclass Handler<int> : public IntegerHandler<int>\n{\npublic:\n    explicit Handler(int* i) : IntegerHandler<int>(i) {}\n\n    std::string type_name() const override { return \"int\"; }\n\n    bool write(IHandler* output) const override { return output->Int(*m_value); }\n};\n\ntemplate <>\nclass Handler<unsigned int> : public IntegerHandler<unsigned int>\n{\npublic:\n    explicit Handler(unsigned* i) : IntegerHandler<unsigned int>(i) {}\n\n    std::string type_name() const override { return \"unsigned int\"; }\n\n    bool write(IHandler* output) const override { return output->Uint(*m_value); }\n};\n\ntemplate <>\nclass Handler<long> : public IntegerHandler<long>\n{\npublic:\n    explicit Handler(long* i) : IntegerHandler<long>(i) {}\n\n    std::string type_name() const override { return \"long\"; }\n};\n\ntemplate <>\nclass Handler<unsigned long> : public IntegerHandler<unsigned long>\n{\npublic:\n    explicit Handler(unsigned long* i) : IntegerHandler<unsigned long>(i) {}\n\n    std::string type_name() const override { return \"unsigned long\"; }\n};\n\ntemplate <>\nclass Handler<long long> : public IntegerHandler<long long>\n{\npublic:\n    explicit Handler(long long* i) : IntegerHandler<long long>(i) {}\n\n    std::string type_name() const override { return \"long long\"; }\n};\n\ntemplate <>\nclass Handler<unsigned long long> : public IntegerHandler<unsigned long long>\n{\npublic:\n    explicit Handler(unsigned long long* i) : IntegerHandler<unsigned long long>(i) {}\n\n    std::string type_name() const override { return \"unsigned long long\"; }\n};\n\n// char is an alias for bool to work around the stupid `std::vector<bool>`\ntemplate <>\nclass Handler<char> : public BaseHandler\n{\nprivate:\n    char* m_value;\n\npublic:\n    explicit Handler(char* i) : m_value(i) {}\n\n    std::string type_name() const override { return \"bool\"; }\n\n    bool Bool(bool v) override\n    {\n        *this->m_value = v;\n        this->parsed = true;\n        return true;\n    }\n\n    bool write(IHandler* out) const override { return out->Bool(*m_value != 0); }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"boolean\"), alloc);\n    }\n};\n\ntemplate <>\nclass Handler<double> : public BaseHandler\n{\nprivate:\n    double* m_value;\n\npublic:\n    explicit Handler(double* v) : m_value(v) {}\n\n    bool Int(int i) override\n    {\n        *m_value = i;\n        this->parsed = true;\n        return true;\n    }\n\n    bool Uint(unsigned i) override\n    {\n        *m_value = i;\n        this->parsed = true;\n        return true;\n    }\n\n    bool Int64(std::int64_t i) override\n    {\n        *m_value = static_cast<double>(i);\n        if (static_cast<decltype(i)>(*m_value) != i)\n            return set_out_of_range(\"std::int64_t\");\n        this->parsed = true;\n        return true;\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        *m_value = static_cast<double>(i);\n        if (static_cast<decltype(i)>(*m_value) != i)\n            return set_out_of_range(\"std::uint64_t\");\n        this->parsed = true;\n        return true;\n    }\n\n    bool Double(double d) override\n    {\n        *m_value = d;\n        this->parsed = true;\n        return true;\n    }\n\n    std::string type_name() const override { return \"double\"; }\n\n    bool write(IHandler* out) const override { return out->Double(*m_value); }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"number\"), alloc);\n    }\n};\n\ntemplate <>\nclass Handler<float> : public BaseHandler\n{\nprivate:\n    float* m_value;\n\npublic:\n    explicit Handler(float* v) : m_value(v) {}\n\n    bool Int(int i) override\n    {\n        *m_value = static_cast<float>(i);\n        if (static_cast<decltype(i)>(*m_value) != i)\n            return set_out_of_range(\"int\");\n        this->parsed = true;\n        return true;\n    }\n\n    bool Uint(unsigned i) override\n    {\n        *m_value = static_cast<float>(i);\n        if (static_cast<decltype(i)>(*m_value) != i)\n            return set_out_of_range(\"unsigned int\");\n        this->parsed = true;\n        return true;\n    }\n\n    bool Int64(std::int64_t i) override\n    {\n        *m_value = static_cast<float>(i);\n        if (static_cast<decltype(i)>(*m_value) != i)\n            return set_out_of_range(\"std::int64_t\");\n        this->parsed = true;\n        return true;\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        *m_value = static_cast<float>(i);\n        if (static_cast<decltype(i)>(*m_value) != i)\n            return set_out_of_range(\"std::uint64_t\");\n        this->parsed = true;\n        return true;\n    }\n\n    bool Double(double d) override\n    {\n        *m_value = static_cast<float>(d);\n        this->parsed = true;\n        return true;\n    }\n\n    std::string type_name() const override { return \"float\"; }\n\n    bool write(IHandler* out) const override { return out->Double(*m_value); }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"number\"), alloc);\n    }\n};\n\ntemplate <>\nclass Handler<std::string> : public BaseHandler\n{\nprivate:\n    std::string* m_value;\n\npublic:\n    explicit Handler(std::string* v) : m_value(v) {}\n\n    bool String(const char* str, SizeType length, bool) override\n    {\n        m_value->assign(str, length);\n        this->parsed = true;\n        return true;\n    }\n\n    std::string type_name() const override { return \"string\"; }\n\n    bool write(IHandler* out) const override\n    {\n        return out->String(m_value->data(), SizeType(m_value->size()), true);\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"string\"), alloc);\n    }\n};\n}\n"
  },
  {
    "path": "include/staticjson/staticjson.hpp",
    "content": "#pragma once\n#include <staticjson/basic.hpp>\n#include <staticjson/document.hpp>\n#include <staticjson/enum.hpp>\n#include <staticjson/io.hpp>\n#include <staticjson/primitive_types.hpp>\n#include <staticjson/stl_types.hpp>\n"
  },
  {
    "path": "include/staticjson/stl_types.hpp",
    "content": "#pragma once\n#include <staticjson/basic.hpp>\n\n#include <array>\n#include <deque>\n#include <list>\n#include <map>\n#include <memory>\n#include <tuple>\n#include <unordered_map>\n#include <vector>\n\nnamespace staticjson\n{\ntemplate <class ArrayType>\nclass ArrayHandler : public BaseHandler\n{\npublic:\n    typedef typename ArrayType::value_type ElementType;\n\nprotected:\n    ElementType element;\n    Handler<ElementType> internal;\n    ArrayType* m_value;\n    int depth = 0;\n\nprotected:\n    void set_element_error() { the_error.reset(new error::ArrayElementError(m_value->size())); }\n\n    bool precheck(const char* type)\n    {\n        if (depth <= 0)\n        {\n            the_error.reset(new error::TypeMismatchError(type_name(), type));\n            return false;\n        }\n        return true;\n    }\n\n    bool postcheck(bool success)\n    {\n        if (!success)\n        {\n            set_element_error();\n            return false;\n        }\n        if (internal.is_parsed())\n        {\n            m_value->emplace_back(std::move(element));\n            element = ElementType();\n            internal.prepare_for_reuse();\n        }\n        return true;\n    }\n\n    void reset() override\n    {\n        element = ElementType();\n        internal.prepare_for_reuse();\n        depth = 0;\n    }\n\npublic:\n    explicit ArrayHandler(ArrayType* value) : element(), internal(&element), m_value(value) {}\n\n    bool Null() override { return precheck(\"null\") && postcheck(internal.Null()); }\n\n    bool Bool(bool b) override { return precheck(\"bool\") && postcheck(internal.Bool(b)); }\n\n    bool Int(int i) override { return precheck(\"int\") && postcheck(internal.Int(i)); }\n\n    bool Uint(unsigned i) override { return precheck(\"unsigned\") && postcheck(internal.Uint(i)); }\n\n    bool Int64(std::int64_t i) override\n    {\n        return precheck(\"int64_t\") && postcheck(internal.Int64(i));\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        return precheck(\"uint64_t\") && postcheck(internal.Uint64(i));\n    }\n\n    bool Double(double d) override { return precheck(\"double\") && postcheck(internal.Double(d)); }\n\n    bool String(const char* str, SizeType length, bool copy) override\n    {\n        return precheck(\"string\") && postcheck(internal.String(str, length, copy));\n    }\n\n    bool Key(const char* str, SizeType length, bool copy) override\n    {\n        return precheck(\"object\") && postcheck(internal.Key(str, length, copy));\n    }\n\n    bool StartObject() override { return precheck(\"object\") && postcheck(internal.StartObject()); }\n\n    bool EndObject(SizeType length) override\n    {\n        return precheck(\"object\") && postcheck(internal.EndObject(length));\n    }\n\n    bool StartArray() override\n    {\n        ++depth;\n        if (depth > 1)\n            return postcheck(internal.StartArray());\n        else\n            m_value->clear();\n        return true;\n    }\n\n    bool EndArray(SizeType length) override\n    {\n        --depth;\n\n        // When depth >= 1, this event should be forwarded to the element\n        if (depth > 0)\n            return postcheck(internal.EndArray(length));\n\n        this->parsed = true;\n        return true;\n    }\n\n    bool reap_error(ErrorStack& stk) override\n    {\n        if (!the_error)\n            return false;\n        stk.push(the_error.release());\n        internal.reap_error(stk);\n        return true;\n    }\n\n    bool write(IHandler* output) const override\n    {\n        if (!output->StartArray())\n            return false;\n        for (auto&& e : *m_value)\n        {\n            Handler<ElementType> h(&e);\n            if (!h.write(output))\n                return false;\n        }\n        return output->EndArray(static_cast<staticjson::SizeType>(m_value->size()));\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"array\"), alloc);\n        Value items;\n        internal.generate_schema(items, alloc);\n        output.AddMember(rapidjson::StringRef(\"items\"), items, alloc);\n    }\n\n    const Handler<ElementType>& get_internal_handler() const noexcept { return internal; }\n};\n\ntemplate <class T>\nclass Handler<std::vector<T>> : public ArrayHandler<std::vector<T>>\n{\npublic:\n    explicit Handler(std::vector<T>* value) : ArrayHandler<std::vector<T>>(value) {}\n\n    std::string type_name() const override\n    {\n        return \"std::vector<\" + this->internal.type_name() + \">\";\n    }\n};\n\ntemplate <class T>\nclass Handler<std::deque<T>> : public ArrayHandler<std::deque<T>>\n{\npublic:\n    explicit Handler(std::deque<T>* value) : ArrayHandler<std::deque<T>>(value) {}\n\n    std::string type_name() const override\n    {\n        return \"std::deque<\" + this->internal.type_name() + \">\";\n    }\n};\n\ntemplate <class T>\nclass Handler<std::list<T>> : public ArrayHandler<std::list<T>>\n{\npublic:\n    explicit Handler(std::list<T>* value) : ArrayHandler<std::list<T>>(value) {}\n\n    std::string type_name() const override\n    {\n        return \"std::list<\" + this->internal.type_name() + \">\";\n    }\n};\n\ntemplate <class T, size_t N>\nclass Handler<std::array<T, N>> : public BaseHandler\n{\nprotected:\n    T element;\n    Handler<T> internal;\n    std::array<T, N>* m_value;\n    size_t count = 0;\n    int depth = 0;\n\nprotected:\n    void set_element_error() { the_error.reset(new error::ArrayElementError(count)); }\n\n    void set_length_error() { the_error.reset(new error::ArrayLengthMismatchError()); }\n\n    bool precheck(const char* type)\n    {\n        if (depth <= 0)\n        {\n            the_error.reset(new error::TypeMismatchError(type_name(), type));\n            return false;\n        }\n        return true;\n    }\n\n    bool postcheck(bool success)\n    {\n        if (!success)\n        {\n            set_element_error();\n            return false;\n        }\n        if (internal.is_parsed())\n        {\n            if (count >= N)\n            {\n                set_length_error();\n                return false;\n            }\n            (*m_value)[count] = std::move(element);\n            ++count;\n            element = T();\n            internal.prepare_for_reuse();\n        }\n        return true;\n    }\n\n    void reset() override\n    {\n        element = T();\n        internal.prepare_for_reuse();\n        depth = 0;\n        count = 0;\n    }\n\npublic:\n    explicit Handler(std::array<T, N>* value) : element(), internal(&element), m_value(value) {}\n\n    bool Null() override { return precheck(\"null\") && postcheck(internal.Null()); }\n\n    bool Bool(bool b) override { return precheck(\"bool\") && postcheck(internal.Bool(b)); }\n\n    bool Int(int i) override { return precheck(\"int\") && postcheck(internal.Int(i)); }\n\n    bool Uint(unsigned i) override { return precheck(\"unsigned\") && postcheck(internal.Uint(i)); }\n\n    bool Int64(std::int64_t i) override\n    {\n        return precheck(\"int64_t\") && postcheck(internal.Int64(i));\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        return precheck(\"uint64_t\") && postcheck(internal.Uint64(i));\n    }\n\n    bool Double(double d) override { return precheck(\"double\") && postcheck(internal.Double(d)); }\n\n    bool String(const char* str, SizeType length, bool copy) override\n    {\n        return precheck(\"string\") && postcheck(internal.String(str, length, copy));\n    }\n\n    bool Key(const char* str, SizeType length, bool copy) override\n    {\n        return precheck(\"object\") && postcheck(internal.Key(str, length, copy));\n    }\n\n    bool StartObject() override { return precheck(\"object\") && postcheck(internal.StartObject()); }\n\n    bool EndObject(SizeType length) override\n    {\n        return precheck(\"object\") && postcheck(internal.EndObject(length));\n    }\n\n    bool StartArray() override\n    {\n        ++depth;\n        if (depth > 1)\n            return postcheck(internal.StartArray());\n        return true;\n    }\n\n    bool EndArray(SizeType length) override\n    {\n        --depth;\n\n        // When depth >= 1, this event should be forwarded to the element\n        if (depth > 0)\n            return postcheck(internal.EndArray(length));\n        if (count != N)\n        {\n            set_length_error();\n            return false;\n        }\n        this->parsed = true;\n        return true;\n    }\n\n    bool reap_error(ErrorStack& stk) override\n    {\n        if (!the_error)\n            return false;\n        stk.push(the_error.release());\n        internal.reap_error(stk);\n        return true;\n    }\n\n    bool write(IHandler* output) const override\n    {\n        if (!output->StartArray())\n            return false;\n        for (auto&& e : *m_value)\n        {\n            Handler<T> h(&e);\n            if (!h.write(output))\n                return false;\n        }\n        return output->EndArray(static_cast<staticjson::SizeType>(m_value->size()));\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"array\"), alloc);\n        Value items;\n        internal.generate_schema(items, alloc);\n        output.AddMember(rapidjson::StringRef(\"items\"), items, alloc);\n        output.AddMember(rapidjson::StringRef(\"minItems\"), static_cast<uint64_t>(N), alloc);\n        output.AddMember(rapidjson::StringRef(\"maxItems\"), static_cast<uint64_t>(N), alloc);\n    }\n\n    std::string type_name() const override\n    {\n        return \"std::array<\" + internal.type_name() + \", \" + std::to_string(N) + \">\";\n    }\n};\n\ntemplate <class PointerType>\nclass PointerHandler : public BaseHandler\n{\npublic:\n    typedef typename std::pointer_traits<PointerType>::element_type ElementType;\n\nprotected:\n    mutable PointerType* m_value;\n    mutable std::unique_ptr<Handler<ElementType>> internal_handler;\n    int depth = 0;\n\nprotected:\n    explicit PointerHandler(PointerType* value) : m_value(value) {}\n\n    void initialize()\n    {\n        if (!internal_handler)\n        {\n            m_value->reset(new ElementType());\n            internal_handler.reset(new Handler<ElementType>(m_value->get()));\n        }\n    }\n\n    void reset() override\n    {\n        depth = 0;\n        internal_handler.reset();\n        m_value->reset();\n    }\n\n    bool postcheck(bool success)\n    {\n        if (success)\n            this->parsed = internal_handler->is_parsed();\n        return success;\n    }\n\npublic:\n    bool Null() override\n    {\n        if (depth == 0)\n        {\n            m_value->reset();\n            this->parsed = true;\n            return true;\n        }\n        else\n        {\n            initialize();\n            return postcheck(internal_handler->Null());\n        }\n    }\n\n    bool write(IHandler* out) const override\n    {\n        if (!m_value || !m_value->get())\n        {\n            return out->Null();\n        }\n        if (!internal_handler)\n        {\n            internal_handler.reset(new Handler<ElementType>(m_value->get()));\n        }\n        return internal_handler->write(out);\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        const_cast<PointerHandler<PointerType>*>(this)->initialize();\n        output.SetObject();\n        Value anyOf(rapidjson::kArrayType);\n        Value nullDescriptor(rapidjson::kObjectType);\n        nullDescriptor.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"null\"), alloc);\n        Value descriptor;\n        internal_handler->generate_schema(descriptor, alloc);\n        anyOf.PushBack(nullDescriptor, alloc);\n        anyOf.PushBack(descriptor, alloc);\n        output.AddMember(rapidjson::StringRef(\"anyOf\"), anyOf, alloc);\n    }\n\n    bool Bool(bool b) override\n    {\n        initialize();\n        return postcheck(internal_handler->Bool(b));\n    }\n\n    bool Int(int i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Int(i));\n    }\n\n    bool Uint(unsigned i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Uint(i));\n    }\n\n    bool Int64(std::int64_t i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Int64(i));\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Uint64(i));\n    }\n\n    bool Double(double i) override\n    {\n        initialize();\n        return postcheck(internal_handler->Double(i));\n    }\n\n    bool String(const char* str, SizeType len, bool copy) override\n    {\n        initialize();\n        return postcheck(internal_handler->String(str, len, copy));\n    }\n\n    bool Key(const char* str, SizeType len, bool copy) override\n    {\n        initialize();\n        return postcheck(internal_handler->Key(str, len, copy));\n    }\n\n    bool StartObject() override\n    {\n        initialize();\n        ++depth;\n        return internal_handler->StartObject();\n    }\n\n    bool EndObject(SizeType len) override\n    {\n        initialize();\n        --depth;\n        return postcheck(internal_handler->EndObject(len));\n    }\n\n    bool StartArray() override\n    {\n        initialize();\n        ++depth;\n        return postcheck(internal_handler->StartArray());\n    }\n\n    bool EndArray(SizeType len) override\n    {\n        initialize();\n        --depth;\n        return postcheck(internal_handler->EndArray(len));\n    }\n\n    bool has_error() const override { return internal_handler && internal_handler->has_error(); }\n\n    bool reap_error(ErrorStack& stk) override\n    {\n        return internal_handler && internal_handler->reap_error(stk);\n    }\n};\n\ntemplate <class T, class Deleter>\nclass Handler<std::unique_ptr<T, Deleter>> : public PointerHandler<std::unique_ptr<T, Deleter>>\n{\npublic:\n    explicit Handler(std::unique_ptr<T, Deleter>* value)\n        : PointerHandler<std::unique_ptr<T, Deleter>>(value)\n    {\n    }\n\n    std::string type_name() const override\n    {\n        if (this->internal_handler)\n        {\n            return \"std::unique_ptr<\" + this->internal_handler->type_name() + \">\";\n        }\n        return \"std::unique_ptr\";\n    }\n};\n\ntemplate <class T>\nclass Handler<std::shared_ptr<T>> : public PointerHandler<std::shared_ptr<T>>\n{\npublic:\n    explicit Handler(std::shared_ptr<T>* value) : PointerHandler<std::shared_ptr<T>>(value) {}\n\n    std::string type_name() const override\n    {\n        if (this->internal_handler)\n        {\n            return \"std::shared_ptr<\" + this->internal_handler->type_name() + \">\";\n        }\n        return \"std::shared_ptr\";\n    }\n};\n\ntemplate <class MapType>\nclass MapHandler : public BaseHandler\n{\nprotected:\n    typedef typename MapType::mapped_type ElementType;\n\nprotected:\n    ElementType element;\n    Handler<ElementType> internal_handler;\n    MapType* m_value;\n    std::string current_key;\n    int depth = 0;\n\nprotected:\n    void reset() override\n    {\n        element = ElementType();\n        current_key.clear();\n        internal_handler.prepare_for_reuse();\n        depth = 0;\n    }\n\n    bool precheck(const char* type)\n    {\n        if (depth <= 0)\n        {\n            set_type_mismatch(type);\n            return false;\n        }\n        return true;\n    }\n\n    bool postcheck(bool success)\n    {\n        if (!success)\n        {\n            the_error.reset(new error::ObjectMemberError(current_key));\n        }\n        else\n        {\n            if (internal_handler.is_parsed())\n            {\n                m_value->emplace(std::move(current_key), std::move(element));\n                element = ElementType();\n                internal_handler.prepare_for_reuse();\n            }\n        }\n        return success;\n    }\n\npublic:\n    explicit MapHandler(MapType* value) : element(), internal_handler(&element), m_value(value) {}\n\n    bool Null() override { return precheck(\"null\") && postcheck(internal_handler.Null()); }\n\n    bool Bool(bool b) override { return precheck(\"bool\") && postcheck(internal_handler.Bool(b)); }\n\n    bool Int(int i) override { return precheck(\"int\") && postcheck(internal_handler.Int(i)); }\n\n    bool Uint(unsigned i) override\n    {\n        return precheck(\"unsigned\") && postcheck(internal_handler.Uint(i));\n    }\n\n    bool Int64(std::int64_t i) override\n    {\n        return precheck(\"int64_t\") && postcheck(internal_handler.Int64(i));\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        return precheck(\"uint64_t\") && postcheck(internal_handler.Uint64(i));\n    }\n\n    bool Double(double d) override\n    {\n        return precheck(\"double\") && postcheck(internal_handler.Double(d));\n    }\n\n    bool String(const char* str, SizeType length, bool copy) override\n    {\n        return precheck(\"string\") && postcheck(internal_handler.String(str, length, copy));\n    }\n\n    bool Key(const char* str, SizeType length, bool copy) override\n    {\n        if (depth > 1)\n            return postcheck(internal_handler.Key(str, length, copy));\n\n        current_key.assign(str, length);\n        return true;\n    }\n\n    bool StartArray() override\n    {\n        return precheck(\"array\") && postcheck(internal_handler.StartArray());\n    }\n\n    bool EndArray(SizeType length) override\n    {\n        return precheck(\"array\") && postcheck(internal_handler.EndArray(length));\n    }\n\n    bool StartObject() override\n    {\n        ++depth;\n        if (depth > 1)\n            return postcheck(internal_handler.StartObject());\n        else\n            m_value->clear();\n        return true;\n    }\n\n    bool EndObject(SizeType length) override\n    {\n        --depth;\n        if (depth > 0)\n            return postcheck(internal_handler.EndObject(length));\n        this->parsed = true;\n        return true;\n    }\n\n    bool reap_error(ErrorStack& errs) override\n    {\n        if (!this->the_error)\n            return false;\n\n        errs.push(this->the_error.release());\n        internal_handler.reap_error(errs);\n        return true;\n    }\n\n    bool write(IHandler* out) const override\n    {\n        if (!out->StartObject())\n            return false;\n        for (auto&& pair : *m_value)\n        {\n            if (!out->Key(pair.first.data(), static_cast<SizeType>(pair.first.size()), true))\n                return false;\n            Handler<ElementType> h(&pair.second);\n            if (!h.write(out))\n                return false;\n        }\n        return out->EndObject(static_cast<SizeType>(m_value->size()));\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        Value internal_schema;\n        internal_handler.generate_schema(internal_schema, alloc);\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"object\"), alloc);\n\n        Value empty_obj(rapidjson::kObjectType);\n        output.AddMember(rapidjson::StringRef(\"properties\"), empty_obj, alloc);\n        output.AddMember(rapidjson::StringRef(\"additionalProperties\"), internal_schema, alloc);\n    }\n};\n\ntemplate <class T, class Hash, class Equal>\nclass Handler<std::unordered_map<std::string, T, Hash, Equal>>\n    : public MapHandler<std::unordered_map<std::string, T, Hash, Equal>>\n{\npublic:\n    explicit Handler(std::unordered_map<std::string, T, Hash, Equal>* value)\n        : MapHandler<std::unordered_map<std::string, T, Hash, Equal>>(value)\n    {\n    }\n\n    std::string type_name() const override\n    {\n        return \"std::unordered_map<std::string, \" + this->internal_handler.type_name() + \">\";\n    }\n};\n\ntemplate <class T, class Hash, class Equal>\nclass Handler<std::map<std::string, T, Hash, Equal>>\n    : public MapHandler<std::map<std::string, T, Hash, Equal>>\n{\npublic:\n    explicit Handler(std::map<std::string, T, Hash, Equal>* value)\n        : MapHandler<std::map<std::string, T, Hash, Equal>>(value)\n    {\n    }\n\n    std::string type_name() const override\n    {\n        return \"std::map<std::string, \" + this->internal_handler.type_name() + \">\";\n    }\n};\n\ntemplate <class T, class Hash, class Equal>\nclass Handler<std::unordered_multimap<std::string, T, Hash, Equal>>\n    : public MapHandler<std::unordered_multimap<std::string, T, Hash, Equal>>\n{\npublic:\n    explicit Handler(std::unordered_multimap<std::string, T, Hash, Equal>* value)\n        : MapHandler<std::unordered_multimap<std::string, T, Hash, Equal>>(value)\n    {\n    }\n\n    std::string type_name() const override\n    {\n        return \"std::unordered_mulitimap<std::string, \" + this->internal_handler.type_name() + \">\";\n    }\n};\n\ntemplate <class T, class Hash, class Equal>\nclass Handler<std::multimap<std::string, T, Hash, Equal>>\n    : public MapHandler<std::multimap<std::string, T, Hash, Equal>>\n{\npublic:\n    explicit Handler(std::multimap<std::string, T, Hash, Equal>* value)\n        : MapHandler<std::multimap<std::string, T, Hash, Equal>>(value)\n    {\n    }\n\n    std::string type_name() const override\n    {\n        return \"std::multimap<std::string, \" + this->internal_handler.type_name() + \">\";\n    }\n};\n\ntemplate <std::size_t N>\nclass TupleHander : public BaseHandler\n{\nprotected:\n    std::array<std::unique_ptr<BaseHandler>, N> handlers;\n    std::size_t index = 0;\n    int depth = 0;\n\n    bool postcheck(bool success)\n    {\n        if (!success)\n        {\n            the_error.reset(new error::ArrayElementError(index));\n            return false;\n        }\n        if (handlers[index]->is_parsed())\n        {\n            ++index;\n        }\n        return true;\n    }\n\nprotected:\n    void reset() override\n    {\n        index = 0;\n        depth = 0;\n        for (auto&& h : handlers)\n            h->prepare_for_reuse();\n    }\n\npublic:\n    bool Null() override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Null());\n    }\n\n    bool Bool(bool b) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Bool(b));\n    }\n\n    bool Int(int i) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Int(i));\n    }\n\n    bool Uint(unsigned i) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Uint(i));\n    }\n\n    bool Int64(std::int64_t i) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Int64(i));\n    }\n\n    bool Uint64(std::uint64_t i) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Uint64(i));\n    }\n\n    bool Double(double d) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Double(d));\n    }\n\n    bool String(const char* str, SizeType length, bool copy) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->String(str, length, copy));\n    }\n\n    bool Key(const char* str, SizeType length, bool copy) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->Key(str, length, copy));\n    }\n\n    bool StartArray() override\n    {\n        if (++depth > 1)\n        {\n            if (index >= N)\n                return true;\n            return postcheck(handlers[index]->StartArray());\n        }\n        return true;\n    }\n\n    bool EndArray(SizeType length) override\n    {\n        if (--depth > 0)\n        {\n            if (index >= N)\n                return true;\n            return postcheck(handlers[index]->EndArray(length));\n        }\n        this->parsed = true;\n        return true;\n    }\n\n    bool StartObject() override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->StartObject());\n    }\n\n    bool EndObject(SizeType length) override\n    {\n        if (index >= N)\n            return true;\n        return postcheck(handlers[index]->EndObject(length));\n    }\n\n    bool reap_error(ErrorStack& errs) override\n    {\n        if (!this->the_error)\n            return false;\n\n        errs.push(this->the_error.release());\n        for (auto&& h : handlers)\n            h->reap_error(errs);\n        return true;\n    }\n\n    bool write(IHandler* out) const override\n    {\n        if (!out->StartArray())\n            return false;\n        for (auto&& h : handlers)\n        {\n            if (!h->write(out))\n                return false;\n        }\n        return out->EndArray(N);\n    }\n\n    void generate_schema(Value& output, MemoryPoolAllocator& alloc) const override\n    {\n        output.SetObject();\n        output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"array\"), alloc);\n        Value items(rapidjson::kArrayType);\n        for (auto&& h : handlers)\n        {\n            Value item;\n            h->generate_schema(item, alloc);\n            items.PushBack(item, alloc);\n        }\n        output.AddMember(rapidjson::StringRef(\"items\"), items, alloc);\n    }\n};\n\nnamespace nonpublic\n{\n    template <std::size_t index, std::size_t N, typename Tuple>\n    struct TupleIniter\n    {\n        void operator()(std::unique_ptr<BaseHandler>* handlers, Tuple& t) const\n        {\n            handlers[index].reset(\n                new Handler<typename std::tuple_element<index, Tuple>::type>(&std::get<index>(t)));\n            TupleIniter<index + 1, N, Tuple>{}(handlers, t);\n        }\n    };\n\n    template <std::size_t N, typename Tuple>\n    struct TupleIniter<N, N, Tuple>\n    {\n        void operator()(std::unique_ptr<BaseHandler>* handlers, Tuple& t) const\n        {\n            (void)handlers;\n            (void)t;\n        }\n    };\n}\n\ntemplate <typename... Ts>\nclass Handler<std::tuple<Ts...>> : public TupleHander<std::tuple_size<std::tuple<Ts...>>::value>\n{\nprivate:\n    static const std::size_t N = std::tuple_size<std::tuple<Ts...>>::value;\n\npublic:\n    explicit Handler(std::tuple<Ts...>* t)\n    {\n        nonpublic::TupleIniter<0, N, std::tuple<Ts...>> initer;\n        initer(this->handlers.data(), *t);\n    }\n\n    std::string type_name() const override\n    {\n        std::string str = \"std::tuple<\";\n        for (auto&& h : this->handlers)\n        {\n            str += h->type_name();\n            str += \", \";\n        }\n        str.pop_back();\n        str.pop_back();\n        str += '>';\n        return str;\n    }\n};\n}\n"
  },
  {
    "path": "src/staticjson.cpp",
    "content": "#include <staticjson/document.hpp>\n#include <staticjson/staticjson.hpp>\n\n#include <rapidjson/error/en.h>\n#include <rapidjson/error/error.h>\n#include <rapidjson/filereadstream.h>\n#include <rapidjson/filewritestream.h>\n#include <rapidjson/prettywriter.h>\n#include <rapidjson/reader.h>\n#include <rapidjson/writer.h>\n\n#include <cstdarg>\n#include <cstdio>\n#include <cstdlib>\n#include <exception>\n#include <new>\n\nnamespace staticjson\n{\n// Adapted from Jettison's implementation (http://jettison.codehaus.org/)\n// Original copyright (compatible with MIT):\n\n// Copyright 2006 Envoi Solutions LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\ninline std::string quote(const std::string& str)\n{\n    std::string sb;\n    sb.reserve(str.size() + 8);\n    sb += '\\\"';\n\n    typedef std::string::const_iterator iterator;\n\n    for (iterator it = str.begin(), end = str.end(); it != end; ++it)\n    {\n        char c = *it;\n        switch (c)\n        {\n        case '\\\\':\n        case '\"':\n            sb += '\\\\';\n            sb += c;\n            break;\n        case '\\b':\n            sb.append(\"\\\\b\", 2);\n            break;\n        case '\\t':\n            sb.append(\"\\\\t\", 2);\n            break;\n        case '\\n':\n            sb.append(\"\\\\n\", 2);\n            break;\n        case '\\f':\n            sb.append(\"\\\\f\", 2);\n            break;\n        case '\\r':\n            sb.append(\"\\\\r\", 2);\n            break;\n        case '\\x00':\n            sb.append(\"\\\\x00\", 4);\n            break;\n        case '\\x01':\n            sb.append(\"\\\\x01\", 4);\n            break;\n        case '\\x02':\n            sb.append(\"\\\\x02\", 4);\n            break;\n        case '\\x03':\n            sb.append(\"\\\\x03\", 4);\n            break;\n        case '\\x04':\n            sb.append(\"\\\\x04\", 4);\n            break;\n        case '\\x05':\n            sb.append(\"\\\\x05\", 4);\n            break;\n        case '\\x06':\n            sb.append(\"\\\\x06\", 4);\n            break;\n        case '\\x07':\n            sb.append(\"\\\\x07\", 4);\n            break;\n        case '\\x0b':\n            sb.append(\"\\\\x0b\", 4);\n            break;\n        case '\\x0e':\n            sb.append(\"\\\\x0e\", 4);\n            break;\n        case '\\x0f':\n            sb.append(\"\\\\x0f\", 4);\n            break;\n        case '\\x10':\n            sb.append(\"\\\\x10\", 4);\n            break;\n        case '\\x11':\n            sb.append(\"\\\\x11\", 4);\n            break;\n        case '\\x12':\n            sb.append(\"\\\\x12\", 4);\n            break;\n        case '\\x13':\n            sb.append(\"\\\\x13\", 4);\n            break;\n        case '\\x14':\n            sb.append(\"\\\\x14\", 4);\n            break;\n        case '\\x15':\n            sb.append(\"\\\\x15\", 4);\n            break;\n        case '\\x16':\n            sb.append(\"\\\\x16\", 4);\n            break;\n        case '\\x17':\n            sb.append(\"\\\\x17\", 4);\n            break;\n        case '\\x18':\n            sb.append(\"\\\\x18\", 4);\n            break;\n        case '\\x19':\n            sb.append(\"\\\\x19\", 4);\n            break;\n        case '\\x1a':\n            sb.append(\"\\\\x1a\", 4);\n            break;\n        case '\\x1b':\n            sb.append(\"\\\\x1b\", 4);\n            break;\n        case '\\x1c':\n            sb.append(\"\\\\x1c\", 4);\n            break;\n        case '\\x1d':\n            sb.append(\"\\\\x1d\", 4);\n            break;\n        case '\\x1e':\n            sb.append(\"\\\\x1e\", 4);\n            break;\n        case '\\x1f':\n            sb.append(\"\\\\x1f\", 4);\n            break;\n        default:\n            sb += c;\n        }\n    }\n    sb += '\\\"';\n    return sb;\n}\n\nstatic std::string stringprintf(const char* format, ...)\n#ifndef _MSC_VER\n    __attribute__((format(printf, 1, 2)))\n#endif\n    ;\n\nstatic std::string stringprintf(const char* format, ...)\n{\n    va_list ap;\n    va_start(ap, format);\n    int sz = vsnprintf(nullptr, 0, format, ap);\n    va_end(ap);\n\n    if (sz <= 0)\n        return std::string();\n\n    std::string result(sz, 0);\n    va_start(ap, format);\n    vsnprintf(&result[0], static_cast<size_t>(sz + 1), format, ap);\n    va_end(ap);\n    return result;\n}\n\nstd::string error::Success::description() const { return \"No error\"; }\n\nstd::string error::ObjectMemberError::description() const\n{\n    return \"Error at object member with name \" + quote(member_name());\n}\n\nstd::string error::ArrayElementError::description() const\n{\n    return \"Error at array element at index \" + std::to_string(index());\n}\n\nstd::string error::RequiredFieldMissingError::description() const\n{\n    std::string result = \"Missing required field(s): \";\n    bool first = true;\n    for (auto&& name : missing_members())\n    {\n        if (!first)\n        {\n            result += \", \";\n        }\n        first = false;\n        result += quote(name);\n    }\n    return result;\n}\n\nstd::string error::NumberOutOfRangeError::description() const\n{\n    return \"Number out of range: expected type \" + quote(expected_type())\n        + \" but the type needed is \" + quote(actual_type());\n}\n\nstd::string error::TypeMismatchError::description() const\n{\n    return \"Type mismatch between expected type \" + quote(expected_type()) + \" and actual type \"\n        + quote(actual_type());\n}\n\nstd::string error::DuplicateKeyError::description() const\n{\n    return \"Duplicate key in uniquely keyed map type: \" + quote(key());\n}\n\nstd::string error::UnknownFieldError::description() const\n{\n    return \"Unknown field with name: \" + quote(field_name());\n}\n\nstd::string error::RecursionTooDeepError::description() const\n{\n    return \"Too many levels of recursion\";\n}\nstd::string error::TooManyLeavesError::description() const { return \"Too many leaves\"; }\nstd::string error::CorruptedDOMError::description() const { return \"JSON has invalid structure\"; }\n\nstd::string error::ArrayLengthMismatchError::description() const\n{\n    return \"The JSON array has different length than the required type\";\n}\n\nstd::string error::InvalidEnumError::description() const\n{\n    return quote(m_name) + \" is an invalid enum name\";\n}\n\nstd::string error::CustomError::description() const { return m_message; }\n\nstd::string ParseStatus::short_description() const\n{\n    if (!has_error())\n    {\n        return std::string();\n    }\n    return stringprintf(\n        \"Parsing failed at offset %lld with error code %d:\\n%s\\n\",\n        static_cast<long long>(m_offset),\n        m_code,\n        rapidjson::GetParseError_En(static_cast<rapidjson::ParseErrorCode>(m_code)));\n}\n\nstd::string ParseStatus::description() const\n{\n    std::string res = short_description();\n    if (m_stack)\n    {\n        res += \"\\nTraceback (last call first)\\n\";\n\n        for (auto&& err : m_stack)\n        {\n            res += \"* \";\n            res += err.description();\n            res += '\\n';\n        }\n    }\n    return res;\n}\n\nIHandler::~IHandler() {}\n\nBaseHandler::~BaseHandler() {}\n\nbool BaseHandler::set_out_of_range(const char* actual_type)\n{\n    the_error.reset(new error::NumberOutOfRangeError(type_name(), actual_type));\n    return false;\n}\n\nbool BaseHandler::set_type_mismatch(const char* actual_type)\n{\n    the_error.reset(new error::TypeMismatchError(type_name(), actual_type));\n    return false;\n}\n\nbool IHandler::RawNumber(const char*, SizeType, bool)\n{\n    fprintf(stderr, \"%s\", \"Calling non-overridden IHandler::RawNumber() is a programming bug!\\n\");\n    std::terminate();\n}\n\nObjectHandler::ObjectHandler()\n    : memory_pool_allocator(GlobalConfig::getInstance()->getMemoryChunkSize(),\n                            &mempool::get_crt_allocator())\n    , internals(decltype(internals)::allocator_type(&memory_pool_allocator))\n    , current_name(decltype(current_name)::allocator_type(&memory_pool_allocator))\n    , leavesStack(decltype(leavesStack)::container_type::allocator_type(&memory_pool_allocator))\n{\n}\n\nObjectHandler::~ObjectHandler() {}\n\nstd::string ObjectHandler::type_name() const { return \"object\"; }\n\nvoid ObjectHandler::postinit()\n{\n    size_t max_string_size = 0;\n    for (const auto& pair : internals)\n    {\n        max_string_size = std::max<size_t>(max_string_size, pair.first.size());\n    }\n    if (max_string_size)\n    {\n        current_name.reserve(max_string_size);\n    }\n}\n\nbool ObjectHandler::precheck(const char* actual_type)\n{\n    if (depth <= 0)\n    {\n        the_error.reset(new error::TypeMismatchError(type_name(), actual_type));\n        return false;\n    }\n    if (current && current->handler && current->handler->is_parsed())\n    {\n        if (flags & Flags::AllowDuplicateKey)\n        {\n            current->handler->prepare_for_reuse();\n        }\n        else\n        {\n            the_error.reset(new error::DuplicateKeyError(mempool::to_std_string(current_name)));\n            return false;\n        }\n    }\n    return true;\n}\n\nbool ObjectHandler::postcheck(bool success)\n{\n    if (!success)\n    {\n        the_error.reset(new error::ObjectMemberError(mempool::to_std_string(current_name)));\n    }\n    return success;\n}\n\nvoid ObjectHandler::set_missing_required(const std::string& name)\n{\n    if (!the_error || the_error->type() != error::MISSING_REQUIRED)\n        the_error.reset(new error::RequiredFieldMissingError());\n\n    std::vector<std::string>& missing\n        = static_cast<error::RequiredFieldMissingError*>(the_error.get())->missing_members();\n\n    missing.push_back(name);\n}\n\n#define POSTCHECK(x) (!current || !(current->handler) || postcheck(x))\n\nbool ObjectHandler::Double(double value)\n{\n    if (!precheck(\"double\"))\n        return false;\n    return POSTCHECK(current->handler->Double(value));\n}\n\nbool ObjectHandler::Int(int value)\n{\n    if (!precheck(\"int\"))\n        return false;\n    return POSTCHECK(current->handler->Int(value));\n}\n\nbool ObjectHandler::Uint(unsigned value)\n{\n    if (!precheck(\"unsigned\"))\n        return false;\n    return POSTCHECK(current->handler->Uint(value));\n}\n\nbool ObjectHandler::Bool(bool value)\n{\n    if (!precheck(\"bool\"))\n        return false;\n    return POSTCHECK(current->handler->Bool(value));\n}\n\nbool ObjectHandler::Int64(std::int64_t value)\n{\n    if (!precheck(\"std::int64_t\"))\n        return false;\n    return POSTCHECK(current->handler->Int64(value));\n}\n\nbool ObjectHandler::Uint64(std::uint64_t value)\n{\n    if (!precheck(\"std::uint64_t\"))\n        return false;\n    return POSTCHECK(current->handler->Uint64(value));\n}\n\nbool ObjectHandler::Null()\n{\n    if (!precheck(\"null\"))\n        return false;\n    return POSTCHECK(current->handler->Null());\n}\nbool ObjectHandler::StartCheckMaxDepthMaxLeaves(bool isArray)\n{\n    if (GlobalConfig::getInstance()->isMaxDepthSet())\n    {\n        ++jsonDepth;\n        // If a leaf IE is an array of a simple data type, then the whole array shall be considered\n        // as the first level of nesting. If a leaf IE is a data structure or an array of data\n        // structures, then it shall be considered a branch and the first level of nesting.\n        if (jsonDepth > GlobalConfig::getInstance()->getMaxDepth())\n        {\n            if (!the_error || the_error->type() != error::TOO_DEEP_RECURSION)\n                the_error.reset(new error::RecursionTooDeepError());\n            jsonDepth = 0;\n            return false;\n        }\n    }\n    if (GlobalConfig::getInstance()->isMaxLeavesSet())\n    {\n        if (isArray)\n        {\n            lastLeafStat = true;\n        }\n        else\n        {\n            lastLeafStat = false;\n        }\n        leavesStack.push(0);\n    }\n    return true;\n}\n\nbool ObjectHandler::EndCheckMaxDepthMaxLeaves(SizeType sz, bool isArray)\n{\n    if (GlobalConfig::getInstance()->isMaxDepthSet())\n    {\n        --jsonDepth;\n    }\n    if (GlobalConfig::getInstance()->isMaxLeavesSet())\n    {\n        if (isArray)\n        {\n            if (lastLeafStat && sz > 0)\n            {\n                // simple array type\n                // sz > 0 check if it is an empty array, and should not increase total leaf number\n                // for empty array\n                // TS29501 chapter 6.2\n                // If a leaf IE is an array of a simple data type, then the whole array shall count\n                // as one leaf.\n                totalLeaves += 1;\n            }\n        }\n        else\n        {\n            // object type\n            totalLeaves += sz;\n            totalLeaves -= leavesStack.top();\n        }\n\n        if (totalLeaves > GlobalConfig::getInstance()->getMaxLeaves())\n        {\n            if (!the_error || the_error->type() != error::TOO_MANY_LEAVES)\n                the_error.reset(new error::TooManyLeavesError());\n            totalLeaves = 0;\n            return false;\n        }\n        leavesStack.pop();\n        if (!leavesStack.empty())\n        {\n            leavesStack.top()++;\n        }\n        lastLeafStat = false;\n    }\n    return true;\n}\n\nbool ObjectHandler::StartArray()\n{\n    if (!StartCheckMaxDepthMaxLeaves(true))\n        return false;\n    if (!precheck(\"array\"))\n        return false;\n    return POSTCHECK(current->handler->StartArray());\n}\n\nbool ObjectHandler::EndArray(SizeType sz)\n{\n    if (!EndCheckMaxDepthMaxLeaves(sz, true))\n        return false;\n    if (!precheck(\"array\"))\n        return false;\n    return POSTCHECK(current->handler->EndArray(sz));\n}\n\nbool ObjectHandler::String(const char* str, SizeType sz, bool copy)\n{\n    if (!precheck(\"string\"))\n        return false;\n    return POSTCHECK(current->handler->String(str, sz, copy));\n}\n\nbool ObjectHandler::Key(const char* str, SizeType sz, bool copy)\n{\n    if (depth <= 0)\n    {\n        the_error.reset(new error::CorruptedDOMError());\n        return false;\n    }\n    if (depth == 1)\n    {\n        current_name.assign(str, sz);\n        auto it = internals.find(current_name);\n        if (it == internals.end())\n        {\n            current = nullptr;\n            if ((flags & Flags::DisallowUnknownKey))\n            {\n                the_error.reset(new error::UnknownFieldError(str, sz));\n                return false;\n            }\n        }\n        else if (it->second.flags & Flags::IgnoreRead)\n        {\n            current = nullptr;\n        }\n        else\n        {\n            current = &it->second;\n        }\n        return true;\n    }\n    else\n    {\n        return POSTCHECK(current->handler->Key(str, sz, copy));\n    }\n}\n\nbool ObjectHandler::StartObject()\n{\n    ++depth;\n    if (!StartCheckMaxDepthMaxLeaves(false))\n    {\n        return false;\n    }\n\n    if (depth > 1)\n    {\n        return POSTCHECK(current->handler->StartObject());\n    }\n    return true;\n}\n\nbool ObjectHandler::EndObject(SizeType sz)\n{\n    --depth;\n    if (!EndCheckMaxDepthMaxLeaves(sz, false))\n    {\n        return false;\n    }\n    if (depth > 0)\n    {\n        return POSTCHECK(current->handler->EndObject(sz));\n    }\n    for (auto&& pair : internals)\n    {\n        if (pair.second.handler && !(pair.second.flags & Flags::Optional)\n            && !pair.second.handler->is_parsed())\n        {\n            set_missing_required(mempool::to_std_string(pair.first));\n        }\n    }\n    if (!the_error)\n    {\n        this->parsed = true;\n        return true;\n    }\n    return false;\n}\n\nvoid ObjectHandler::reset()\n{\n    current = nullptr;\n    current_name.clear();\n    depth = 0;\n    for (auto&& pair : internals)\n    {\n        if (pair.second.handler)\n            pair.second.handler->prepare_for_reuse();\n    }\n}\n\nvoid ObjectHandler::add_handler(mempool::String&& name, ObjectHandler::FlaggedHandler&& fh)\n{\n    internals.emplace(std::move(name), std::move(fh));\n}\n\nbool ObjectHandler::reap_error(ErrorStack& stack)\n{\n    if (!the_error)\n        return false;\n    stack.push(the_error.release());\n    if (current && current->handler)\n        current->handler->reap_error(stack);\n    return true;\n}\n\nbool ObjectHandler::write(IHandler* output) const\n{\n    SizeType count = 0;\n    if (!output->StartObject())\n        return false;\n\n    for (auto&& pair : internals)\n    {\n        if (!pair.second.handler || (pair.second.flags & Flags::IgnoreWrite))\n            continue;\n        if (!output->Key(\n                pair.first.data(), static_cast<staticjson::SizeType>(pair.first.size()), true))\n            return false;\n        if (!pair.second.handler->write(output))\n            return false;\n        ++count;\n    }\n    return output->EndObject(count);\n}\n\nvoid ObjectHandler::generate_schema(Value& output, MemoryPoolAllocator& alloc) const\n{\n    output.SetObject();\n    output.AddMember(rapidjson::StringRef(\"type\"), rapidjson::StringRef(\"object\"), alloc);\n\n    Value properties(rapidjson::kObjectType);\n    Value required(rapidjson::kArrayType);\n    for (auto&& pair : internals)\n    {\n        Value schema;\n        if (pair.second.handler)\n            pair.second.handler->generate_schema(schema, alloc);\n        else\n            std::abort();\n        Value key;\n        key.SetString(pair.first.c_str(), static_cast<SizeType>(pair.first.size()), alloc);\n        properties.AddMember(key, schema, alloc);\n        if (!(pair.second.flags & Flags::Optional))\n        {\n            key.SetString(pair.first.c_str(), static_cast<SizeType>(pair.first.size()), alloc);\n            required.PushBack(key, alloc);\n        }\n    }\n    output.AddMember(rapidjson::StringRef(\"properties\"), properties, alloc);\n    if (!required.Empty())\n    {\n        output.AddMember(rapidjson::StringRef(\"required\"), required, alloc);\n    }\n    output.AddMember(rapidjson::StringRef(\"additionalProperties\"),\n                     !(get_flags() & Flags::DisallowUnknownKey),\n                     alloc);\n}\n\nnamespace nonpublic\n{\n    template <class T>\n    class IHandlerAdapter : public IHandler\n    {\n    private:\n        T* t;\n\n    public:\n        explicit IHandlerAdapter(T* t) : t(t) {}\n\n        virtual bool Null() override { return t->Null(); }\n\n        virtual bool Bool(bool v) override { return t->Bool(v); }\n\n        virtual bool Int(int v) override { return t->Int(v); }\n\n        virtual bool Uint(unsigned v) override { return t->Uint(v); }\n\n        virtual bool Int64(std::int64_t v) override { return t->Int64(v); }\n\n        virtual bool Uint64(std::uint64_t v) override { return t->Uint64(v); }\n\n        virtual bool Double(double v) override { return t->Double(v); }\n\n        virtual bool String(const char* str, SizeType sz, bool copy) override\n        {\n            return t->String(str, sz, copy);\n        }\n\n        virtual bool StartObject() override { return t->StartObject(); }\n\n        virtual bool Key(const char* str, SizeType sz, bool copy) override\n        {\n            return t->Key(str, sz, copy);\n        }\n\n        virtual bool EndObject(SizeType sz) override { return t->EndObject(sz); }\n\n        virtual bool StartArray() override { return t->StartArray(); }\n\n        virtual bool EndArray(SizeType sz) override { return t->EndArray(sz); }\n\n        virtual void prepare_for_reuse() override { std::terminate(); }\n    };\n\n    template <class InputStream>\n    static bool read_json(InputStream& is, BaseHandler* h, ParseStatus* status)\n    {\n        rapidjson::Reader r;\n        rapidjson::ParseResult rc = r.Parse(is, *h);\n        if (status)\n        {\n            status->set_result(rc.Code(), rc.Offset());\n            h->reap_error(status->error_stack());\n        }\n        return rc.Code() == 0;\n    }\n\n    bool parse_json_string(const char* str, BaseHandler* handler, ParseStatus* status)\n    {\n        rapidjson::StringStream is(str);\n        return read_json(is, handler, status);\n    }\n\n    bool parse_json_file(std::FILE* fp, BaseHandler* handler, ParseStatus* status)\n    {\n        if (!fp)\n            return false;\n        char buffer[1000];\n        rapidjson::FileReadStream is(fp, buffer, sizeof(buffer));\n        return read_json(is, handler, status);\n    }\n\n    struct StringOutputStream : private NonMobile\n    {\n        typedef char Ch;\n\n        std::string* str;\n\n        void Put(char c) { str->push_back(c); }\n\n        void Flush() {}\n    };\n\n    std::string serialize_json_string(const BaseHandler* handler)\n    {\n        std::string result;\n        StringOutputStream os;\n        os.str = &result;\n        rapidjson::Writer<StringOutputStream> writer(os);\n        IHandlerAdapter<decltype(writer)> adapter(&writer);\n        handler->write(&adapter);\n        return result;\n    }\n\n    bool serialize_json_file(std::FILE* fp, const BaseHandler* handler)\n    {\n        if (!fp)\n            return false;\n        char buffer[1000];\n        rapidjson::FileWriteStream os(fp, buffer, sizeof(buffer));\n        rapidjson::Writer<rapidjson::FileWriteStream> writer(os);\n        IHandlerAdapter<decltype(writer)> adapter(&writer);\n        return handler->write(&adapter);\n    }\n\n    std::string serialize_pretty_json_string(const BaseHandler* handler)\n    {\n        std::string result;\n        StringOutputStream os;\n        os.str = &result;\n        rapidjson::PrettyWriter<StringOutputStream> writer(os);\n        IHandlerAdapter<decltype(writer)> adapter(&writer);\n        handler->write(&adapter);\n        result.push_back('\\n');\n        return result;\n    }\n\n    bool serialize_pretty_json_file(std::FILE* fp, const BaseHandler* handler)\n    {\n        if (!fp)\n            return false;\n        char buffer[1000];\n        rapidjson::FileWriteStream os(fp, buffer, sizeof(buffer));\n        rapidjson::PrettyWriter<rapidjson::FileWriteStream> writer(os);\n        IHandlerAdapter<decltype(writer)> adapter(&writer);\n        bool res = handler->write(&adapter);\n        if (res)\n        {\n            putc('\\n', fp);\n        }\n        return res;\n    }\n\n    bool write_value(const Value& v, BaseHandler* out, ParseStatus* status)\n    {\n        if (!v.Accept(*static_cast<IHandler*>(out)))\n        {\n            if (status)\n            {\n                status->set_result(rapidjson::kParseErrorTermination, 0);\n                out->reap_error(status->error_stack());\n            }\n            return false;\n        }\n        return true;\n    }\n\n    bool\n    read_value(Value* v, MemoryPoolAllocator* alloc, const BaseHandler* input, ParseStatus* status)\n    {\n        JSONHandler handler(v, alloc);\n        if (!input->write(&handler))\n        {\n            if (status)\n            {\n                status->set_result(rapidjson::kParseErrorTermination, 0);\n                handler.reap_error(status->error_stack());\n            }\n            return false;\n        }\n        return true;\n    }\n}\n\nJSONHandler::JSONHandler(Value* v, MemoryPoolAllocator* a) : m_stack(), m_value(v), m_alloc(a)\n{\n    m_stack.reserve(25);\n}\n\nbool JSONHandler::set_corrupted_dom()\n{\n    the_error.reset(new error::CorruptedDOMError());\n    return false;\n}\n\nstd::string JSONHandler::type_name() const { return \"JSON\"; }\n\nbool JSONHandler::stack_push()\n{\n    m_stack.emplace_back();\n    return true;\n}\n\nvoid JSONHandler::stack_pop()\n{\n    if (!m_stack.empty())\n        m_stack.pop_back();\n}\n\nValue& JSONHandler::stack_top()\n{\n    if (m_stack.empty())\n        return *m_value;\n    return m_stack.back();\n}\n\nbool JSONHandler::postprocess()\n{\n    if (m_stack.empty())\n    {\n        this->parsed = true;\n        return true;\n    }\n\n    Value top1(std::move(stack_top()));\n    stack_pop();\n    if (stack_top().IsArray())\n    {\n        stack_top().PushBack(top1, *m_alloc);\n        return stack_push();\n    }\n    else if (stack_top().IsString())\n    {\n        Value key(std::move(stack_top()));\n        stack_pop();\n        if (!stack_top().IsObject())\n            return set_corrupted_dom();\n        stack_top().AddMember(key, top1, *m_alloc);\n        return true;\n    }\n    return set_corrupted_dom();\n}\n\nbool JSONHandler::Null()\n{\n    stack_top().SetNull();\n    return postprocess();\n}\n\nbool JSONHandler::Bool(bool b)\n{\n    stack_top().SetBool(b);\n    return postprocess();\n}\n\nbool JSONHandler::Double(double d)\n{\n    stack_top().SetDouble(d);\n    return postprocess();\n}\n\nbool JSONHandler::Int(int i)\n{\n    stack_top().SetInt(i);\n    return postprocess();\n}\n\nbool JSONHandler::Int64(std::int64_t i)\n{\n    stack_top().SetInt64(i);\n    return postprocess();\n}\n\nbool JSONHandler::Uint(unsigned int i)\n{\n    stack_top().SetUint(i);\n    return postprocess();\n}\n\nbool JSONHandler::Uint64(std::uint64_t i)\n{\n    stack_top().SetUint64(i);\n    return postprocess();\n}\n\nbool JSONHandler::String(const char* str, SizeType sz, bool copy)\n{\n    if (copy)\n        stack_top().SetString(str, sz, *m_alloc);\n    else\n        stack_top().SetString(str, sz);\n    return postprocess();\n}\n\nbool JSONHandler::Key(const char* str, SizeType sz, bool copy)\n{\n    if (!stack_top().IsObject())\n        return set_corrupted_dom();\n    if (!stack_push())\n        return false;\n    if (copy)\n        stack_top().SetString(str, sz, *m_alloc);\n    else\n        stack_top().SetString(str, sz);\n    return stack_push();\n}\n\nbool JSONHandler::StartArray()\n{\n    stack_top().SetArray();\n    return stack_push();\n}\n\nbool JSONHandler::EndArray(SizeType)\n{\n    stack_pop();\n    if (!stack_top().IsArray())\n        return set_corrupted_dom();\n    return postprocess();\n}\n\nbool JSONHandler::StartObject()\n{\n    stack_top().SetObject();\n    return true;\n}\n\nbool JSONHandler::EndObject(SizeType)\n{\n    if (!stack_top().IsObject())\n        return set_corrupted_dom();\n    return postprocess();\n}\n\nvoid JSONHandler::reset(MemoryPoolAllocator* a)\n{\n    for (Value& v : m_stack)\n    {\n        v.SetNull();\n    }\n\n    m_stack.clear();\n    m_alloc = a;\n}\n\nvoid JSONHandler::reset()\n{\n    // Not implemented. See https://github.com/netheril96/StaticJSON/issues/41.\n    std::terminate();\n}\n\nbool JSONHandler::write(IHandler* output) const { return m_value->Accept(*output); }\n\nGlobalConfig* GlobalConfig::getInstance() noexcept\n{\n    static GlobalConfig config;\n    return &config;\n}\n\nnamespace mempool\n{\n    [[noreturn]] void throw_bad_alloc()\n    {\n#ifdef __cpp_exceptions\n        throw std::bad_alloc();\n#else\n        abort();\n#endif\n    }\n\n    rapidjson::CrtAllocator& get_crt_allocator() noexcept\n    {\n        static rapidjson::CrtAllocator a;\n        return a;\n    }\n}\n}\n"
  },
  {
    "path": "test/myarray.hpp",
    "content": "#include <deque>\n#include <staticjson/staticjson.hpp>\n\n// This class is used to test custom conversion functions in StaticJSON.\n\ntemplate <class T>\nclass Array\n{\nprivate:\n    T* m_data;\n    size_t m_size;\n\npublic:\n    explicit Array() : m_data(nullptr), m_size(0) {}\n    explicit Array(size_t size) : m_size(size) { m_data = new T[size]; }\n    ~Array() { clear(); }\n    Array(Array&& that) noexcept\n    {\n        m_data = that.m_data;\n        m_size = that.m_size;\n        that.m_data = nullptr;\n        that.m_size = 0;\n    }\n    Array& operator=(Array&& that) noexcept\n    {\n        std::swap(m_data, that.m_data);\n        std::swap(m_size, that.m_size);\n        return *this;\n    }\n    const T& operator[](size_t i) const { return m_data[i]; }\n    T& operator[](size_t i) { return m_data[i]; }\n    size_t size() const { return m_size; }\n    const T& back() const { return m_data[m_size - 1]; }\n    T& back() { return m_data[m_size - 1]; }\n    const T& front() const { return m_data[0]; }\n    T& front() { return m_data[0]; }\n    bool empty() const { return m_size == 0; }\n    void clear()\n    {\n        delete[] m_data;\n        m_data = nullptr;\n        m_size = 0;\n    }\n};\n\nnamespace staticjson\n{\ntemplate <class T>\nstruct Converter<Array<T>>\n{\n    typedef std::deque<T> shadow_type;\n\n    static std::unique_ptr<ErrorBase> from_shadow(const shadow_type& shadow, Array<T>& value)\n    {\n        value = Array<T>(shadow.size());\n        for (size_t i = 0; i < shadow.size(); ++i)\n        {\n            value[i] = shadow[i];\n        }\n        return nullptr;\n    }\n\n    static void to_shadow(const Array<T>& value, shadow_type& shadow)\n    {\n        shadow.resize(value.size());\n        for (size_t i = 0; i < shadow.size(); ++i)\n        {\n            shadow[i] = value[i];\n        }\n    }\n};\n}\n"
  },
  {
    "path": "test/test_autojsoncxx.cpp",
    "content": "// The MIT License (MIT)\n//\n// Copyright (c) 2014 Siyuan Ren (netheril96@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n#include \"catch.hpp\"\n\n#define AUTOJSONCXX_ROOT_DIRECTORY get_base_dir() + \"/autojsoncxx/\" +\n\n#include <autojsoncxx.hpp>\n\n#include \"userdef.hpp\"\n\n#include <fstream>\n#include <stack>\n\nusing namespace autojsoncxx;\nusing namespace config;\nusing namespace config::event;\n\nconst std::string& get_base_dir(void);\n\nnamespace config\n{\ninline bool operator==(Date d1, Date d2)\n{\n    return d1.year == d2.year && d1.month == d2.month && d1.day == d2.day;\n}\n\ninline bool operator!=(Date d1, Date d2) { return !(d1 == d2); }\n}\n\nnamespace config\n{\nnamespace event\n{\n    bool operator==(const BlockEvent& b1, const BlockEvent& b2)\n    {\n        return b1.admin_ID == b2.admin_ID && b1.date == b2.date && b1.description == b2.description\n            && b1.details == b2.details && b1.serial_number == b2.serial_number;\n    }\n}\n\nbool operator==(const User& u1, const User& u2)\n{\n    return u1.birthday == u2.birthday\n        && (u1.block_event == u2.block_event\n            || (u1.block_event && u2.block_event && *u1.block_event == *u2.block_event))\n        && u1.dark_history == u2.dark_history && u1.ID == u2.ID && u1.nickname == u2.nickname\n        && u1.optional_attributes == u2.optional_attributes;\n}\n}\n\nstatic std::string read_all(const std::string& file_name)\n{\n    std::ifstream input(file_name.c_str());\n    std::ostringstream buffer;\n    buffer << input.rdbuf();\n    return buffer.str();\n}\n\nstatic Date create_date(int year, int month, int day)\n{\n    Date d;\n    d.year = year;\n    d.month = month;\n    d.day = day;\n    return d;\n}\n\n// If most of the cases fail, you probably set the work directory wrong.\n// Point the work directory to the `test/` subdirectory\n// or redefine the macro AUTOJSONCXX_ROOT_DIRECTORY.\n\nTEST_CASE(\"Test for the constructor of generated class (old)\", \"[code generator]\")\n{\n    User user;\n\n    REQUIRE(user.ID == 0ULL);\n\n    // Do not use string literal because MSVC will mess up the encoding\n    static const char default_nickname[] = {char(0xe2),\n                                            char(0x9d),\n                                            char(0xb6),\n                                            char(0xe2),\n                                            char(0x9d),\n                                            char(0xb7),\n                                            char(0xe2),\n                                            char(0x9d),\n                                            char(0xb8)};\n\n    REQUIRE(user.nickname.size() == sizeof(default_nickname));\n    REQUIRE(std::equal(user.nickname.begin(), user.nickname.end(), default_nickname));\n\n    REQUIRE(user.birthday == create_date(0, 0, 0));\n    REQUIRE(user.dark_history.empty());\n    REQUIRE(user.optional_attributes.empty());\n    REQUIRE(!user.block_event);\n\n    BlockEvent event;\n\n    REQUIRE(event.admin_ID == 255ULL);\n    REQUIRE(event.date == create_date(1970, 1, 1));\n    REQUIRE(event.serial_number == 0ULL);\n    REQUIRE(event.details.empty());\n}\n\nTEST_CASE(\"Test for correct parsing (old)\", \"[parsing]\")\n{\n    SECTION(\"Test for an array of user\", \"[parsing]\")\n    {\n        std::vector<User> users;\n        ParsingResult err;\n\n        bool success = from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/success/user_array.json\", users, err);\n        {\n            CAPTURE(err.description());\n            REQUIRE(success);\n        }\n        REQUIRE(users.size() == 2);\n\n        {\n            const User& u = users.front();\n            REQUIRE(u.ID == 7947402710862746952ULL);\n            REQUIRE(u.nickname == \"bigger than bigger\");\n            REQUIRE(u.birthday == create_date(1984, 9, 2));\n\n            REQUIRE(u.block_event.get() != nullptr);\n            const BlockEvent& e = *u.block_event;\n\n            REQUIRE(e.admin_ID > 0ULL);\n            REQUIRE(e.date == create_date(1970, 12, 31));\n            REQUIRE(e.description == \"advertisement\");\n            REQUIRE(e.details.size() > 0ULL);\n\n            REQUIRE(u.dark_history.empty());\n            REQUIRE(u.optional_attributes.empty());\n        }\n\n        {\n            const User& u = users.back();\n            REQUIRE(u.ID == 13478355757133566847ULL);\n            REQUIRE(u.nickname.size() == 15);\n            REQUIRE(!u.block_event);\n            REQUIRE(u.optional_attributes.size() == 3);\n            REQUIRE(u.optional_attributes.find(\"Self description\") != u.optional_attributes.end());\n        }\n    }\n\n    SECTION(\"Test for a map of user\", \"[parsing]\")\n    {\n        std::unordered_map<std::string, User> users;\n        ParsingResult err;\n\n        bool success = from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/success/user_map.json\", users, err);\n        {\n            CAPTURE(err.description());\n            REQUIRE(success);\n        }\n        REQUIRE(users.size() == 2);\n\n        {\n            const User& u = users[\"First\"];\n            REQUIRE(u.ID == 7947402710862746952ULL);\n            REQUIRE(u.nickname == \"bigger than bigger\");\n            REQUIRE(u.birthday == create_date(1984, 9, 2));\n\n            REQUIRE(u.block_event.get() != nullptr);\n            const BlockEvent& e = *u.block_event;\n\n            REQUIRE(e.admin_ID > 0ULL);\n            REQUIRE(e.date == create_date(1970, 12, 31));\n            REQUIRE(e.description == \"advertisement\");\n            REQUIRE(e.details.size() > 0ULL);\n\n            REQUIRE(u.dark_history.empty());\n            REQUIRE(u.optional_attributes.empty());\n        }\n\n        {\n            const User& u = users[\"Second\"];\n            REQUIRE(u.ID == 13478355757133566847ULL);\n            REQUIRE(u.nickname.size() == 15);\n            REQUIRE(!u.block_event);\n            REQUIRE(u.optional_attributes.size() == 3);\n            REQUIRE(u.optional_attributes.find(\"Self description\") != u.optional_attributes.end());\n        }\n    }\n}\n\nTEST_CASE(\"Test for mismatch between JSON and C++ class std::vector<config::User> (old)\",\n          \"[parsing], [error]\")\n{\n    std::vector<User> users;\n    ParsingResult err;\n\n    SECTION(\"Mismatch between array and object\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/single_object.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n        REQUIRE(std::distance(err.begin(), err.end()) == 1);\n\n        auto&& e = static_cast<const error::TypeMismatchError&>(*err.begin());\n\n        // REQUIRE(e.expected_type() == \"array\");\n\n        REQUIRE(e.actual_type() == \"object\");\n    }\n\n    SECTION(\"Required field not present; test the path as well\",\n            \"[parsing], [error], [missing required]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/missing_required.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(std::distance(err.begin(), err.end()) == 5);\n\n        auto it = err.begin();\n        REQUIRE(it->type() == error::MISSING_REQUIRED);\n\n        ++it;\n        REQUIRE(it->type() == error::OBJECT_MEMBER);\n        REQUIRE(static_cast<const error::ObjectMemberError&>(*it).member_name() == \"date\");\n\n        ++it;\n        REQUIRE(it->type() == error::ARRAY_ELEMENT);\n        REQUIRE(static_cast<const error::ArrayElementError&>(*it).index() == 0);\n\n        ++it;\n        REQUIRE(it->type() == error::OBJECT_MEMBER);\n        REQUIRE(static_cast<const error::ObjectMemberError&>(*it).member_name() == \"dark_history\");\n    }\n\n    SECTION(\"Unknown field in strict parsed class Date\", \"[parsing], [error], [unknown field]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/unknown_field.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::UNKNOWN_FIELD);\n\n        REQUIRE(static_cast<const error::UnknownFieldError&>(*err.begin()).field_name() == \"hour\");\n    }\n\n    SECTION(\"Duplicate key in class User\", \"[parsing], [error], [duplicate key]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/duplicate_key_user.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::DUPLICATE_KEYS);\n\n        REQUIRE(static_cast<const error::DuplicateKeyError&>(*err.begin()).key() == \"ID\");\n    }\n\n    SECTION(\"Out of range\", \"[parsing], [error], [out of range]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/out_of_range.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::NUMBER_OUT_OF_RANGE);\n    }\n\n    SECTION(\"Mismatch between integer and string\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/integer_string.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n    }\n\n    SECTION(\"Null character in key\", \"[parsing], [error], [null character]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/null_in_key.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::UNKNOWN_FIELD);\n    }\n}\n\nTEST_CASE(\"Test for mismatch between JSON and C++ class std::map<std::string, config::User> (old)\",\n          \"[parsing], [error]\")\n{\n    std::map<std::string, config::User> users;\n    ParsingResult err;\n\n    SECTION(\"Mismatch between object and array\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/success/user_array.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n\n        auto&& e = static_cast<const error::TypeMismatchError&>(*err.begin());\n        // REQUIRE(e.expected_type() == \"object\");\n        REQUIRE(e.actual_type() == \"array\");\n    }\n\n    SECTION(\"Mismatch in mapped element\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/map_element_mismatch.json\", users, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n        {\n            REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n\n            auto&& e = static_cast<const error::TypeMismatchError&>(*err.begin());\n            (void)e;\n        }\n        {\n            auto it = ++err.begin();\n            REQUIRE(it != err.end());\n            REQUIRE(it->type() == error::OBJECT_MEMBER);\n            auto&& e = static_cast<const error::ObjectMemberError&>(*it);\n            REQUIRE(e.member_name() == \"Third\");\n        }\n    }\n}\n\nTEST_CASE(\"Test for writing JSON (old)\", \"[serialization]\")\n{\n    std::vector<User> users;\n    ParsingResult err;\n\n    bool success = from_json_file(\n        AUTOJSONCXX_ROOT_DIRECTORY \"/examples/success/user_array.json\", users, err);\n    {\n        CAPTURE(err.description());\n        REQUIRE(success);\n    }\n    REQUIRE(users.size() == 2);\n\n    std::string str = to_json_string(users);\n    std::vector<User> copied_users;\n\n    success = from_json_string(str, copied_users, err);\n    {\n        CAPTURE(err.description());\n        REQUIRE(success);\n    }\n    REQUIRE(users == copied_users);\n}\n\nTEST_CASE(\"Test for DOM support (old)\", \"[DOM]\")\n{\n    rapidjson::Document doc;\n    ParsingResult err;\n    bool success = from_json_file(\n        AUTOJSONCXX_ROOT_DIRECTORY \"/examples/success/user_array_compact.json\", doc, err);\n    {\n        CAPTURE(err.description());\n        REQUIRE(success);\n    }\n\n    SECTION(\"Test for parsed result\", \"[DOM], [parsing]\")\n    {\n        REQUIRE(doc.IsArray());\n        REQUIRE(doc.Size() == 2);\n\n        const rapidjson::Value& second = doc[1u];\n        REQUIRE(second[\"ID\"].IsUint64());\n        REQUIRE(second[\"ID\"].GetUint64() == 13478355757133566847ULL);\n        REQUIRE(second[\"block_event\"].IsNull());\n        REQUIRE(second[\"dark_history\"].IsArray());\n        REQUIRE(second[\"dark_history\"][0u].IsObject());\n        REQUIRE(second[\"dark_history\"][0u][\"description\"] == \"copyright infringement\");\n    }\n\n    SECTION(\"Test for serialization\", \"[DOM], [serialization]\")\n    {\n        std::string output;\n        to_json_string(output, doc);\n        REQUIRE(\n            output\n            == read_all(AUTOJSONCXX_ROOT_DIRECTORY \"/examples/success/user_array_compact.json\"));\n    }\n\n    SECTION(\"Test for to/from DOM\", \"[DOM], [conversion]\")\n    {\n        std::vector<User> users;\n        error::ErrorStack errs;\n\n        REQUIRE(from_document(users, doc, errs));\n\n        REQUIRE(users.size() == 2);\n        REQUIRE(users[0].birthday == create_date(1984, 9, 2));\n        REQUIRE(users[0].block_event);\n        REQUIRE(users[0].block_event->details == \"most likely a troll\");\n\n        rapidjson::Document another_doc;\n        to_document(users, another_doc);\n        REQUIRE(doc == another_doc);\n    }\n}\n\nTEST_CASE(\"Test for parsing tuple type (old)\", \"[parsing], [tuple]\")\n{\n    typedef std::tuple<BlockEvent,\n                       int,\n                       std::nullptr_t,\n                       double,\n                       std::unordered_map<std::string, std::shared_ptr<User>>,\n                       bool>\n        hard_type;\n    hard_type hetero_array;\n    ParsingResult err;\n\n    SECTION(\"Test for valid tuple\", \"[parsing], [tuple]\")\n    {\n        bool success = from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/success/hard.json\", hetero_array, err);\n        {\n            CAPTURE(err.description());\n            REQUIRE(success);\n        }\n        REQUIRE(std::get<1>(hetero_array) == -65535);\n        REQUIRE(std::get<std::tuple_size<hard_type>::value - 1>(hetero_array) == false);\n    }\n\n    SECTION(\"Test for invalid tuple\", \"[parsing], [tuple], [error]\")\n    {\n        REQUIRE(!from_json_file(\n            AUTOJSONCXX_ROOT_DIRECTORY \"/examples/failure/hard.json\", hetero_array, err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n        REQUIRE(static_cast<const error::TypeMismatchError&>(*err.begin()).actual_type() == \"null\");\n    }\n}\n"
  },
  {
    "path": "test/test_basic.cpp",
    "content": "#include <staticjson/staticjson.hpp>\n\n#include \"catch.hpp\"\n\nusing namespace staticjson;\n\nstruct MyObject\n{\n    int i;\n\n    void staticjson_init(ObjectHandler* h)\n    {\n        h->set_flags(Flags::DisallowUnknownKey);\n        h->add_property(\"i\", &i);\n    }\n};\n\nTEST_CASE(\"Basic test\")\n{\n    MyObject obj;\n    const char* input = \"{\\\"i\\\": -980008}\";\n    REQUIRE(from_json_string(input, &obj, nullptr));\n    REQUIRE(obj.i == -980008);\n}\n\nTEST_CASE(\"Failure test\")\n{\n    MyObject obj;\n    const char* input = (\"{\\\"i\\\": -980008, \\\"j\\\": 42}\");\n    ParseStatus res;\n    REQUIRE(!from_json_string(input, &obj, &res));\n    CAPTURE(res.description());\n    REQUIRE(obj.i == -980008);\n}\n\nTEST_CASE(\"Vector test\")\n{\n    std::vector<int> integers;\n    const char* input = (\"[1,2,3,4,5,6]\");\n    ParseStatus res;\n    bool success = from_json_string(input, &integers, nullptr);\n    CAPTURE(res.description());\n    REQUIRE(success);\n    REQUIRE(integers.size() == 6);\n}\n\nTEST_CASE(\"Serial\")\n{\n    REQUIRE(to_json_string(123) == \"123\");\n    MyObject obj;\n    obj.i = 999;\n    REQUIRE(to_pretty_json_string(obj).size() > 0);\n    REQUIRE(to_json_string(std::vector<int>{1, 2, 3, 4, 5, 6}) == \"[1,2,3,4,5,6]\");\n}"
  },
  {
    "path": "test/test_example.cpp",
    "content": "#undef NDEBUG\n\n#include <cassert>\n#include <staticjson/staticjson.hpp>\n\nint builtin_test()\n{\n    using namespace staticjson;\n    std::string a = to_json_string(std::vector<double>{1.0, 2.0, -3.1415});\n    std::string b\n        = to_pretty_json_string(std::map<std::string, std::shared_ptr<std::list<bool>>>{});\n\n    std::vector<std::unordered_map<std::string, std::int64_t>> data;\n\n    const char* json_string = \"[{\\\" hello \\\": 535353, \\\" world \\\": 849}, {\\\" k \\\": -548343}]\";\n    assert(from_json_string(json_string, &data, nullptr));\n    assert(data.size() == 2);\n    assert(data[1][\" k \"] == -548343);\n    to_pretty_json_file(\"/tmp/B11FA212-ED7F-4577-83B1-CC7ADBBC8ED3.json\", data);\n    return 0;\n}\n\n#include \"catch.hpp\"\n\nTEST_CASE(\"Example test\") { REQUIRE(builtin_test() == 0); }"
  },
  {
    "path": "test/test_instantiation.cpp",
    "content": "#include <staticjson/document.hpp>\n#include <staticjson/staticjson.hpp>\n\n#define INSTANTIATE(type)                                                                          \\\n    {                                                                                              \\\n        staticjson::Handler<type> h(nullptr);                                                      \\\n    }\n\n// Ensure that the template classes can be instantiated without compile time error\nvoid instantiate_all_types()\n{\n    INSTANTIATE(char)\n    INSTANTIATE(bool)\n    INSTANTIATE(int)\n    INSTANTIATE(unsigned)\n    INSTANTIATE(std::int64_t)\n    INSTANTIATE(std::uint64_t)\n    INSTANTIATE(std::string)\n    typedef std::array<long long, 10> my_array;\n    INSTANTIATE(my_array)\n    INSTANTIATE(std::vector<float>)\n    INSTANTIATE(std::vector<double>)\n    INSTANTIATE(std::deque<std::shared_ptr<std::unique_ptr<std::vector<std::list<std::string>>>>>);\n    INSTANTIATE(staticjson::Document);\n    INSTANTIATE(decltype(nullptr));\n\n    typedef std::tuple<int, double, std::vector<std::string>> complex_tuple_type;\n    INSTANTIATE(complex_tuple_type);\n}\n\n#undef INSTANTIATE\n"
  },
  {
    "path": "test/test_integration.cpp",
    "content": "#include \"catch.hpp\"\n#include \"myarray.hpp\"\n\n#include <staticjson/document.hpp>\n#include <staticjson/staticjson.hpp>\n\n#include <rapidjson/schema.h>\n\n#include <cerrno>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <system_error>\n\n#ifdef __has_include\n#if __has_include(<optional>)\n#pragma message(\"INFO: <optional> available for testing\")\n#include <staticjson/optional_support.hpp>\n#define STATICJSON_OPTIONAL 1\n#endif\n#endif\n\n#ifdef _MSC_VER\n#define stat _stat\n#endif\n\nconst std::string& get_base_dir()\n{\n    struct Initializer\n    {\n        std::string path;\n\n        Initializer()\n        {\n            path = \".\";\n            struct stat st;\n            for (int i = 0; i < 16; ++i)\n            {\n                if (::stat((path + \"/examples\").c_str(), &st) == 0)\n                {\n                    return;\n                }\n                else\n                {\n                    path += \"/..\";\n                }\n            }\n            fprintf(stderr,\n                    \"%s\",\n                    \"No 'examples' directory found in the working directory or its ancestors\\n\");\n            std::abort();\n        }\n    };\n\n    static const Initializer init;\n    return init.path;\n}\n\nusing namespace staticjson;\n\nenum class CalendarType\n{\n    Gregorian,\n    Chinese,\n    Jewish,\n    Islam\n};\n\nSTATICJSON_DECLARE_ENUM(CalendarType,\n                        {\"Gregorian\", CalendarType::Gregorian},\n                        {\"Chinese\", CalendarType::Chinese},\n                        {\"Jewish\", CalendarType::Jewish},\n                        {\"Islam\", CalendarType::Islam})\n\nstruct Date\n{\n    int year, month, day;\n    CalendarType type;\n\n    Date() : year(0), month(0), day(0), type(CalendarType::Gregorian) {}\n};\n\nnamespace staticjson\n{\nvoid init(Date* d, ObjectHandler* h)\n{\n    h->add_property(\"year\", &d->year);\n    h->add_property(\"month\", &d->month);\n    h->add_property(\"day\", &d->day);\n    h->add_property(\"type\", &d->type, Flags::Optional);\n    h->set_flags(Flags::DisallowUnknownKey);\n}\n}\n\nstruct BlockEvent\n{\n    std::uint64_t serial_number, admin_ID = 255;\n    Date date;\n    std::string description, details;\n#ifdef STATICJSON_OPTIONAL\n    staticjson::optional<std::string> flags;\n#endif\n\n    void staticjson_init(ObjectHandler* h)\n    {\n        h->add_property(\"serial_number\", &serial_number);\n        h->add_property(\"administrator ID\", &admin_ID, Flags::Optional);\n        h->add_property(\"date\", &date, Flags::Optional);\n        h->add_property(\"description\", &description, Flags::Optional);\n        h->add_property(\"details\", &details, Flags::Optional);\n#ifdef STATICJSON_OPTIONAL\n        h->add_property(\"flags\", &flags, Flags::Optional);\n#endif\n    }\n};\n\nstruct User\n{\n    friend class Handler<User>;\n\n    unsigned long long ID;\n    std::string nickname;\n    Date birthday;\n    std::shared_ptr<BlockEvent> block_event;\n    std::vector<BlockEvent> dark_history;\n    std::unordered_map<std::string, std::string> optional_attributes;\n\n    std::tuple<int, std::vector<std::tuple<double, double>>, bool> auxiliary;\n\n#ifdef STATICJSON_OPTIONAL\n    staticjson::optional<BlockEvent> dark_event;\n    staticjson::optional<std::vector<staticjson::optional<BlockEvent>>> alternate_history;\n#endif\n};\n\nnamespace staticjson\n{\ntemplate <>\nclass Handler<User> : public ObjectHandler\n{\npublic:\n    explicit Handler(User* user)\n    {\n        auto h = this;\n        h->add_property(\"ID\", &user->ID);\n        h->add_property(\"nickname\", &user->nickname);\n        h->add_property(\"birthday\", &user->birthday, Flags::Optional);\n        h->add_property(\"block_event\", &user->block_event, Flags::Optional);\n        h->add_property(\"optional_attributes\", &user->optional_attributes, Flags::Optional);\n        h->add_property(\"dark_history\", &user->dark_history, Flags::Optional);\n        h->add_property(\"auxiliary\", &user->auxiliary, Flags::Optional);\n#ifdef STATICJSON_OPTIONAL\n        h->add_property(\"dark_event\", &user->dark_event, Flags::Optional);\n        h->add_property(\"alternate_history\", &user->alternate_history, Flags::Optional);\n#endif\n    }\n\n    std::string type_name() const override { return \"User\"; }\n};\n}\n\ninline bool operator==(Date d1, Date d2)\n{\n    return d1.year == d2.year && d1.month == d2.month && d1.day == d2.day;\n}\n\ninline bool operator!=(Date d1, Date d2) { return !(d1 == d2); }\n\ninline bool operator==(const BlockEvent& b1, const BlockEvent& b2)\n{\n    return b1.admin_ID == b2.admin_ID && b1.date == b2.date && b1.description == b2.description\n        && b1.details == b2.details;\n}\n\ninline bool operator!=(const BlockEvent& b1, const BlockEvent& b2) { return !(b1 == b2); }\n\ninline bool operator==(const User& u1, const User& u2)\n{\n    return u1.birthday == u2.birthday && u1.ID == u2.ID && u1.nickname == u2.nickname\n        && u1.dark_history == u2.dark_history && u1.optional_attributes == u2.optional_attributes\n        && ((!u1.block_event && !u2.block_event)\n            || ((u1.block_event && u2.block_event) && *u1.block_event == *u2.block_event));\n}\n\ninline bool operator!=(const User& u1, const User& u2) { return !(u1 == u2); }\n\ninline std::string read_all(const std::string& file_name)\n{\n    nonpublic::FileGuard fg(std::fopen(file_name.c_str(), \"rb\"));\n    if (!fg.fp)\n        throw std::system_error(errno, std::system_category());\n    std::string result;\n    while (1)\n    {\n        int ch = getc(fg.fp);\n        if (ch == EOF)\n            break;\n        result.push_back(static_cast<unsigned char>(ch));\n    }\n    return result;\n}\n\ninline Date create_date(int year, int month, int day)\n{\n    Date d;\n    d.year = year;\n    d.month = month;\n    d.day = day;\n    return d;\n}\n\nvoid check_first_user(const User& u)\n{\n    REQUIRE(u.ID == 7947402710862746952ULL);\n    REQUIRE(u.nickname == \"bigger than bigger\");\n    REQUIRE(u.birthday == create_date(1984, 9, 2));\n\n    REQUIRE(u.block_event.get() != nullptr);\n    const BlockEvent& e = *u.block_event;\n\n    REQUIRE(e.admin_ID > 0ULL);\n    REQUIRE(e.date == create_date(1970, 12, 31));\n    REQUIRE(e.description == \"advertisement\");\n    REQUIRE(e.details.size() > 0ULL);\n\n    REQUIRE(u.dark_history.empty());\n    REQUIRE(u.optional_attributes.empty());\n\n#ifdef STATICJSON_OPTIONAL\n    REQUIRE(!!u.dark_event);\n    REQUIRE(u.dark_event->serial_number == 9876543210123456789ULL);\n    REQUIRE(u.dark_event->admin_ID == 11223344556677889900ULL);\n    REQUIRE(u.dark_event->date == create_date(1970, 12, 31));\n    REQUIRE(u.dark_event->description == \"promote\");\n    REQUIRE(u.dark_event->details == \"at least like a troll\");\n    REQUIRE(static_cast<bool>(u.dark_event->flags) == false);\n\n    REQUIRE(static_cast<bool>(u.alternate_history) == true);\n    REQUIRE(u.alternate_history->size() == 2);\n    REQUIRE(static_cast<bool>(u.alternate_history->at(0)) == false);\n    REQUIRE(static_cast<bool>(u.alternate_history->at(1)) == true);\n\n    {\n        const auto& opt_e = u.alternate_history->at(1);\n        REQUIRE(opt_e);\n        const BlockEvent& e = *opt_e;\n        REQUIRE(e.serial_number == 1123581321345589ULL);\n        REQUIRE(e.admin_ID == 1123581321345589ULL);\n        REQUIRE(e.date == create_date(1970, 12, 31));\n        REQUIRE(e.description == \"redacted\");\n        REQUIRE(e.details == \"redacted\");\n        REQUIRE(static_cast<bool>(e.flags) == true);\n        REQUIRE(*e.flags == \"x\");\n    }\n#endif\n}\n\nvoid check_second_user(const User& u)\n{\n    REQUIRE(u.ID == 13478355757133566847ULL);\n    REQUIRE(u.nickname.size() == 15);\n    REQUIRE(!u.block_event);\n    REQUIRE(u.optional_attributes.size() == 3);\n    REQUIRE(u.optional_attributes.find(\"Self description\") != u.optional_attributes.end());\n}\n\ntemplate <class ArrayOfUsers>\nvoid check_array_of_user(const ArrayOfUsers& users)\n{\n    REQUIRE(users.size() == 3);\n\n    check_first_user(users[0]);\n    check_second_user(users[1]);\n}\n\nvoid check_array_of_user(const Document& users)\n{\n    REQUIRE(users.IsArray());\n    REQUIRE(users.Size() == 3);\n\n    const Value& u = users[0];\n    REQUIRE(u.IsObject());\n    REQUIRE(u.HasMember(\"ID\"));\n    REQUIRE(u[\"ID\"].IsUint64());\n    REQUIRE(u[\"ID\"].GetUint64() == 7947402710862746952ULL);\n    REQUIRE(u.HasMember(\"nickname\"));\n    REQUIRE(u[\"nickname\"].IsString());\n    REQUIRE(std::strcmp(u[\"nickname\"].GetString(), \"bigger than bigger\") == 0);\n    REQUIRE(u.HasMember(\"birthday\"));\n    REQUIRE(u[\"birthday\"].IsObject());\n    REQUIRE(u[\"birthday\"].HasMember(\"year\"));\n    REQUIRE(u[\"birthday\"][\"year\"] == 1984);\n\n    REQUIRE(u.HasMember(\"block_event\"));\n    const Value& e = u[\"block_event\"];\n    REQUIRE(e.HasMember(\"administrator ID\"));\n    REQUIRE(e.HasMember(\"description\"));\n    const Value& desc = e[\"description\"];\n    REQUIRE(desc.IsString());\n    REQUIRE(std::strcmp(desc.GetString(), \"advertisement\") == 0);\n\n#ifdef STATICJSON_OPTIONAL\n    REQUIRE(u.HasMember(\"dark_event\"));\n    {\n        const Value& e = u[\"dark_event\"];\n        REQUIRE(e.HasMember(\"administrator ID\"));\n        REQUIRE(e.HasMember(\"description\"));\n        REQUIRE(e[\"flags\"].IsNull());\n    }\n\n    REQUIRE(u.HasMember(\"alternate_history\"));\n    {\n        const Value& e = u[\"alternate_history\"];\n        REQUIRE(e.IsArray());\n        REQUIRE(e[0].IsNull());\n        REQUIRE(e[1].IsObject());\n        REQUIRE(e[1][\"flags\"].IsString());\n    }\n#endif\n}\n\nTEST_CASE(\"Test for correct parsing\", \"[parsing],[c]\")\n{\n    SECTION(\"Simple date parsing\", \"[parsing]\")\n    {\n        Date d;\n        ParseStatus err;\n        bool success = from_json_string(\n            \"{\\\"year\\\": 1900, \\\"day\\\": 3, \\\"month\\\": 11, \\\"type\\\": \\\"Chinese\\\"}\", &d, &err);\n        {\n            CAPTURE(err.description());\n            REQUIRE(success);\n        }\n    }\n\n    SECTION(\"Test for an array of user\", \"[parsing]\")\n    {\n        Array<User> users;\n        ParseStatus err;\n\n        // Do it twice to test if vectors are reset properly at parsing.\n        for (int i = 0; i < 2; ++i)\n        {\n            bool success = from_json_file(\n                get_base_dir() + \"/examples/success/user_array.json\", &users, &err);\n            {\n                CAPTURE(err.description());\n                REQUIRE(success);\n            }\n            check_array_of_user(users);\n            REQUIRE(users[0].birthday.type == CalendarType::Jewish);\n        }\n\n        Document d;\n        REQUIRE(to_json_document(&d, users, nullptr));\n        check_array_of_user(d);\n    }\n    SECTION(\"Test for document\", \"[parsing]\")\n    {\n        Document users;\n        ParseStatus err;\n\n        bool success\n            = from_json_file(get_base_dir() + \"/examples/success/user_array.json\", &users, &err);\n        {\n            CAPTURE(err.description());\n            REQUIRE(success);\n        }\n        check_array_of_user(users);\n\n        std::vector<User> vusers;\n        REQUIRE(from_json_document(users, &vusers, nullptr));\n        check_array_of_user(vusers);\n    }\n\n    SECTION(\"Test for a map of user\", \"[parsing], [q]\")\n    {\n        std::unordered_map<std::string, User> users;\n        ParseStatus err;\n\n        // Do it twice to test if map is reset properly at parsing.\n        for (int i = 0; i < 2; ++i)\n        {\n            bool success\n                = from_json_file(get_base_dir() + \"/examples/success/user_map.json\", &users, &err);\n            {\n                CAPTURE(err.description());\n                REQUIRE(success);\n            }\n            REQUIRE(users.size() == 2);\n            check_first_user(users[\"First\"]);\n            check_second_user(users[\"Second\"]);\n        }\n    }\n}\n\nTEST_CASE(\"Test for mismatch between JSON and C++ class std::vector<config::User>\",\n          \"[parsing], [error]\")\n{\n    std::vector<User> users;\n    ParseStatus err;\n\n    SECTION(\"Mismatch between array and object\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(\n            !from_json_file(get_base_dir() + \"/examples/failure/single_object.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n        REQUIRE(std::distance(err.begin(), err.end()) == 1);\n    }\n\n    SECTION(\"Missing requied simple\", \"[missing required]\")\n    {\n        Date date;\n        const char* str = \"{ \\\"month\\\": 12 }\";\n        REQUIRE(!from_json_string(str, &date, nullptr));\n    }\n\n    SECTION(\"Required field not present; test the path as well\",\n            \"[parsing], [error], [missing required]\")\n    {\n        REQUIRE(!from_json_file(\n            get_base_dir() + \"/examples/failure/missing_required.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(std::distance(err.begin(), err.end()) == 5);\n\n        auto it = err.begin();\n        REQUIRE(it->type() == error::MISSING_REQUIRED);\n\n        ++it;\n        REQUIRE(it->type() == error::OBJECT_MEMBER);\n        REQUIRE(static_cast<const error::ObjectMemberError&>(*it).member_name() == \"date\");\n\n        ++it;\n        REQUIRE(it->type() == error::ARRAY_ELEMENT);\n        REQUIRE(static_cast<const error::ArrayElementError&>(*it).index() == 0);\n\n        ++it;\n        REQUIRE(it->type() == error::OBJECT_MEMBER);\n        REQUIRE(static_cast<const error::ObjectMemberError&>(*it).member_name() == \"dark_history\");\n    }\n\n    SECTION(\"Unknown field in strict parsed class Date\", \"[parsing], [error], [unknown field]\")\n    {\n        REQUIRE(\n            !from_json_file(get_base_dir() + \"/examples/failure/unknown_field.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::UNKNOWN_FIELD);\n\n        REQUIRE(static_cast<const error::UnknownFieldError&>(*err.begin()).field_name() == \"hour\");\n    }\n\n    SECTION(\"Duplicate key in class User\", \"[parsing], [error], [duplicate key]\")\n    {\n        REQUIRE(!from_json_file(\n            get_base_dir() + \"/examples/failure/duplicate_key_user.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::DUPLICATE_KEYS);\n\n        REQUIRE(static_cast<const error::DuplicateKeyError&>(*err.begin()).key() == \"ID\");\n    }\n\n    SECTION(\"Out of range\", \"[parsing], [error], [out of range]\")\n    {\n        REQUIRE(\n            !from_json_file(get_base_dir() + \"/examples/failure/out_of_range.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::NUMBER_OUT_OF_RANGE);\n    }\n\n    SECTION(\"Mismatch between integer and string\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(!from_json_file(\n            get_base_dir() + \"/examples/failure/integer_string.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n    }\n\n    SECTION(\"Null character in key\", \"[parsing], [error], [null character]\")\n    {\n        REQUIRE(\n            !from_json_file(get_base_dir() + \"/examples/failure/null_in_key.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::UNKNOWN_FIELD);\n    }\n}\n\nTEST_CASE(\"Test for mismatch between JSON and C++ class std::map<std::string, config::User>\",\n          \"[parsing], [error]\")\n{\n    std::map<std::string, User> users;\n    ParseStatus err;\n\n    SECTION(\"Mismatch between object and array\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(\n            !from_json_file(get_base_dir() + \"/examples/success/user_array.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n\n        auto&& e = static_cast<const error::TypeMismatchError&>(*err.begin());\n        REQUIRE(e.actual_type() == \"array\");\n    }\n\n    SECTION(\"Mismatch in mapped element\", \"[parsing], [error], [type mismatch]\")\n    {\n        REQUIRE(!from_json_file(\n            get_base_dir() + \"/examples/failure/map_element_mismatch.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n        {\n            REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n\n            auto&& e = static_cast<const error::TypeMismatchError&>(*err.begin());\n            (void)e;\n        }\n        {\n            auto it = ++err.begin();\n            REQUIRE(it != err.end());\n            REQUIRE(it->type() == error::OBJECT_MEMBER);\n            auto&& e = static_cast<const error::ObjectMemberError&>(*it);\n            REQUIRE(e.member_name() == \"Third\");\n        }\n    }\n\n    SECTION(\"Invalid enum\", \"[parsing], [error], [enum]\")\n    {\n        REQUIRE(\n            !from_json_file(get_base_dir() + \"/examples/failure/invalid_enum.json\", &users, &err));\n        CAPTURE(err.description());\n        REQUIRE(!err.error_stack().empty());\n\n        REQUIRE(err.begin()->type() == error::INVALID_ENUM);\n        const auto& e = static_cast<const error::InvalidEnumError&>(*err.begin());\n        REQUIRE(e.description() == \"\\\"West\\\" is an invalid enum name\");\n    }\n}\n\nTEST_CASE(\"Test for max leaf number check\", \"[serialization]\")\n{\n    std::vector<User> users, reparsed_users;\n    ParseStatus err;\n\n    bool success\n        = from_json_file(get_base_dir() + \"/examples/success/user_array.json\", &users, &err);\n    {\n        CAPTURE(err.description());\n        REQUIRE(success);\n    }\n    REQUIRE(users.size() == 3);\n\n    std::string json_output = to_pretty_json_string(users);\n    CAPTURE(json_output);\n    staticjson::GlobalConfig::getInstance()->setMaxLeaves(20);\n    success = from_json_string(json_output.c_str(), &reparsed_users, &err);\n    staticjson::GlobalConfig::getInstance()->unsetMaxLeavesFlag();\n    {\n        CAPTURE(err.description());\n        REQUIRE(!success);\n    }\n\n    REQUIRE(err.description().find(\"Too many leaves\") != std::string::npos);\n}\n\nTEST_CASE(\"Test for max depth check\", \"[serialization]\")\n{\n    std::vector<User> users, reparsed_users;\n    ParseStatus err;\n    staticjson::GlobalConfig::getInstance()->setMaxDepth(3);\n    bool success\n        = from_json_file(get_base_dir() + \"/examples/success/user_array.json\", &users, &err);\n    staticjson::GlobalConfig::getInstance()->unsetMaxDepthFlag();\n\n    {\n        CAPTURE(err.description());\n        REQUIRE(!success);\n    }\n    REQUIRE(err.description().find(\"Too many levels of recursion\") != std::string::npos);\n}\n\nTEST_CASE(\"Test for writing JSON\", \"[serialization]\")\n{\n    std::vector<User> users, reparsed_users;\n    ParseStatus err;\n\n    bool success\n        = from_json_file(get_base_dir() + \"/examples/success/user_array.json\", &users, &err);\n    {\n        CAPTURE(err.description());\n        REQUIRE(success);\n    }\n    REQUIRE(users.size() == 3);\n\n    std::string json_output = to_pretty_json_string(users);\n    CAPTURE(json_output);\n\n    success = from_json_string(json_output.c_str(), &reparsed_users, &err);\n    {\n        CAPTURE(err.description());\n        REQUIRE(success);\n    }\n\n    REQUIRE(users == reparsed_users);\n}\n\nstatic bool is_valid_json(const std::string& filename, rapidjson::SchemaValidator* validator)\n{\n    Document d;\n    REQUIRE(from_json_file(filename, &d, nullptr));\n    bool rc = d.Accept(*validator);\n    validator->Reset();\n    return rc;\n}\n\nTEST_CASE(\"Schema generation and validation\")\n{\n    const char* invalid_json_filenames[] = {\"out_of_range.json\",\n                                            \"integer_string.json\",\n                                            \"missing_required.json\",\n                                            \"map_element_mismatch.json\",\n                                            \"null_in_key.json\",\n                                            \"single_object.json\",\n                                            \"unknown_field.json\",\n                                            \"invalid_enum.json\"};\n    {\n        std::vector<User> users;\n        Document schema = export_json_schema(&users);\n        rapidjson::SchemaDocument sd(schema);\n        rapidjson::SchemaValidator validator(sd);\n\n        REQUIRE(is_valid_json(get_base_dir() + \"/examples/success/user_array.json\", &validator));\n        REQUIRE(is_valid_json(get_base_dir() + \"/examples/success/user_array_compact.json\",\n                              &validator));\n\n        for (const char* fn : invalid_json_filenames)\n            REQUIRE(!is_valid_json(get_base_dir() + \"/examples/failure/\" + fn, &validator));\n    }\n    {\n        std::map<std::string, User> users;\n        Document schema = export_json_schema(&users);\n        rapidjson::SchemaDocument sd(schema);\n        rapidjson::SchemaValidator validator(sd);\n\n        REQUIRE(is_valid_json(get_base_dir() + \"/examples/success/user_map.json\", &validator));\n        for (const char* fn : invalid_json_filenames)\n            REQUIRE(!is_valid_json(get_base_dir() + \"/examples/failure/\" + fn, &validator));\n    }\n}\n"
  },
  {
    "path": "test/test_memory_usage.cpp",
    "content": "#include <staticjson/staticjson.hpp>\n\n#include \"catch.hpp\"\n\nusing namespace staticjson;\n\nnamespace\n{\nconst std::string COMPLEX_VALUES = \"complex_values\";\n\nstruct Simple\n{\n    std::vector<float> floats;\n\n    void staticjson_init(ObjectHandler* h) { h->add_property(\"floats\", &floats); }\n};\n\nstruct Struct\n{\n    std::string name;\n    std::vector<std::tuple<std::vector<int>, std::list<std::string>>> complex_values;\n    Simple simple;\n\n    void staticjson_init(ObjectHandler* h)\n    {\n        h->add_property(\"name\", &name);\n        h->add_property(COMPLEX_VALUES, &complex_values, staticjson::Flags::AllowDuplicateKey);\n        h->add_property(\"simple\", &simple);\n    }\n};\n}\n\nTEST_CASE(\"Test memory usage\")\n{\n    size_t memory_usage_before = 0, memory_usage_after = 0;\n    std::string serialized;\n\n    std::vector<Struct> structs(100);\n    for (size_t i = 0; i < structs.size(); ++i)\n    {\n        structs[i].name = \"Struct\" + std::to_string(i);\n        structs[i].complex_values.resize(i);\n        for (size_t j = 0; j < i; ++j)\n        {\n            auto&& v = structs[i].complex_values[j];\n            std::get<0>(v).push_back(j);\n            for (size_t k = 0; k < 2 * j; ++k)\n            {\n                std::get<1>(v).emplace_back(std::to_string(k));\n            }\n        }\n    }\n    Handler<std::vector<Struct>> h(&structs);\n    serialized = nonpublic::serialize_json_string(&h);\n    memory_usage_before = h.get_internal_handler().get_memory_pool().Capacity();\n\n    structs.clear();\n    h.prepare_for_reuse();\n\n    ParseStatus status;\n    REQUIRE(nonpublic::parse_json_string(serialized.c_str(), &h, &status));\n    memory_usage_after = h.get_internal_handler().get_memory_pool().Capacity();\n\n    printf(\"Memory usage: before %zu, after %zu\\n\", memory_usage_before, memory_usage_after);\n    CHECK(memory_usage_before == memory_usage_after);\n}\n"
  },
  {
    "path": "test/test_tensor.cpp",
    "content": "#include <staticjson/staticjson.hpp>\n\n#include \"catch.hpp\"\n#include \"myarray.hpp\"\n\n#include <cerrno>\n#include <deque>\n#include <list>\n#include <vector>\n\nusing namespace staticjson;\n\nconst std::string& get_base_dir();\n\nTEST_CASE(\"Success tensor\")\n{\n    std::list<std::array<Array<double>, 3>> tensor;\n    ParseStatus err;\n\n    bool success = from_json_file(get_base_dir() + \"/examples/success/tensor.json\", &tensor, &err);\n    {\n        CAPTURE(err.description());\n        REQUIRE(success);\n    }\n\n    REQUIRE(tensor.size() == 4);\n    REQUIRE(!tensor.back().empty());\n    REQUIRE(tensor.back().back().empty());\n    auto&& first = tensor.front();\n\n    REQUIRE(first.size() == 3);\n    REQUIRE(first[0].size() == 3);\n    REQUIRE(first[0][0] == 1);\n}\n\nTEST_CASE(\"Error tensor\")\n{\n    std::list<std::array<Array<double>, 2>> tensor;\n    {\n        ParseStatus err;\n        REQUIRE(!from_json_file(\n            get_base_dir() + \"/examples/failure/tensor_type_mismatch.json\", &tensor, &err));\n        REQUIRE(err.begin()->type() == error::TYPE_MISMATCH);\n    }\n    {\n        ParseStatus err;\n        REQUIRE(!from_json_file(\n            get_base_dir() + \"/examples/failure/tensor_length_error.json\", &tensor, &err));\n        REQUIRE(err.begin()->type() == error::ARRAY_LENGTH_MISMATCH);\n    }\n}\n"
  }
]