Awesome
protobuf-go-lite
protobuf-go-lite is a stripped-down version of the protobuf-go code generator modified to work without reflection and merged with vtprotobuf to provide modular features with static code generation for marshal/unmarshal, size, clone, and equal. It bundles a fork of protoc-gen-go-json for JSON.
Static code generation without reflection is more efficient at runtime and results in smaller code binaries. It also provides better support for tinygo which has limited reflection support.
protobuf-go-lite does not support fieldmasks and extensions.
Ecosystem
Lightweight Protobuf 3 RPCs are implemented in StaRPC for Go and TypeScript.
protoc-gen-doc is recommended for generating documentation.
protobuf-es-lite is recommended for lightweight TypeScript protobufs.
Protobuf
protocol buffers are a cross-platform cross-language message serialization format. Protobuf is a language for specifying the schema for structured data. This schema is compiled into language specific bindings. This project provides both a tool to generate Go code for the protocol buffer language, and also the runtime implementation to handle serialization of messages in Go.
See the protocol buffer developer guide for more information about protocol buffers themselves.
Example
See the protobuf-project template for an example of how to use this package and vtprotobuf together with protowrap to generate protobufs for your project.
This package is available at github.com/aperturerobotics/protobuf-go-lite.
Package index
Summary of the packages provided by this module:
compiler/protogen
: Packageprotogen
provides support for writing protoc plugins.cmd/protoc-gen-go-lite
: Theprotoc-gen-go-lite
binary is a protoc plugin to generate a Go protocol buffer package.
Usage
-
Install
protoc-gen-go-lite
:go install github.com/aperturerobotics/protobuf-go-lite/cmd/protoc-gen-go-lite@latest
-
Update your
protoc
generator to use the new plug-in.for name in $(PROTO_SRC_NAMES); do \ protoc \ --plugin protoc-gen-go-lite="${GOBIN}/protoc-gen-go-lite" --go-lite_out=. \ --go-lite_opt=features=marshal+unmarshal+size+equal+clone \ proto/$${name}.proto; \ done
protobuf-go-lite
replaces protoc-gen-go
and protoc-gen-go-vtprotobuf
and should not be used with those generators.
Check out the template for a quick start!
Available features
The following additional features from vtprotobuf can be enabled:
-
size
: generates afunc (p *YourProto) SizeVT() int
helper that behaves identically to callingproto.Size(p)
on the message, except the size calculation is fully unrolled and does not use reflection. This helper function can be used directly, and it'll also be used by themarshal
codegen to ensure the destination buffer is properly sized before ProtoBuf objects are marshalled to it. -
equal
: generates the following helper methods-
func (this *YourProto) EqualVT(that *YourProto) bool
: this function behaves almost identically to callingproto.Equal(this, that)
on messages, except the equality calculation is fully unrolled and does not use reflection. This helper function can be used directly. -
func (this *YourProto) EqualMessageVT(thatMsg any) bool
: this function behaves like the abovethis.EqualVT(that)
, but allows comparing against arbitrary proto messages. IfthatMsg
is not of type*YourProto
, false is returned. The uniform signature provided by this method allows accessing this method via type assertions even if the message type is not known at compile time. This allows implementing a genericfunc EqualVT(proto.Message, proto.Message) bool
without reflection.
-
-
marshal
: generates the following helper methods-
func (p *YourProto) MarshalVT() ([]byte, error)
: this function behaves identically to callingproto.Marshal(p)
, except the actual marshalling has been fully unrolled and does not use reflection or allocate memory. This function simply allocates a properly sized buffer by callingSizeVT
on the message and then usesMarshalToSizedBufferVT
to marshal to it. -
func (p *YourProto) MarshalToVT(data []byte) (int, error)
: this function can be used to marshal a message to an existing buffer. The buffer must be large enough to hold the marshalled message, otherwise this function will panic. It returns the number of bytes marshalled. This function is useful e.g. when using memory pooling to re-use serialization buffers. -
func (p *YourProto) MarshalToSizedBufferVT(data []byte) (int, error)
: this function behaves likeMarshalTo
but expects that the input buffer has the exact size required to hold the message, otherwise it will panic.
-
-
marshal_strict
: generates the following helper methods-
func (p *YourProto) MarshalVTStrict() ([]byte, error)
: this function behaves likeMarshalVT
, except fields are marshalled in a strict order by field's numbers they were declared in .proto file. -
func (p *YourProto) MarshalToVTStrict(data []byte) (int, error)
: this function behaves likeMarshalToVT
, except fields are marshalled in a strict order by field's numbers they were declared in .proto file. -
func (p *YourProto) MarshalToSizedBufferVTStrict(data []byte) (int, error)
: this function behaves likeMarshalToSizedBufferVT
, except fields are marshalled in a strict order by field's numbers they were declared in .proto file.
-
-
unmarshal
: generates afunc (p *YourProto) UnmarshalVT(data []byte)
that behaves similarly to callingproto.Unmarshal(data, p)
on the message, except the unmarshalling is performed by unrolled codegen without using reflection and allocating as little memory as possible. If the receiverp
is not fully zeroed-out, the unmarshal call will actually behave likeproto.Merge(data, p)
. This is because theproto.Unmarshal
in the ProtoBuf API is implemented by resetting the destination message and then callingproto.Merge
on it. To ensure properUnmarshal
semantics, ensure you've calledproto.Reset
on your message before callingUnmarshalVT
, or that your message has been newly allocated. -
unmarshal_unsafe
generates afunc (p *YourProto) UnmarshalVTUnsafe(data []byte)
that behaves likeUnmarshalVT
, except it unsafely casts slices of data tobytes
andstring
fields instead of copying them to newly allocated arrays, so that it performs less allocations. Data received from the wire has to be left untouched for the lifetime of the message. Otherwise, the message'sbytes
andstring
fields can be corrupted. -
clone
: generates the following helper methods-
func (p *YourProto) CloneVT() *YourProto
: this function behaves similarly to callingproto.Clone(p)
on the message, except the cloning is performed by unrolled codegen without using reflection. If the receiverp
isnil
a typednil
is returned. -
func (p *YourProto) CloneMessageVT() any
: this function behaves like the abovep.CloneVT()
, but provides a uniform signature in order to be accessible via type assertions even if the type is not known at compile time. This allows implementing a genericfunc CloneMessageVT() any
without reflection. If the receiverp
isnil
, a typednil
pointer of the message type will be returned inside aany
interface.
-
-
json
: generates the following helper methods-
func (p *YourProto) UnmarshalJSON(data []byte) error
behaves similarly to callingprotojson.Unmarshal(data, p)
on the message, except the unmarshalling is performed by unrolled codegen without using reflection and allocating as little memory as possible (with json-iterator/go). If the receiverp
is not fully zeroed-out, the unmarshal call will actually behave likeproto.Merge(data, p)
. To ensure properUnmarshal
semantics, ensure you've calledproto.Reset
on your message before callingUnmarshalJSON
, or that your message has been newly allocated. -
func (p *YourProto) UnmarshalJSONValue(val *fastjson.Value) error
unmarshals a*fastjson.Value
. -
func (p *YourProto) MarshalJSON() ([]byte, error)
behaves similarly to callingprotojson.Marshal(p)
on the message, except the marshalling is performed by unrolled codegen without using reflection and allocating as little memory as possible (with json-iterator/go). -
Adding a
//protobuf-go-lite:disable-json
comment before a message or enum will disable the json marshaler / unmarshaler.
-
License
BSD-3