std::protobuf
std::protobuf provides dependency-free Protocol Buffers binary wire helpers
for Silk code and for modules generated by silk proto.
The module covers the proto3 wire-format primitives:
- varint keys and integer payloads,
- ZigZag
sint32/sint64, - little-endian fixed32/fixed64 payloads,
- length-delimited strings, bytes, embedded messages, and packed repeated fields,
- field skipping,
- and preservation of unknown field bytes.
It intentionally does not shell out to protoc and does not depend on a C or
third-party protobuf runtime.
Types#
WireTypeis the protobuf wire type tag enum. Usewire_type_code()andwire_type_from_code()when storing or validating numeric wire tags.DecodeErrorKindis the stable decode error category enum.DecodeErrorcarriescode, byteoffset,field_number, and numericwire_typecontext.kind()converts the stored code back toDecodeErrorKind;message()returns a short human-readable message.Keyis the decoded(field_number, wire_type)record key returned byReader.read_key().Readeris a borrowing binary reader overstd::arrays::ByteSlice.Decode*Resultaliases arestd::result::Result(..., DecodeError)shapes used by reader methods.
Strings and byte slices decoded by Reader borrow from the input byte slice.
Callers must keep the original byte storage alive for as long as decoded
strings or bytes are used.
Reading#
Create a reader with:
let mut reader = std::protobuf::Reader.from_bytes(bytes);
Then repeatedly call read_key() until reader.eof():
let key_r = reader.read_key();
if let Err(e) = key_r {
return 1;
}
let key = match key_r {
Ok(value) => value,
Err(_) => std::protobuf::Key{ field_number: 0, wire_type: std::protobuf::WireType::Varint },
};
Payload helpers include:
read_varint()read_length()read_i32()read_i64()read_uint32()read_sint32()read_sint64()read_fixed32_bits()read_fixed64_bits()read_float()read_double()read_bool()read_bytes()read_string()skip_field(key)
Generated string decoders use read_bytes() and convert the byte slice to a
borrowed string view, which keeps string payload handling explicit.
Writing#
Writers append to std::buffer::BufferU8 and return
std::memory::OutOfMemory?:
let mut out = BufferU8.empty();
if std::protobuf::write_int64(mut out, 1, 42) != None {
return 1;
}
Payload helpers include:
write_varint(out, value)write_key(out, field_number, wire_type)write_bool(out, field_number, value)write_uint64(out, field_number, value)write_int64(out, field_number, value)write_sint32(out, field_number, value)write_sint64(out, field_number, value)write_fixed32_bits(out, field_number, value)write_fixed32_payload(out, value)write_fixed64_bits(out, field_number, value)write_fixed64_payload(out, value)write_float(out, field_number, value)write_double(out, field_number, value)write_bytes(out, field_number, bytes)write_string(out, field_number, value)append_unknown_field(out, source, start, end)
append_unknown_field() copies a raw field record from source[start..end) and
is used by generated decoders to preserve forward-compatible data.
silk proto#
Use silk proto to compile .proto files to Silk modules:
silk proto -I schemas -o generated schemas/person.proto
The compiler accepts proto3 files with syntax = "proto3"; and covers:
- packages and imports,
- normal imports,
import publicre-exports, and missingimport weakdeclarations when no referenced type depends on the weak file, - adjacent protobuf string literals in string-valued schema positions, including syntax, import paths, and reserved names,
- protobuf integer literals in decimal, hexadecimal, octal, and signed forms where the schema grammar permits signed integers,
- file/message/field/enum/service options,
- messages and nested messages,
- enums and aliases,
- scalar, message, enum, optional, repeated, oneof, and map fields,
- reserved field names and ranges,
- services/rpcs as generated descriptor structs and lookup functions,
- recursive import loading through
-I/--proto-path, - default emission of imported schema dependencies needed by generated Silk imports,
- complete
--descriptor-outJSON summaries for files, imports, options, messages, fields, oneofs, nested types, enums, services, RPCs, reserved declarations, resolved type names, and generated module/type names, - field-number validation, reserved-range validation, duplicate detection,
generated Silk name-collision validation, generated storage-field collision
validation, map key validation, enum-zero validation, type-reference
validation, cross-file import visibility validation, cyclic import detection,
and targeted rejection of unsupported
extend,extensions, andgroupdeclarations.
Generated modules include:
- Silk structs for messages,
- Silk enums for known constants, raw-preserving
EnumValuewrappers for enum field storage, and numeric conversion helpers for protobuf enum values, - vector aliases for repeated/map fields,
T?storage for singular message fields and explicitoptionalfields, withNonerepresenting absent fields andSome(value)representing presence,empty(),drop(),encode(),decode(), andmerge_from()methods for messages,- service RPC descriptor structs plus
<Service>_RPC_COUNTand<Service>_rpc(index)metadata helpers, - raw unknown-field storage slots plus
unknown_fields()for preserved unknown field bytes.
Generated modules type-check, expose their public API surface, build as object
code, and can be imported by Silk programs that construct messages, encode
them, decode them, and inspect decoded fields. The regression suite covers both
direct std::protobuf wire helpers and an end-to-end generated-message
round-trip executable.
Generated cross-file references use named Silk imports. The generator keeps the original proto type name when it is unique in the generated module and uses a deterministic alias only when a name collision would otherwise occur.
Compatibility#
std::protobuf follows proto3 binary wire-format compatibility rules:
- singular scalar fields default to the proto3 zero value,
- singular message fields use presence, default to
None, and encode only when set toSome(value); repeated wire occurrences merge into the existing message payload, - explicit
optionalfields useT?storage and followNone/Some(value)presence, - enum fields use generated raw-value wrappers, so numeric values unknown to the current schema are preserved and re-encoded instead of being coerced to a default or discarded,
- repeated primitive and enum fields accept packed and unpacked encodings,
- repeated message, string, and bytes fields accept length-delimited unpacked records,
- generated decoders validate a known field's wire type before consuming its payload,
- unknown fields are preserved verbatim when generated decoders skip them,
- and unsupported or missing imports are reported by
silk protoinstead of being silently ignored.
Generated encoders emit proto3 packed encoding for repeated scalar and enum
fields by default. A field option of [packed = false] forces unpacked
encoding. Decoders accept both packed and unpacked encodings for packable fields
so schema changes remain wire-compatible.
Descriptor JSON#
silk proto --descriptor-out <path> writes a deterministic JSON document:
- top-level
versionis1; files[]recordspath,source_path,syntax,package, generatedmodule,explicit_input,imports,options,messages,enums, andservices;- message descriptors include generated Silk names, options, reserved names and ranges, fields, oneofs, nested messages, and nested enums;
- field descriptors include protobuf name/number/label/type, semantic kind
(
scalar,message,enum, ormap), resolved full type names when applicable, oneof membership, packed-encoding status, map key/value metadata, and raw field options; - enum descriptors include values, aliases as repeated numeric values, options, and reserved declarations;
- service descriptors include RPC names, request/response type names, resolved full type names, streaming flags, and options.
Source repository · Edit this page · View Markdown