菜单

Rust 实现

相关源文件

Protocol Buffers 的 Rust 实现提供了惯用的 Rust 绑定,使开发人员能够在 Rust 项目中使用 Protocol Buffers。本文档涵盖了 Rust Protocol Buffers 实现的架构、设计原则、代码生成和运行时组件。

概述

Protocol Buffers 的 Rust 实现包含两个主要部分:

  1. 代码生成器:Protocol Compiler (protoc) 的 Rust 代码生成器。
  2. 运行时库:支持生成代码的 Rust 运行时。

Rust 实现支持两种不同的内核(底层实现):

  • C++ 内核:使用 C++ Protocol Buffers 实现。
  • upb 内核 (µprotobuf):使用 upb C 实现。

这两种内核向用户提供相同的 API,但具有不同的内部实现和性能特征。

来源:rust/BUILD31-43 rust/BUILD80-173 src/google/protobuf/compiler/rust/generator.cc136-271

架构

Rust 实现的中心是一个类型系统,它允许高效且安全地与 Protocol Buffers 进行交互。该架构遵循几个关键的设计原则:

  1. 内核无关性:大部分代码库是内核无关的,内核特定的代码已隔离。
  2. Rust 惯用性:提供类似 Rust 的体验,同时保持效率。
  3. 零成本抽象:与在 C++ 中使用 Protocol Buffers 相比,避免了不必要的开销。

内核

该实现支持两种内核:

内核描述Rust 目标
C++通过 FFI 使用 C++ Protocol Buffers 实现。protobuf_cpp
upb (µprotobuf)通过 FFI 使用 upb C 实现。protobuf_upb

内核选择由 rust_proto_library_kernel 构建标志控制,默认为 "cpp"。

来源:rust/BUILD31-43 rust/BUILD246-261 rust/defs.bzl23-63

核心组件

Rust 实现的核心组件包括:

  1. 运行时库:为生成的代码提供运行时支持。
  2. 代理系统:用于处理 Protocol Buffer 值的核心抽象。
  3. 代码生成器:从 .proto 文件生成 Rust 代码。
  4. 序列化/反序列化:处理线格式编码/解码。
  5. 内存管理:处理内存分配和生命周期管理。

来源:rust/shared.rs1-113 rust/cpp.rs1-107 rust/upb.rs8-136 src/google/protobuf/compiler/rust/generator.cc136-271

代理系统

Rust 实现的一个关键架构特性是其代理系统,它提供了一种安全有效地处理 Protocol Buffer 值的方法。

代理类型

代理系统围绕“代理”类型这一概念构建。代理类型允许间接访问 Protocol Buffer 值,类似于 Rust 的引用,但具有 Protocol Buffer 操作所需的额外运行时信息。

来源:rust/proxied.rs8-47 rust/proxied.rs50-75 rust/proxied.rs80-93

视图和突变

代理系统提供两种主要方式与 Protocol Buffer 值进行交互:

  1. 视图(View<T>:提供对 Protocol Buffer 值的只读访问。
  2. 突变(Mut<T>:提供对 Protocol Buffer 值的读写访问。

这种方法允许高效且安全地访问 Protocol Buffer 值,同时保持与两种内核的兼容性。

来源:src/google/protobuf/compiler/rust/message.cc810-1113 rust/proxied.rs95-204 src/google/protobuf/compiler/rust/message.cc815-1106

消息类型

消息结构

每个 Protocol Buffer 消息由三个 Rust 类型表示:

  1. 所有类型Message):消息的所有者类型。
  2. 视图类型MessageView):消息的借用的只读视图。
  3. Mut 类型MessageMut):消息的借用的可变视图。

来源:src/google/protobuf/compiler/rust/message.cc30-207 src/google/protobuf/compiler/rust/message.cc299-374

消息操作

消息支持以下关键操作:

操作描述
创建创建具有默认值的新消息。
序列化将消息转换为线格式字节。
反序列化将线格式字节解析到消息中。
Clear清除消息中的所有字段。
复制/克隆创建消息的深层副本。
合并将字段从一个消息合并到另一个消息。
字段访问获取和设置字段值。

来源:src/google/protobuf/compiler/rust/message.cc30-207 src/google/protobuf/compiler/rust/message.cc30-207

字段类型

标量字段

标量字段(整数、浮点数、布尔值)直接由其 Rust 等效项表示。

来源:rust/primitive.rs10-32

字符串和字节

字符串和字节由 ProtoStringProtoBytes 类型表示,它们是 Protocol Buffers 的所有者字符串和字节数组类型。

来源:rust/string.rs31-82 rust/string.rs101-217

重复字段

重复字段由 Repeated<T> 类型表示,它提供了一个类型为 T 的值的集合。

来源:rust/repeated.rs23-113 rust/repeated.rs114-247 rust/repeated.rs307-356

Map

Map 由 Map<K, V> 类型表示,它提供了一个从类型为 K 的键到类型为 V 的值的映射。

来源: rust/map.rs16-57 rust/map.rs63-77 rust/map.rs86-108

枚举

枚举由封装整数值的自定义 Rust 类型表示。

来源: src/google/protobuf/compiler/rust/enum.cc138-346

代码生成

生成器架构

Rust 代码生成器集成到 Protocol Compiler (protoc) 中。它处理 .proto 文件并为消息、枚举和服务生成 Rust 代码。

来源: src/google/protobuf/compiler/rust/generator.cc136-271

构建系统集成

Rust 实现通过 rust_proto_library 规则与 Bazel 构建系统集成,该规则根据构建配置选择合适的内核。

来源: rust/defs.bzl23-63 rust/defs.bzl144-163

运行时实现

内存管理

两种内核之间的内存管理方式不同

  1. C++ 内核:使用 RAII 进行 C++ 内存管理
  2. upb 内核:使用基于 arena 的内存管理

这种差异通过通用 API 被抽象化了,但对于理解性能特征很重要。

来源: rust/cpp.rs346-396 rust/upb.rs76-140

序列化/反序列化

两种内核都提供序列化和反序列化功能,但实现不同

来源: src/google/protobuf/compiler/rust/message.cc59-91 src/google/protobuf/compiler/rust/message.cc114-157

API 使用

基本消息操作

来源: rust/test/shared/serialization_test.rs16-52

处理重复字段

来源: rust/test/shared/accessors_repeated_test.rs13-53

处理 Map

来源: rust/test/shared/accessors_map_test.rs16-41

结论

Protocol Buffers 的 Rust 实现为 Rust 项目提供了安全、高效且符合惯用的 Protocol Buffers 使用方式。它支持两种不同的内核(C++ 和 upb),API 相同,使开发人员可以选择最适合其需求的实现。

该实现利用 Rust 的类型系统来提供安全高效的 API,同时保持与现有 Protocol Buffers 生态系统的兼容性。