std1.0.0-beta-7 SafeC docs

Module serial::protobuf

#include <std/serial/protobuf.h> source

Protocol Buffers wire format (proto3 binary encoding, https://protobuf.dev/programming-guides/encoding/).

This is a wire-format primitive library, not a .proto-file IDL compiler (SafeC has no field-name/field-number reflection to drive code generation from a schema — see std/serial/value.h's top comment on the same limitation for JSON). Making a struct protobuf-serializable means writing 'to_proto()'/'from_proto()' methods by hand that call these primitives with the field numbers your .proto schema assigns:

// .proto: message Point { int32 x = 1; int32 y = 2; }
struct Point { int x; int y; };
struct String Point::to_proto() const {
    struct String out = String::new();
    pb_write_int64_field(&out, 1, (long long)self.x);
    pb_write_int64_field(&out, 2, (long long)self.y);
    return out;
}
struct Point Point::from_proto(const unsigned char* data, unsigned long len, int* ok) {
    struct Point p;
    p.x = 0; p.y = 0;
    struct PbReader r = PbReader::new(data);
    int good = 1;
    while (r.has_more()) {
        int field; int wireType;
        if (!r.read_tag(&field, &wireType)) { good = 0; break; }
        if (field == 1 && wireType == PB_WIRE_VARINT) {
            long long v; r.read_int64(&v); p.x = (int)v;
        } else if (field == 2 && wireType == PB_WIRE_VARINT) {
            long long v; r.read_int64(&v); p.y = (int)v;
        } else if (!r.skip_field(wireType)) { good = 0; break; }
    }
    if (ok != (int*)0) { *ok = good; }
    return p;
}

Interoperates with real protobuf implementations in other languages — the wire format itself (varint, tags, zigzag, length-delimited, fixed32/fixed64) is exactly what protoc-generated code produces, field numbers and wire types are the only thing that has to match by hand since there's no shared .proto schema driving both sides here.

Structs

PbReader

Functions

pb_write_varint
pb_write_tag
pb_write_int64_fieldint32/int64: plain varint of the value's bit pattern (protobuf's own quirk: a negative int32 is sign-extended to 64 bits before varint encoding, so it always takes the full 10 bytes on the wire — this matches protoc's own behavior, not a bug).
pb_write_uint64_field
pb_write_sint64_fieldsint32/sint64: zigzag-encoded varint (efficient for small negative values, unlike plain int64 above).
pb_write_bool_field
pb_write_double_field
pb_write_float_field
pb_write_string_fieldLength-delimited: string, bytes, or an embedded/nested message's own already-encoded bytes (encode the submessage with its own to_proto() first, then pass the result here).
pb_write_bytes_field

Macros

PB_WIRE_VARINTint32/int64/uint32/uint64/sint32/sint64/bool/enum
PB_WIRE_FIXED64fixed64/sfixed64/double
PB_WIRE_LENstring/bytes/embedded messages/packed repeated
PB_WIRE_FIXED32fixed32/sfixed32/float