{"id":15102726,"url":"https://github.com/tonda-kriz/simple-protobuf","last_synced_at":"2026-01-18T22:33:47.642Z","repository":{"id":239786259,"uuid":"800524522","full_name":"tonda-kriz/simple-protobuf","owner":"tonda-kriz","description":"C++ protobuf serialization library","archived":false,"fork":false,"pushed_at":"2025-12-08T20:04:41.000Z","size":483,"stargazers_count":14,"open_issues_count":5,"forks_count":6,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-09T05:30:59.691Z","etag":null,"topics":["json","json-parser","json-schema","json-serialization","protobuf","protocol-buffers","protocol-compiler","serialization"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tonda-kriz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["tonda-kriz"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2024-05-14T13:53:37.000Z","updated_at":"2025-12-05T17:48:53.000Z","dependencies_parsed_at":"2024-06-03T17:07:55.666Z","dependency_job_id":"407d4f77-d967-4a70-ad3b-3d28425f8448","html_url":"https://github.com/tonda-kriz/simple-protobuf","commit_stats":null,"previous_names":["tonda-kriz/sds-protobuf","tonda-kriz/simple-protobuf"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tonda-kriz/simple-protobuf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonda-kriz%2Fsimple-protobuf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonda-kriz%2Fsimple-protobuf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonda-kriz%2Fsimple-protobuf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonda-kriz%2Fsimple-protobuf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tonda-kriz","download_url":"https://codeload.github.com/tonda-kriz/simple-protobuf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonda-kriz%2Fsimple-protobuf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28552785,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T20:59:07.572Z","status":"ssl_error","status_checked_at":"2026-01-18T20:59:02.799Z","response_time":98,"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":["json","json-parser","json-schema","json-serialization","protobuf","protocol-buffers","protocol-compiler","serialization"],"created_at":"2024-09-25T19:05:28.613Z","updated_at":"2026-01-18T22:33:47.636Z","avatar_url":"https://github.com/tonda-kriz.png","language":"C++","funding_links":["https://github.com/sponsors/tonda-kriz"],"categories":[],"sub_categories":[],"readme":"# simple-protobuf\n\n[![Linux-build](https://github.com/tonda-kriz/simple-protobuf/actions/workflows/ci-linux-tests.yml/badge.svg)](https://github.com/tonda-kriz/simple-protobuf/actions/workflows/ci-linux-tests.yml)\n[![Windows-build](https://github.com/tonda-kriz/simple-protobuf/actions/workflows/ci-windows-tests.yml/badge.svg)](https://github.com/tonda-kriz/simple-protobuf/actions/workflows/ci-windows-tests.yml)\n[![Mac-build](https://github.com/tonda-kriz/simple-protobuf/actions/workflows/ci-macos-tests.yml/badge.svg)](https://github.com/tonda-kriz/simple-protobuf/actions/workflows/ci-macos-tests.yml)\n[![Library-coverage](https://tonda-kriz.github.io/simple-protobuf/library/coverage.svg)](https://tonda-kriz.github.io/simple-protobuf/library)\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://matrix.to/#/#simple-protobuf:gitter.im)\n\n**simple data struct** serialization library for C++. With this library you can serialize and deserialize *POD* C++ structs directly to [JSON](https://json.org) or [protobuf](https://github.com/protocolbuffers/protobuf).\nWhen used together with [etl library](https://github.com/ETLCPP/etl) it doesn't need to allocate any memory, so its suitable for embedded environments (see [extensions](doc/extensions.md)).\n\n```CPP\nnamespace PhoneBook\n{\nstruct Person {\n    enum class PhoneType : int32_t {\n        MOBILE = 0,\n        HOME   = 1,\n        WORK   = 2,\n    };\n    struct PhoneNumber {\n        // phone number is always required\n        etl::string\u003c16\u003e number;\n        std::optional\u003c PhoneType \u003e type;\n    };\n    std::optional\u003c std::string \u003e name;\n    // Unique ID number for this person.\n    std::optional\u003c int32_t \u003e id;\n    std::optional\u003c std::string \u003e email;\n    // all registered phones\n    std::vector\u003c PhoneNumber \u003e phones;\n};\n}// namespace PhoneBook\n\nauto john = PhoneBook::Person{\n        .name  = \"John Doe\",\n        .id    = 1234,\n        .email = \"jdoe@example.com\",\n    };\n//- serialize john to json-string\nauto json    = spb::json::serialize\u003c std::string \u003e( john );\n//- deserialize john from json-string\nauto person  = spb::json::deserialize\u003c PhoneBook::Person \u003e( json );\n//- serialize john to protobuf-vector\nauto pb      = spb::pb::serialize\u003c std::vector\u003c std::byte \u003e \u003e( john );\n//- deserialize john from protobuf-vector\nauto person2 = spb::pb::deserialize\u003c PhoneBook::Person \u003e( pb );\n//- john == person == person2\n```\n\n## goal\n\ngoal of this library is to make [JSON](https://json.org) and [protobuf](https://github.com/protocolbuffers/protobuf) *part* of the C++ language itself.\n\n## reason\n\nThere are literally a tons of [JSON](https://json.org) C++ libraries but most of them are designed in a way that the user needs to construct the json *Object* via some API and for serialization and deserialization there is a lot of boilerplate code like type/schema checking, `to_json`, `from_json`, macros... All this is needed to be done by the user, and it usually ends up with a conversion to some C++ struct.\n\nspb works the other way around, from C++ struct to [JSON](https://json.org) or [protobuf](https://github.com/protocolbuffers/protobuf). With this approach user can focus only on the data, C++ struct, which is much more natural and spb will handle all the boring stuff like serialization/deserialization and type/schema checking.\n\n## about\n\nspb is an alternative implementation of [protobuf](https://github.com/protocolbuffers/protobuf) for C++. This is not an plugin for `protoc` but an **replacement** for `protoc`, so you don't need `protobuf` or `protoc` installed to use it. Serialization and deserialization to [JSON](https://json.org) or [protobuf](https://github.com/protocolbuffers/protobuf) is compatible with `protoc`, in other words, data serialized with code generated by `spb-protoc` can be deserialized by code generated by `protoc` and vice versa.\n\n## usage\n\n### dependencies\n\n* C++ compiler (at least C++20)\n* cmake\n* std library\n* *(optional) clang-format for code formatting*\n\n### cheat sheet\n\n```cmake\n# add this repo to your project\nadd_subdirectory(external/spb-proto)\n# add .proto files to some `target`\nadd_executable(myapp myapp.cc proto/person.proto)\n# compile proto files to C++ and add them to myapp\nspb_protobuf_generate(TARGET myapp)\n```\n\n### how to use\n\n1. define a schema for you data in a `person.proto` file\n\n```proto\npackage PhoneBook;\n\nmessage Person {\n  optional string name = 1;\n  optional int32 id = 2;  // Unique ID number for this person.\n  optional string email = 3;\n\n  enum PhoneType {\n    MOBILE = 0;\n    HOME = 1;\n    WORK = 2;\n  }\n\n  message PhoneNumber {\n    required string number = 1; // phone number is always required\n    optional PhoneType type = 2;\n  }\n  // all registered phones\n  repeated PhoneNumber phones = 4;\n}\n```\n\n2. compile `person.proto` with `spb-protoc` into `person.pb.h` and `person.pb.cc`\n\n```cmake\nspb_protobuf_generate(TARGET myapp proto/person.proto)\n```\nor\n```cmake\nspb_protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto/person.proto)\ntarget_sources(myapp PRIVATE ${PROTO_SRCS} ${PROTO_HDRS})\n```\n\n*for a brief moment... observe the beautifully generated `person.pb.h` and `person.pb.cc`*\n\n```C++\nnamespace PhoneBook\n{\nstruct Person {\n    enum class PhoneType : int32_t {\n        MOBILE = 0,\n        HOME   = 1,\n        WORK   = 2,\n    };\n    struct PhoneNumber {\n        // phone number is always required\n        std::string number;\n        std::optional\u003c PhoneType \u003e type;\n    };\n    std::optional\u003c std::string \u003e name;\n    // Unique ID number for this person.\n    std::optional\u003c int32_t \u003e id;\n    std::optional\u003c std::string \u003e email;\n    // all registered phones\n    std::vector\u003c PhoneNumber \u003e phones;\n};\n}// namespace PhoneBook\n```\n\n3. use `Person` struct natively and de/serialize to/from json/pb\n\n```CPP\n#include \u003cproto/person.pb.h\u003e\n\nauto john = PhoneBook::Person{\n        .name  = \"John Doe\",\n        .id    = 1234,\n        .email = \"jdoe@example.com\",\n    };\n\nauto json    = spb::json::serialize( john );\nauto person  = spb::json::deserialize\u003c PhoneBook::Person \u003e( json );\nauto pb      = spb::pb::serialize( john );\nauto person2 = spb::pb::deserialize\u003c PhoneBook::Person \u003e( pb );\n//- john == person == person2\n```\n\n## API\n\nAll generated messages (and enums) are using the following API [`include/spb/json.hpp`](include/spb/json.hpp) and [`include/spb/pb.hpp`](include/spb/pb.hpp)\n\n```CPP\n//- serialize message via writer (all other `serialize` are just wrappers around this one)\n//- example: `auto serialized_size = spb::pb::serialize( message, my_writer );`\nauto serialize( const auto \u0026 message, spb::io::writer on_write ) -\u003e size_t;\n\n//- return size in bytes of serialized message\n//- example: `auto serialized_size = spb::pb::serialize_size( message );`\nauto serialize_size( const auto \u0026 message ) -\u003e size_t;\n\n//- serialize message into container like std::string, std::vector, ...\n//- example: `auto serialized_size = spb::pb::serialize( message, my_string );`\ntemplate \u003c typename Message, spb::resizable_container Container \u003e\nauto serialize( const Message \u0026 message, Container \u0026 result ) -\u003e size_t;\n\n//- serialize message and return container like std::string, std::vector, ...\n//- example: `auto my_string = spb::pb::serialize\u003c std::string \u003e( message );`\ntemplate \u003c spb::resizable_container Container = std::string, typename Message \u003e\nauto serialize( const Message \u0026 message ) -\u003e Container;\n\n```\n\n```CPP\n//- deserialize message from reader (all other `deserialize` are just wrappers around this one)\n//- example: `spb::pb::deserialize( message, my_reader );`\nvoid deserialize( auto \u0026 message, spb::io::reader on_read );\n\n//- deserialize message from container like std::string, std::vector, ...\n//- example: `spb::pb::deserialize( message, my_string );`\ntemplate \u003c typename Message, spb::size_container Container \u003e\nvoid deserialize( Message \u0026 message, const Container \u0026 protobuf );\n\n\n//- return deserialized message from container like std::string, std::vector, ...\n//- example: `auto message = spb::pb::deserialize\u003c Message \u003e( my_string );`\ntemplate \u003c typename Message, spb::size_container Container \u003e\nauto deserialize( const Container \u0026 protobuf ) -\u003e Message;\n\n//- return deserialized message from reader\n//- example: `auto message = spb::pb::deserialize\u003c Message \u003e( my_reader );`\ntemplate \u003c typename Message \u003e\nauto deserialize( spb::io::reader reader ) -\u003e Message;\n```\n\nAPI is prefixed with `spb::json::` for **json** and `spb::pb::` for **protobuf**,\ntemplate concepts [`spb::size_container`](include/spb/concepts.h) and [`spb::resizable_container`](include/spb/concepts.h) are defined in [`include/spb/concepts.h`](include/spb/concepts.h), [`spb::io::reader`](include/spb/io/io.hpp) and [`spb::io::writer`](include/spb/io/io.hpp) are user specified *functions* for IO, more info at [`include/io/io.hpp`](include/spb/io/io.hpp)\n\n## type mapping\n\n| proto type | CPP type    | GPB encoding |\n|------------|-------------|-------------|\n| `bool`     | `bool`      | varint      |\n| `float`    | `float`     | 4 bytes     |\n| `double`   | `double`    | 8 bytes     |\n| `int32`    | `int32_t`   | varint      |\n| `sint32`   | `int32_t`   | zig-zag varint |\n| `uint32`   | `uint32_t`  | varint      |\n| `int64`    | `int64_t`   | varint      |\n| `sint64`   | `int64_t`   | zig-zag varint |\n| `uint64`   | `uint64_t`  | varint      |\n| `fixed32`  | `uint32_t`  | 4 bytes     |\n| `sfixed32` | `int32_t`   | 4 bytes     |\n| `fixed64`  | `uint64_t`  | 8 bytes     |\n| `sfixed64` | `int64_t`   | 8 bytes     |\n| `string`   | `std::string` | utf8 string |\n| `bytes`    | `std::vector\u003c std::byte \u003e` | base64 encoded in json            |\n\n| proto type modifier | CPP type modifier   | Notes       |\n|---------------------|-------------|-------------|\n| `optional`          | `std::optional\u003cMessage\u003e` |             |\n| `optional`          | `std::unique_ptr\u003cMessage\u003e` | if there is cyclic dependency between messages ( A -\u003e B, B -\u003e A )|\n| `repeated`          | `std::vector\u003cMessage\u003e`  |             |\n\nSee also [extensions](doc/extensions.md) for user specific types and advanced usage.\n\n## example\n\nnavigate to the [example](example/) directory.\n\n## status\n\n* [x] Make it work\n* [x] Make it right\n* [ ] Make it fast\n\n### roadmap\n\n* [x] parser for proto files (supported syntax: `proto2` and `proto3`)\n* [x] compile proto message to C++ data struct\n* [x] generate json de/serializer for generated C++ data struct (serialized json has to be compatible with GPB)\n* [x] generate protobuf de/serializer for generated C++ data struct (serialized pb has to be compatible with GPB)\n\n### missing features\n\n* RPC is not implemented\n* extend is not implemented\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonda-kriz%2Fsimple-protobuf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftonda-kriz%2Fsimple-protobuf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonda-kriz%2Fsimple-protobuf/lists"}