Lightweight C++ protobuf & JSON serialization library
- Where simplicity meets usability
- Without protoc and without Google toolchain dependency
- Define your data in standard
.protofiles. - Generate clean, native C++ structs.
- Serialize/deserialize to
protobuf(GPB-wire-compatible) andJSON(GPB-compatible) with minimal effort.
// proto/person.proto, hand written
package PhoneBook;
message Person {
optional string name = 1;
optional int32 id = 2; // Unique ID number for this person.
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1; // phone number is always required
optional PhoneType type = 2;
}
// all registered phones
repeated PhoneNumber phones = 4;
}# CMakeLists.txt, hand written
add_subdirectory(external/simple-protobuf) # or FetchContent
add_executable(myapp main.cpp proto/person.proto)
spb_protobuf_generate(TARGET myapp)// proto/person.pb.h, generated
namespace PhoneBook
{
struct Person {
enum class PhoneType : int32_t {
MOBILE = 0,
HOME = 1,
WORK = 2,
};
struct PhoneNumber {
// phone number is always required
std::string number;
std::optional<PhoneType> type;
};
std::optional<std::string> name;
// Unique ID number for this person.
std::optional<int32_t> id;
std::optional<std::string> email;
// all registered phones
std::vector<PhoneNumber> phones;
};
} // namespace PhoneBook// main.cpp, hand written
#include <iostream>
#include <proto/person.pb.h> // <- generated
int main() {
const auto john = phonebook::Person{
.name = "John Doe",
.id = 1234,
.email = "john@example.com",
.phones = {{.number = "123456789", .type = phonebook::Person::PhoneType::MOBILE}}
};
// JSON round-trip
const auto json = spb::json::serialize<std::string>(john);
std::cout << "JSON:\n" << json << "\n\n";
// Protobuf binary round-trip
const auto pb_bytes = spb::pb::serialize<std::vector<std::byte>>(john);
const auto decoded_json = spb::json::deserialize<phonebook::Person>(json);
const auto decoded_pb = spb::pb::deserialize<phonebook::Person>(pb_bytes);
// All equal: john == decoded_json == decoded_pb
}- No
protocorGoogle libsdependency - instead it uses its own proto-compiler calledsprotoc. - Supports
.protofiles withproto2orproto3syntax (no edition syntax). - Generates clean, modern C++ with
std::optional,std::vector, andenum class. - Bundles protobuf and JSON support in a single library.
- Serialized protobuf and JSON are compatible with official protoc, Python, Go, Java.
- Embedded-friendly, zero heap allocations when paired with ETL or fixed-size strings/vectors.
- See options for user-specified types and advanced usage.
- C++ compiler with C++20 support
- CMake
- Standard C++ library
- (optional) clang-format for code formatting
| proto type | CPP type | GPB encoding |
|---|---|---|
bool |
bool |
varint |
float |
float |
4 bytes |
double |
double |
8 bytes |
int32 |
int32_t |
varint |
sint32 |
int32_t |
zig-zag varint |
uint32 |
uint32_t |
varint |
int64 |
int64_t |
varint |
sint64 |
int64_t |
zig-zag varint |
uint64 |
uint64_t |
varint |
fixed32 |
uint32_t |
4 bytes |
sfixed32 |
int32_t |
4 bytes |
fixed64 |
uint64_t |
8 bytes |
sfixed64 |
int64_t |
8 bytes |
string |
std::string |
UTF-8 string |
bytes |
std::vector<std::byte> |
base64 encoded in JSON |
message |
struct |
length delimited |
enum |
enum class |
varint |
map |
std::map<,> |
|
oneof |
std::variant<> |
| proto type modifier | CPP type modifier | Notes |
|---|---|---|
optional |
std::optional<Message> |
|
optional |
std::unique_ptr<Message> |
for cyclic message dependencies (A -> B, B -> A) |
repeated |
std::vector<Message> |
See also options for user-specified types and advanced usage.
See the example directory.
Tiny and Fast
Measured on Linux/i7-8650U CPU @ 1.90GHz with GCC 16.1.1 -flto -O2 using nanobench.
See the benchmark directory.
- SPB protobuf serializer/deserializer has about the same speed as google GPB.
- SPB JSON serializer/deserializer is about 8x faster than google GPB.
Measured on stripped executable files
$ find build/benchmark -type f -executable -exec strip --strip-all {} +
$ ls -alh ./build/benchmark- SPB is tiny compared to google GPB, which makes it ideal for Embedded systems.
- Make it work
- Make it right
- Make it fast
- Parser for proto files (supported syntax:
proto2andproto3) - Compile proto messages to C++ data structs
- JSON de/serializer for generated C++ data structs (serialized JSON is GPB-compatible)
- Protobuf de/serializer for generated C++ data structs (serialized protobuf is GPB-compatible)
- Implement options and user-specified types/containers
- Benchmarks for size and speed, direct comparison with other libraries (official protobuf, nanopb)
- gRPC is not implemented

