aperturerobotics/protobuf-go-lite

GitHub: aperturerobotics/protobuf-go-lite

一个无反射、高性能的 Go 语言 Protocol Buffers 静态代码生成器,旨在生成更小的二进制文件并提升序列化运行时效率。

Stars: 56 | Forks: 5

# protobuf-go-lite [![GoDoc Widget]][GoDoc] [![Go Report Card Widget]][Go Report Card] [![DeepWiki Widget]][DeepWiki] **protobuf-go-lite** 是 [protobuf-go] 代码生成器的一个精简版本,经过修改后无需 reflection 即可运行,并与 [vtprotobuf] 合并,通过静态代码生成提供针对 marshal/unmarshal、size、clone、equal、text 和 JSON 的模块化功能。JSON 支持派生于 [protoc-gen-go-json] 的一个分支。 无需 reflection 的静态代码生成在 runtime 时效率更高,并且生成的代码二进制文件更小。它还为对 reflection 支持有限的 [tinygo] 提供了更好的支持。 protobuf-go-lite 支持解析为开放 Go API 且静态、无 reflect 生成输出的 Edition 2024 schema。默认的 `features=all` 路径支持显式和隐式存在性、legacy required fields、packed 编码、delimited message 编码、oneofs、maps、clone/equal、text、unmarshal、unsafe unmarshal,以及在解析出的 JSON 格式为 `ALLOW` 时的 JSON。 生成的输出是静态 Go 代码。默认的 `codegen=helper` 模式会发出 message 方法,这些方法会调用根 `protobuf-go-lite` runtime 包中的小型具体 helper,以使生成的 `.pb.go` 文件更小。备选的 `codegen=unrolled` 模式在调用者需要检查或比较该输出时,会为转换为 helper 的方法族保留较旧的内联方法体形状。这两种模式都不依赖于 Go reflection、descriptors、struct tags 或 runtime 类型元数据来实现生成的 marshal、unmarshal、size、clone、equal、text 或 JSON 行为。 protobuf-go-lite 拒绝需要 closed enum 语义、`LEGACY_BEST_EFFORT` JSON 或显式 hybrid/opaque Go API 的 Edition schema。它不支持 fieldmasks 和 extensions。 ### 生态系统 轻量级的 Protobuf 3 RPC 在 [StaRPC] 中为 Go 和 TypeScript 实现。 推荐使用 [protoc-gen-doc] 来生成文档。 推荐使用 [protobuf-es-lite] 来处理轻量级的 TypeScript protobufs。 ## Protobuf [protocol buffers](https://protobuf.dev) 是一种跨平台、跨语言的消息序列化格式。Protobuf 是一种用于指定结构化数据 schema 的语言。该 schema 会被编译为特定语言的绑定。本项目既提供了为 protocol buffer 语言生成 Go 代码的工具,也提供了处理 Go 中消息序列化的 runtime 实现。 有关 protocol buffers 本身的更多信息,请参阅 [protocol buffer 开发者指南](https://protobuf.dev/overview)。 ## 示例 请参阅 [protobuf-project](https://github.com/aperturerobotics/protobuf-project) 模板,了解如何将此包和 vtprotobuf 与 protowrap 结合使用来为您的项目生成 protobufs。 此包可在 **github.com/aperturerobotics/protobuf-go-lite** 获取。 ## 包索引 本模块提供的包摘要: * [`compiler/protogen`](https://pkg.go.dev/github.com/aperturerobotics/protobuf-go-lite/compiler/protogen): `protogen` 包为编写 protoc 插件提供支持。 * [`cmd/protoc-gen-go-lite`](https://pkg.go.dev/github.com/aperturerobotics/protobuf-go-lite/cmd/protoc-gen-go-lite): `protoc-gen-go-lite` 二进制文件是一个用于生成 Go protocol buffer 包的 protoc 插件。 ## 用法 1. 安装 `protoc-gen-go-lite`: go install github.com/aperturerobotics/protobuf-go-lite/cmd/protoc-gen-go-lite@latest 2. 更新您的 `protoc` 生成器以使用新插件。 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+text \ proto/$${name}.proto; \ done `protobuf-go-lite` 取代了 `protoc-gen-go` 和 `protoc-gen-go-vtprotobuf`,不应与那些生成器一起使用。 查看[模板](https://github.com/aperturerobotics/template)以快速入门! ### 代码生成模式 `protoc-gen-go-lite` 接受 `codegen=helper` 和 `codegen=unrolled`: - `codegen=helper` 是默认值。它会发出调用具体 runtime helper 的静态 message 方法,例如 encode、decode、clone/equal、size 和 text helper。 - `codegen=unrolled` 会为转换为 helper 的方法族发出较旧的内联方法体样式。通过将 `codegen=unrolled` 添加到 `--go-lite_opt` 来选择它。 这两种模式都在生成时选择,并为调用者生成普通的 Go 包。它们不会为生成的快速路径添加 reflection 注册表、descriptor 构建器、struct tag 解释器或 runtime 类型元数据依赖。 ### 生成的输出 此存储库的 fixtures 和 well-known type 包的生成 `.pb.go` 文件已被签入。更改生成器或 runtime helper 后,使用 GNU Make 目标重新生成并验证它们: ``` gmake gengo gmake check-gengo ``` 在 `make` 为 GNU Make 的系统上,`make check-gengo` 具有同等效果。在 macOS 上,请使用 `gmake`,以便在本地和 Linux CI 中使用相同的 GNU Make 行为。 ## 可用功能 可以启用以下附加功能: - `size`:生成一个 `func (p *YourProto) SizeVT() int` helper,其行为与在消息上调用 `proto.Size(p)` 完全相同,不同之处在于 size 计算是静态生成的代码,不使用 reflection。此 helper 函数可以直接使用,并且也会被 `marshal` codegen 使用,以确保在将 ProtoBuf 对象 marshal 到目标缓冲区之前,其大小已正确调整。 - `equal`:生成以下 helper 方法 - `func (this *YourProto) EqualVT(that *YourProto) bool`:此函数的行为与在消息上调用 `proto.Equal(this, that)` 几乎完全相同,不同之处在于相等性计算是静态生成的代码,不使用 reflection。此 helper 函数可以直接使用。 - `func (this *YourProto) EqualMessageVT(thatMsg any) bool`:此函数的行为类似于上面的 `this.EqualVT(that)`,但允许与任意 proto 消息进行比较。如果 `thatMsg` 的类型不是 `*YourProto`,则返回 false。此方法提供的统一签名允许即使在编译时不知道消息类型的情况下,也可以通过类型断言访问此方法。这允许实现没有 reflection 的通用 `func EqualVT(proto.Message, proto.Message) bool`。 - `marshal`:生成以下 helper 方法 - `func (p *YourProto) MarshalVT() ([]byte, error)`:此函数的行为与调用 `proto.Marshal(p)` 完全相同,不同之处在于实际的 marshalling 是静态生成的代码,不使用 reflection 或分配内存。此函数只需通过在消息上调用 `SizeVT` 分配一个大小合适的缓冲区,然后使用 `MarshalToSizedBufferVT` 将其 marshal 到其中。 - `func (p *YourProto) MarshalToVT(data []byte) (int, error)`:此函数可用于将消息 marshal 到现有缓冲区。缓冲区必须足够大以容纳 marshalled 后的消息,否则此函数会 panic。它返回 marshal 的字节数。例如,当使用内存池来重用序列化缓冲区时,此函数非常有用。 - `func (p *YourProto) MarshalToSizedBufferVT(data []byte) (int, error)`:此函数的行为类似于 `MarshalTo`,但期望输入缓冲区具有容纳消息所需的精确大小,否则会 panic。 - `marshal_strict`:生成以下 helper 方法 - `func (p *YourProto) MarshalVTStrict() ([]byte, error)`:此函数的行为类似于 `MarshalVT`,不同之处在于字段会根据在 .proto 文件中声明的字段编号按严格顺序进行 marshal。 - `func (p *YourProto) MarshalToVTStrict(data []byte) (int, error)`:此函数的行为类似于 `MarshalToVT`,不同之处在于字段会根据在 .proto 文件中声明的字段编号按严格顺序进行 marshal。 - `func (p *YourProto) MarshalToSizedBufferVTStrict(data []byte) (int, error)`:此函数的行为类似于 `MarshalToSizedBufferVT`,不同之处在于字段会根据在 .proto 文件中声明的字段编号按严格顺序进行 marshal。 - `unmarshal`:生成一个 `func (p *YourProto) UnmarshalVT(data []byte)`,其行为类似于在消息上调用 `proto.Unmarshal(data, p)`,不同之处在于 unmarshalling 是由静态生成的代码执行的,不使用 reflection 并尽可能少地分配内存。如果接收者 `p` **未**完全归零,则 unmarshal 调用实际上会表现得像 `proto.Merge(data, p)`。这是因为 ProtoBuf API 中的 `proto.Unmarshal` 是通过重置目标消息然后对其调用 `proto.Merge` 来实现的。为了确保正确的 `Unmarshal` 语义,请确保在调用 `UnmarshalVT` 之前已对消息调用过 `proto.Reset`,或者您的消息是新分配的。 - `unmarshal_unsafe` 生成一个 `func (p *YourProto) UnmarshalVTUnsafe(data []byte)`,其行为类似于 `UnmarshalVT`,不同之处在于它会将数据切片不安全地转换为 `bytes` 和 `string` 字段,而不是将它们复制到新分配的数组中,从而减少了分配操作。**在消息的生命周期内,从网络接收的数据必须保持未被触碰的状态。**否则,消息的 `bytes` 和 `string` 字段可能会损坏。 - `clone`:生成以下 helper 方法 - `func (p *YourProto) CloneVT() *YourProto`:此函数的行为类似于在消息上调用 `proto.Clone(p)`,不同之处在于 cloning 是由静态生成的代码执行的,不使用 reflection。如果接收者 `p` 为 `nil`,则返回类型化的 `nil`。 - `func (p *YourProto) CloneMessageVT() any`:此函数的行为类似于上面的 `p.CloneVT()`,但提供统一的签名,以便即使在编译时不知道类型,也可以通过类型断言进行访问。这允许实现没有 reflection 的通用 `func CloneMessageVT() any`。如果接收者 `p` 为 `nil`,则会在 `any` 接口内部返回该消息类型的类型化 `nil` 指针。 - `json`:生成以下 helper 方法 - `func (p *YourProto) UnmarshalJSON(data []byte) error` 的行为类似于在消息上调用 `protojson.Unmarshal(data, p)`,不同之处在于 unmarshalling 是由静态生成的代码执行的,不使用 reflection 并尽可能少地分配内存。如果接收者 `p` **未**完全归零,则 unmarshal 调用实际上会表现得像 `proto.Merge(data, p)`。为了确保正确的 `Unmarshal` 语义,请确保在调用 `UnmarshalJSON` 之前已对消息调用过 `proto.Reset`,或者您的消息是新分配的。 - `func (p *YourProto) UnmarshalJSONValue(val *fastjson.Value) error` 用于 unmarshal 一个 `*fastjson.Value`。 - `func (p *YourProto) MarshalJSON() ([]byte, error)` 的行为类似于在消息上调用 `protojson.Marshal(p)`,不同之处在于 marshalling 是由静态生成的代码执行的,不使用 reflection 并尽可能少地分配内存。 - 在 message 或 enum 之前添加 `//protobuf-go-lite:disable-json` 注释将禁用 json marshaler / unmarshaler。 - `text`:生成 `MarshalProtoText() string` 和 `String() string` 方法,这些方法使用静态生成的代码发出 protobuf text-format 风格的输出,无需 reflection。在 message 之前添加 `//protobuf-go-lite:disable-text` 注释会禁用该消息的 text 生成。 ## 许可证 BSD-3
标签:EVTX分析, Go, Protobuf, Ruby工具, SOC Prime, 代码生成, 开发工具, 日志审计, 渗透测试工具