{"id":13730483,"url":"https://github.com/qicosmos/iguana","last_synced_at":"2025-04-13T03:59:14.107Z","repository":{"id":42183292,"uuid":"78250317","full_name":"qicosmos/iguana","owner":"qicosmos","description":"universal serialization engine","archived":false,"fork":false,"pushed_at":"2025-03-11T08:03:10.000Z","size":19527,"stargazers_count":1212,"open_issues_count":51,"forks_count":238,"subscribers_count":52,"default_branch":"master","last_synced_at":"2025-04-13T03:59:07.120Z","etag":null,"topics":["binary","c-plus-plus","json","serialization","xml"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qicosmos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-07T01:02:28.000Z","updated_at":"2025-04-12T14:45:48.000Z","dependencies_parsed_at":"2024-03-22T04:28:18.933Z","dependency_job_id":"62bb6467-6467-48aa-ba1c-822047139153","html_url":"https://github.com/qicosmos/iguana","commit_stats":{"total_commits":774,"total_committers":34,"mean_commits":"22.764705882352942","dds":0.4728682170542635,"last_synced_commit":"ae5a951e0ae952e8cf2af7c21f038e33a5caf558"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qicosmos%2Figuana","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qicosmos%2Figuana/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qicosmos%2Figuana/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qicosmos%2Figuana/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qicosmos","download_url":"https://codeload.github.com/qicosmos/iguana/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248661706,"owners_count":21141450,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binary","c-plus-plus","json","serialization","xml"],"created_at":"2024-08-03T02:01:15.482Z","updated_at":"2025-04-13T03:59:14.078Z","avatar_url":"https://github.com/qicosmos.png","language":"C++","funding_links":[],"categories":["Serialization","C++"],"sub_categories":[],"readme":"# A Universal Serialization Engine Based on compile-time Reflection #\n\n*iguana* is a modern, universal and easy-to-use serialization engine developed in C++20 and C++17.\n\n| OS (Compiler Version)                          | Status                                                                                                   |\n|------------------------------------------------|----------------------------------------------------------------------------------------------------------|\n| Ubuntu 22.04 (clang 14.0.0)                    | ![win](https://github.com/qicosmos/iguana/actions/workflows/linux-clang.yml/badge.svg?branch=master) |\n| Ubuntu 22.04 (gcc 11.2.0)                      | ![win](https://github.com/qicosmos/iguana/actions/workflows/linux-gcc.yml/badge.svg?branch=master)   |\n| macOS Monterey latest (AppleClang latest) | ![win](https://github.com/qicosmos/iguana/actions/workflows/mac.yml/badge.svg?branch=master)         |\n| Windows Server 2022 (MSVC 19.33.31630.0)       | ![win](https://github.com/qicosmos/iguana/actions/workflows/windows.yml/badge.svg?branch=master)     |\n\nqq 交流群 701594518\n\n[中文版](lang/iguana%20使用文档.md)\n\n[struct_pb](lang/struct_pb_intro.md)\n\n### Motivation ###\nSerialize an object to any other format data with compile-time reflection, such as json, xml, binary, table and so on.\nThis library is designed to unify and simplify serialization in a portable cross-platform manner. This library is also easy to extend, and you can serialize any format of data with the library.\nThis library provides a portable cross-platform way of: \n\n- serialization of json\n- serialization of xml\n- serialization of yaml\n- serialization of protobuf\n- serialization of any customized format\n\n### compile time reflection ###\n\n[reflection lib introduction](lang/reflection_introduction.md)\n\n### Tutorial ###\nThis Tutorial is provided to give you a view of how *iguana* works for serialization. \n\n### Serialization of json\n\nThe first thing to do when you serialize an object is to define meta data.  There is an example of defining meta data.\n\n```c++\nstruct person\n{\n    std::string  name;\n    int          age;\n};\n#if __cplusplus \u003c 202002L\nYLT_REFL(person, name, age) //define meta data\n#endif\n```\n\nDefining meta data is very simple, if your compiler is C++20 compiler(gcc11+, clang13+, msvc2022), no need define YLT_REFL, other wise need to define in a `YLT_REFL` macro.\n\nNow let's serialize `person` to `json` string.\n\n```c++\nperson p = { \"tom\", 28 };\n\niguana::string_stream ss; // here use std::string is also ok\niguana::to_json(p, ss);\n\nstd::cout \u003c\u003c ss.str() \u003c\u003c std::endl; \n```\n\nThis example will output:\n\n```bash\n{\"name\":\"tom\",\"age\":28}\n```\n\nSerializing person to `json` string is also very simple, just need to call `to_json` method, there is nothing more.\n\nHow about deserialization of `json`? Look at the follow example.\n\n```c++\nstd::string json = \"{ \\\"name\\\" : \\\"tom\\\", \\\"age\\\" : 28}\";\n\nperson p;\niguana::from_json(p, json);\n```\n\nIt's as simple as serialization, just need to call `from_json` method. \n\nYou can also use parse interface to do dom parsing:\n\n```c++\nstd::string_view str = R\"(false)\";\niguana::jvalue val;\niguana::parse(val, str.begin(), str.end());\n\nstd::error_code ec;\nauto b = val.get\u003cbool\u003e(ec);\nCHECK(!ec);\nCHECK(!b);\n\n// or\nb = val.get\u003cbool\u003e(); // this interface maybe throw exception\nCHECK(!b);\n```\n\n### Serialization of xml\n\nThe serialization of `xml` is similar to `json`. The first step is also defining meta data as above, and then you can call `iguana::to_xml` to serialization  the structure, or call `iguana::from_xml` to deserialization  the structure. The following is a complete example.\n\n```c++\n// serialization the structure to the string\nperson p = {\"admin\", 20};\niguana::string_stream ss;  // here use std::string is also ok\niguana::to_xml(p, ss);\nstd::cout \u003c\u003c ss \u003c\u003c std::endl;\n\n// deserialization the structure from the string\nstd::string xml = R\"(\n\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"\u003e  \n\u003croot\u003e \n  \u003cname\u003ebuke\u003c/name\u003e \n  \u003cage\u003e30\u003c/age\u003e \n\u003c/root\u003e)\";\niguana::from_xml(p, xml);\n```\n#### Serialization of yaml\n\nThe serialization of `yaml` is also as simple as the above interface. Here is a complete example:\n\n```c++\n// serialization the structure to the string\nperson p = {\"admin\", 20};\niguana::string_stream ss;  // here use std::string is also ok\niguana::to_yaml(ss, p);\nstd::cout \u003c\u003c ss.str() \u003c\u003c std::endl;\nstd::string yaml = R\"(\nname : buke\nage : 30\n)\";\n// deserialization the structure from the string\niguana::from_yaml(p, yaml);\n```\n\n### A complicated example\n\n#### json\n\n*iguana* can deal with objects which contain another objects and containers. Here is the example:\n\nAt first, we define the meta data:\n\n```c++\nstruct one_t\n{\n    int id;\n};\nYLT_REFL(one_t, id);\n\nstruct two\n{\n    std::string name;\n    one_t one;\n    int age;\n};\nYLT_REFL(two, name, one, age);\n\nstruct composit_t\n{\n    int a;\n    std::vector\u003cstd::string\u003e b;\n    int c;\n    std::map\u003cint, int\u003e d;\n    std::unordered_map\u003cint, int\u003e e;\n    double f;\n    std::list\u003cone_t\u003e g;\n};\nYLT_REFL(composit_t, a, b, c, d, e, f, g);\n```\n\nThen call the simple interface:\n\n```c++\none_t one = { 2 };\ncomposit_t composit = { 1,{ \"tom\", \"jack\" }, 3,{ { 2,3 } },{ { 5,6 } }, 5.3,{ one } };\niguana::string_stream ss;\niguana::to_json(composit, ss);\nstd::cout \u003c\u003c ss.str() \u003c\u003c std::endl;\n\nstd::string str_comp = R\"({\"a\":1, \"b\":[\"tom\", \"jack\"], \"c\":3, \"d\":{\"2\":3,\"5\":6},\"e\":{\"3\":4},\"f\":5.3,\"g\":[{\"id\":1},{\"id\":2}])\";\ncomposit_t comp;\niguana::from_json(comp, str_comp);\n```\n\n#### xml\n\nAt first, define the structure and reflect the meta data.\n\n```c++\nstruct book_t {\n  std::string author;\n  float price;\n};\nYLT_REFL(book_t, author, price);\nstruct library_t {\n  std::string name;\n  int id;\n  std::vector\u003cbook_t\u003e book;\n};\nYLT_REFL(library_t, name, id, book);\n```\n\nAnd then, simply call the interface:\n\n```c++\n// serialization the structure to the string\nlibrary_t library = {\"Pro Lib\", 110, {{\"tom\", 1.8}, {\"jack\", 2.1}}};\nstd::string ss;\niguana::to_xml(library, ss);\nstd::cout \u003c\u003c ss \u003c\u003c \"\\n\";\n\n// deserialization the structure from the string\nstd::string str = R\"(\n\u003clibrary\u003e\n  \u003cname\u003ePro Lib\u003c/name\u003e\n  \u003cid\u003e110\u003c/id\u003e\n  \u003cbook\u003e\u003cauthor\u003etom\u003c/author\u003e\u003cprice\u003e1.8\u003c/price\u003e\n  \u003c/book\u003e\n  \u003cbook\u003e\u003cauthor\u003ejack\u003c/author\u003e\u003cprice\u003e2.1\u003c/price\u003e\n  \u003c/book\u003e\n\u003c/library\u003e\n)\";\nlibrary_t lib;\niguana::from_xml(lib, str);\n```\n#### yaml\n\nAs always what we do, define the structure and reflect the meta data.\n\n```c++\nenum class enum_status {\n  start,\n  stop,\n};\nstruct plain_type_t {\n  bool isok;\n  enum_status status;\n  char c;\n  std::optional\u003cbool\u003e hasprice;\n  std::optional\u003cfloat\u003e num;\n  std::optional\u003cint\u003e price;\n};\nYLT_REFL(plain_type_t, isok, status, c, hasprice, num, price);\n```\n\nAnd then, simply call the interface:\n\n```c++\n// deserialization the structure from the string\nstd::string str = R\"(\nisok: false\nstatus: 1\nc: a\nhasprice: true\nnum:\nprice: 20\n)\";\nplain_type_t p;\niguana::from_yaml(p, str);\n// serialization the structure to the string\nstd::string ss;\niguana::to_yaml(ss, p);\nstd::cout \u003c\u003c ss \u003c\u003c \"\\n\";\n```\n\n### How to solve the problem of unicode path in a json file?\n\nIf there is an unicode string as a path in a json file, however iguana parse the file as utf-8, so maybe you can see some strange characters after parse.\n\nIt's ok, because you see the utf-8 strings. The problem is you can't use the string directly, such as use std::ifstream to open the file with the unicode string path.\n\nWe can slove the problem1 easily with c++17:\n\n```c++\n  //the p.path is a unicode string path\n  std::ifstream in(std::filesystem::u8path(p.path)); //std::filesystem::u8path help us\n  //now you can operate the file\n```\n\n### how to handle the enum type as strings?\n\nBy default, Iguana handle enum type as  number type during serialization and deserialization.\nTo handle the enum type as strings during serialization and deserialization with Iguana, we need to define a  full specialization template in the \"iguana\" namespace. This template is a struct that contains an array with the underlying numbers corresponding to the enum type.\nFor example, if we have the following enum type:\n\n```c++\nenum class Status { STOP = 10, START };\n```\n\nAnd we want to handle the enum type as strings when parsing JSON:\n\n```c++\n    std::string str = R\"(\n{\n  \"a\": \"START\",\n  \"b\": \"STOP\"\n}\n  )\";\n```\n\nTo do this, we define the full specialization template in the \"iguana\" namespace:\n\n```c++\nnamespace iguana {\ntemplate \u003c\u003e struct enum_value\u003cStatus\u003e {\n  constexpr static std::array\u003cint, 2\u003e value = {10, 11};\n};\n} // namespace iguana\n```\n\nOnce this is done, we can continue writing the rest of the code as usual.\n\n```c++\nstruct enum_t {\n    Status a;\n    Status b;\n};\nYLT_REFL(enum_t, a, b);\n\n// deserialization\nenum_t e;\niguana::from_json(e, str);\n// serialization\nenum_t e1;\ne1.a = Status::START;\ne1.b = Status::STOP;\nstd::string ss;\niguana::to_json(e1, ss);\n```\n\n### Serialization of protobuf\nsimilar with before:\n```cpp\nstruct person {\n  int id;\n  std::string name;\n  int age;\n  bool operator==(person const\u0026 rhs) const {\n    return id == rhs.id \u0026\u0026 name == rhs.name \u0026\u0026 age == rhs.age;\n  }\n};\n\n#if __cplusplus \u003c 202002L\nYLT_REFL(person, id, name, age) //define meta data\n#endif\n\nvoid test() {\n  person p{1, \"tom\", 20};\n  std::string pb;\n  iguana::to_pb(p, pb);\n  person p1;\n  iguana::from_pb(p1, pb);\n  CHECK(p == p1);\n}\n```\n[more detail](lang/struct_pb_intro.md)\n\n### Full sources:\n\n\n+ More examples about [json](https://github.com/qicosmos/iguana/blob/master/example/example.cpp)\n+ More examples about [xml](https://github.com/qicosmos/iguana/blob/master/example/xml_example.cpp)\n+ More examples about [yaml](https://github.com/qicosmos/iguana/blob/master/example/yaml_example.cpp)\n+ More examples about [struct_pb](https://github.com/qicosmos/iguana/blob/master/test/test_pb.cpp)\n\n### Scripts\n\nAutomatically generate `YLT_REFL` macros based by struct.\n\nTo get a list of basic options and switches use:\n\n```bash\npython automatic_macro_generator.py -h\n```\n\nbasic example:\n\nThe content of the test_macro_generator.cpp is as follows:\n\n```c++\n struct person {\n    std::string name;\n    int age;\n  };\n\n  char *iguana = NULL;\n\n  struct composit_t { int a; std::vector\u003cstd::string\u003e b; int c; std::map\u003cint, int\u003e d; std::unordered_map\u003cint, int\u003e e; double f;};\n\n  char *iguana_test = NULL;\n\n  struct composit_t2\n  {\n    int a;\n    std::vector\u003cstd::string\u003e b;\n    int iguana;\n    std::map\u003cint, int\u003e example_test;\n    std::unordered_map\u003cint, int\u003e random_name__;\n    double __f__number__complex;\n  };\n```\n\n\nexecute script:\n\n```\npython automatic_macro_generator.py -i test_macro_generator.cpp\n```\n\nAfter processing by the automatic_macro_generator.py script,test_macro_generator.cpp change into:\n\n```c++\nstruct person {\n  std::string name;\n  int age;\n};\nYLT_REFL(person, name, age);\nchar *iguana = NULL;\n\nstruct composit_t { int a; std::vector\u003cstd::string\u003e b; int c; std::map\u003cint, int\u003e d; std::unordered_map\u003cint, int\u003e e; double f;};\nYLT_REFL(composit_t, a, b, c, d, e, f);\n\nstruct composit_t2\n{\n  int a;\n  std::vector\u003cstd::string\u003e b;\n  int iguana;\n  std::map\u003cint, int\u003e example_test;\n  std::unordered_map\u003cint, int\u003e random_name__;\n  double __f__number__complex;\n};\nYLT_REFL(composit_t2, a, b, iguana, example_test, random_name__, __f__number__complex);\n```\n\nother example:\n\n```bash\npython automatic_macro_generator.py -i test_macro_generator.cpp -o have_macro.cpp\n```\n\ntest_macro_generator.cpp will be unchanged, have_macro.cpp will be changed to source file with YLT_REFL macro.\n\nscripts works out of the box with Python version 2.7 and 3.x on any platform.\n\nNotes: In Python3,Will prompt `DeprecationWarning: 'U' mode is deprecated`.Ignore it.\n\n\n### F.A.Q\n\n- **Question**: Why is the library called *iguana*?\n\n  - **Answer**: I think serialization is like an iguana, because the only difference is the displaying format, however the meta data is never changed. With changeless meta data and YLT_REFL, you can serialize an object to any format, which is like how an iguana does.\n\n- **Question**: Does *iguana* support raw pointer?\n\n  - **Answer**: No. *iguana* doesn't support raw pointer, but it will support smart pointer in the future.\n\n- **Question**: Is iguana thread-safe?\n\n  - **Answer**: Not yet, but it's not a problem, you can use `lock` before calling `from_json` or `to_json`.\n\n\n- **Question**: Is *iguana* high performance?\n  - **Answer**: Yes, it is, because *iguana* is based on compile-time reflection.\n\n- **Question**: I found a bug, how could I report?\n  - **Answer**: Create an issue on [GitHub](https://github.com/qicosmos/iguana) with a detailed description. \n\n### deps\nfrozen lib\n\n### Update\n\n1. Support C++20 and C++17\n2. Refactor json reader, modification based on glaze  [json/read.hpp](https://github.com/stephenberry/glaze/blob/main/include/glaze/json/read.hpp)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqicosmos%2Figuana","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqicosmos%2Figuana","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqicosmos%2Figuana/lists"}