#buffer #protocols #error #parser #decoding #serialization #message-parser

protofish

Protofish是一个专注于解码任意协议缓冲区消息并具有错误恢复功能的解码器。

14个不稳定版本 (4个破坏性更新)

0.5.2 2022年1月27日
0.5.1 2021年12月6日
0.4.0 2021年6月6日
0.3.1 2021年2月17日
0.1.1 2020年5月22日

#2097编码

Download history 352/week @ 2024-04-20 394/week @ 2024-04-27 558/week @ 2024-05-04 614/week @ 2024-05-11 583/week @ 2024-05-18 606/week @ 2024-05-25 704/week @ 2024-06-01 644/week @ 2024-06-08 428/week @ 2024-06-15 357/week @ 2024-06-22 262/week @ 2024-06-29 385/week @ 2024-07-06 350/week @ 2024-07-13 359/week @ 2024-07-20 483/week @ 2024-07-27 407/week @ 2024-08-03

每月下载量 1,647次
用于 6 crates

MIT/Apache

115KB
3K SLoC

::<proto>

proto文件解析器和任意协议缓冲区消息解码器

crates.io Docs

Protofish是一个专注于解码任意协议缓冲区消息并具有错误恢复功能的解码器。其主要用途是解码基于用户在运行时提供的.proto文件在proxide中的gRPC消息。

use protofish::{Context, Value, UnknownValue};
use bytes::Bytes;

let context = Context::parse(&[r#"
  syntax = "proto3";
  package Proto;

  message Request { string kind = 1; }
  message Response { int32 distance = 1; }
  service Fish {
    rpc Swim( Request ) returns ( Response );
  }
"#]).unwrap();

let service = context.get_service("Proto.Fish").unwrap();
let rpc = service.rpc_by_name("Swim").unwrap();

let input = rpc.input.message.decode(b"\x0a\x05Perch", &context);
assert_eq!(input.fields[0].number, 1);
assert_eq!(input.fields[0].value, Value::String(String::from("Perch")));

let output = rpc.output.message.decode(b"\x08\xa9\x46", &context);
assert_eq!(output.fields[0].number, 1);
assert_eq!(output.fields[0].value, Value::Int32(9001));

目标

  • 支持协议缓冲区版本3。
  • 独立的proto文件解析器,不依赖于protoc
  • 能够解码部分和无效的协议缓冲区消息。

非目标

  • 为了极致的性能而极端快速。
    • 速度虽然重要,但正确性、错误恢复和可维护性具有更高的优先级。
    • 尤其适用于解析proto文件。
  • 支持协议缓冲区版本2。
    • 对于解码gRPC不是必需的。如果不影响可维护性,不反对包括支持。
  • 代码生成
    • 已经有几个其他crate做这件事。
  • 验证proto文件
    • Protofish关注解析所有有效的proto文件。拒绝无效文件对于基于有效文件解码消息目前没有价值。验证不在范围之外,但不是当前优先级。

动机

在Rust生态系统中有几个处理协议缓冲区消息的crate。其中大部分关注编译时代码生成,用于生成运行时序列化的消息类型。其中大部分crate也依赖于protoc进行实际的proto文件解析。

quick-protobuf项目有一个独立的proto文件解析器:pb-rs。不幸的是,该解析器缺少对完整proto文件语法的支持(至少在撰写此README时,在rpc定义中的流请求和响应不被支持)。

Protofish使用了基于已发布的PEG(语法扩展标记),它遵循Protocol Buffers版本3语言规范。虽然该规范略有偏差,但根据官方提供的EBNF语法编写的语法规则,为构建一个全面的解析器提供了一种简单的方法。

一个手工制作的基于Nom的解析器可能更快,但在读取proto文件的情况下,大多数情况下并不需要高性能。例如,Proxide在程序启动时只做一次这样的操作。

缺少的功能

处理import语句..或者不处理

Protofish 忽略 proto文件中的import语句。构建一个全面的解码上下文需要处理包含所需类型的所有文件。这意味着所有import语句所引用的文件都需要传递给protofish进行解析。因此,提前解析import语句的需求很小。

处理自定义选项

extends语法不是发布版Protocol Buffers版本3语言规范的一部分(这也说明了该规范有多不正确)。因此,使用自定义选项的extends语法不受解析器的支持。

由于protofish根本不验证选项,因此未来可能会初步支持跳过extends定义。

依赖项

~2.3–3MB
~61K SLoC