{"id":48376002,"url":"https://github.com/lim-james/static-serial","last_synced_at":"2026-04-05T18:33:45.671Z","repository":{"id":345697653,"uuid":"1186496805","full_name":"lim-james/static-serial","owner":"lim-james","description":"[wip] zero-overhead binary serialization w/ C++26 Reflections","archived":false,"fork":false,"pushed_at":"2026-03-27T16:38:58.000Z","size":67,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-28T01:24:33.780Z","etag":null,"topics":["cpp26","reflections"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lim-james.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-19T17:27:38.000Z","updated_at":"2026-03-27T16:39:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lim-james/static-serial","commit_stats":null,"previous_names":["lim-james/static-serial"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lim-james/static-serial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lim-james%2Fstatic-serial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lim-james%2Fstatic-serial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lim-james%2Fstatic-serial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lim-james%2Fstatic-serial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lim-james","download_url":"https://codeload.github.com/lim-james/static-serial/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lim-james%2Fstatic-serial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31446527,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T15:22:31.103Z","status":"ssl_error","status_checked_at":"2026-04-05T15:22:00.205Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["cpp26","reflections"],"created_at":"2026-04-05T18:33:44.971Z","updated_at":"2026-04-05T18:33:45.662Z","avatar_url":"https://github.com/lim-james.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Static Serial\n\n`C++26` `Reflections` `GCC16`\n\nZero-overhead binary serialization w/ C++26 Reflection support\n\n## Example\n\n```cpp\n#include \"static_serial.hpp\"\n\nauto bid = OrderBookLevel{\n    .price       = 17250, // int64  - 8B\n    .quantity    = 500,   // uint64 - 8B\n    .order_count = 3      // uint32 - 4B\n};\n\nauto raw_bytes = stse::serialize(bid);\nauto restored  = stse::deserialize\u003cOrderBookLevel\u003e(raw_bytes).object;\n\nassert(bid == restored);\nassert(raw_bytes.size() != sizeof(OrderBookLevel));\nassert(raw_bytes.size() == 20); // excludes padding\n```\n\n## Getting Started\n\n\u003e Incomplete segment: to include supported compilers\n\n1. Add `include/static_serial.hpp` into your project. (No support for modules yet)\n2. Done.\n\n## Public Interface\n\n**Serialization Methods**\n```cpp\ntemplate\u003ctypename T, EndianType Endian = NativeEndian\u003e \n[[nodiscard]] constexpr auto serialize(\n    const T\u0026 data, \n    Endian endianness = {}\n) -\u003e std::array\u003cstd::byte, raw_size\u003cT\u003e\u003e;\n\ntemplate\u003ctypename T, EndianType Endian = NativeEndian\u003e \nconstexpr std::span\u003cstd::byte\u003e serialize_into(\n    const T\u0026 data, \n    std::span\u003cstd::byte\u003e destination,\n    Endian endianness = {}\n);\n\n[[nodiscard]] constexpr auto deserialize(\n    std::span\u003cconst std::byte\u003e data, \n    Endian endianness = {}\n) -\u003e DeserializeResult\u003cT\u003e;\n```\n\n**Skip Member Annotation**\n```cpp\ninline constexpr auto skip = skipserialization{};\n// e.g. [[=skip]] int* ignore_member;\n```\n\n**Check Serializability**\n```cpp\ntemplate\u003ctypename T\u003e\n[[nodiscard]] consteval bool is_serializable();\n```\n\n**Endian Specifiers**\n```cpp\ninline constexpr BigEndian    big_endian{};\ninline constexpr LittleEndian little_endian{};\ninline constexpr NativeEndian native_endian{};\n```\n\n**Return Schema**\n```cpp\ntemplate\u003ctypename T\u003e\n[[nodiscard]] std::string schema();\n```\n\n**Deserialize Return Type**\n```cpp\ntemplate\u003ctypename T\u003e\nstruct DeserializeResult {\n    T object;\n    std::span\u003cconst std::byte\u003e offset;\n};\n```\n\n### Supported Types\n\u003e Intend to better define this in a future patch\n\nA rule-of-thumb is serializable objects should have standard layout and no heap\nowning members/pointers.\n\n\n| Serializable | Non-Serializable |\n| --- | --- |\n| Scalar types | Pointers (\u0026 std::nullptr_t) |\n| std::array with trivially copyable types | std::vector (any dynamically sized container) |\n| std::pair with trivially copyable types | std::tuple |\n| Aggregated structs | std::string |\n| Nested structs | |\n\n\n## Zero-overhead Verification\n\nCompiled with GCC 16 `-O2`\n\n\n| Metric          | `-O0`  | `-O2` |\n|-----------------|--------|-------|\n| Function calls  | 94     | 3     |\n| Loop labels     | 76     | 1     |\n| Assembly lines  | 2494   | 446   |\n\n\n## Motivation\n\nI have been hearing a lot about C++26's reflections and wanted to check it out.\nBut I was primarily inspired by [Barry Revzin's Practical Reflection at CppCon25](https://www.youtube.com/watch?v=ZX_z6wzEOG0) and his challenge to see how we can use reflections to solve problems.\n\n## Resources\n- [P2996R12 Paper](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2996r12.html#selecting-members) \n- GCC 16's header files\n\n\u003e As of writing this project, I couldn't find any available resources but that's\n\u003e fine with me because I want to attempt a new form of learning.\n\n## C++26 features explored\n\n1. `template for` expansion statements, complie-time iteration\n2. `std::meta::nonstatic_data_members_of` extract all nonstatic members of given\n   type\n3. `^^` reflection operator - compute reflection value\n4. `[: refl :]` splicers - produce grammatical elements from reflections (copied\n   from P2996\n5. `std::define_static_array` - takes a range and materialize a span for compile\n   time (consteval). Needed this for `template for` \n6. `std::meta::size_of` why this over `sizeof`? Simply because sizeof\n   accomodates for padded bytes whilst meta::size_of is raw number of bytes\n7. `std::meta::annotations_of` for option to omit a field from serialization\n\n## Difficulties faced\n\nIn this section, I will be documenting problems I have faced whilst attempting\nto learn.\n\n1. Compiler \u0026 P-Paper interface mismatch. p-paper describes `member_of(info\n   r)` whilst the compiler takes in an additional parameter `access_context`\n   - Overcomed by referrencing header files directly\n2. `members_of` returns a vector which is heap allocated with new. Doesn't work\n   directly at compile time esp template for. \n    - Use define_static_array which takes in a range and extracts compile time\n    information\n3. Using a recursive serializer leads to some really ugly error messages when an\n   invalid type is deeply nested in a type.\n   - Fixed it by introducing `is_serializable` check at the start of serializing\n4. Static assert messages are a little vague\n    - Waiting for constexpr std::format [P3391](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3391r0.html)\n5. `nonstatic_data_members_of` does not pick up private members\n    - use unchecked access context\n\n## Known issues\n\n1. std::tuple ~and std::pair~ support\n2. ~private data members are not picked up~\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flim-james%2Fstatic-serial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flim-james%2Fstatic-serial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flim-james%2Fstatic-serial/lists"}