如何使用 serde 反序列化 Prost 枚举?

kal*_*zen 9 rust serde prost

我正在使用 [prost] 从 protobuf 生成结构。其中一个结构非常简单:

enum Direction {
  up = 0;
  down = 1;
  sideways = 2;
}
Run Code Online (Sandbox Code Playgroud)

这会生成如下代码:

enum Direction {
  up = 0;
  down = 1;
  sideways = 2;
}
Run Code Online (Sandbox Code Playgroud)

我必须将大量 JSON 文件解析为这些消息。这些有数万行长,但是当这个字段出现时,它看起来像:

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
#[derive(serde_derive::Deserialize)]
pub enum Direction {
    Up = 0,
    Down = 1,
    Sideways = 2,
}
Run Code Online (Sandbox Code Playgroud)

所以,简而言之,它的反序列化格式是字符串,序列化后是i32

如果我只是运行它,并尝试解析 JSON,我会得到:

thread 'tests::parse_json' panicked at 'Failed to parse: "data/my_data.json": Error("invalid type: string \"up\", expected i32", line: 132, column: 23)
Run Code Online (Sandbox Code Playgroud)

当然,这是有道理的 - 没有反射来指导从"up"到 的反序列化0

问题:如何设置serde将这些字符串解析为匹配的整数值?我已经彻底阅读了 serde 文档,看来我可能需要为此编写一个自定义反序列化器,尽管这看起来有点矫枉过正。

我尝试了一些不同的 serde 属性,例如:

{ "direction": "up" }
Run Code Online (Sandbox Code Playgroud)

有了这个功能:

thread 'tests::parse_json' panicked at 'Failed to parse: "data/my_data.json": Error("invalid type: string \"up\", expected i32", line: 132, column: 23)
Run Code Online (Sandbox Code Playgroud)

但是,尽管 serde文档告诉我什么,该方法甚至没有被调用(但编译成功)。

我还尝试了字段上的字段属性,它是Direction

#[serde(deserialize_with = \"super::super::common::Direction::from\")]
Run Code Online (Sandbox Code Playgroud)

但这当然需要一个不同的签名,而不仅仅是&strthe trait std::convert::From<__D> is not implemented for common::Direction

我只需要编写一个自定义解串器吗?似乎是一个足够常见的用例,应该有一个可以使用的模式。

注意:这是与 解决的问题相反的问题serde_repr。我没有找到让它在这里发挥作用的方法。

kal*_*zen 5

感谢此答案中的指南,我实现了自己的反序列化器。可能有一种更简单或更惯用的方法,所以如果您知道,请分享!

Serde 属性,在字段而不是 Enum 上设置:

config.field_attribute(
    "direction",
    "#[serde(deserialize_with = \"super::super::common::Direction::from_str\")]"
);
Run Code Online (Sandbox Code Playgroud)

解串器:

config.field_attribute(
    "direction",
    "#[serde(deserialize_with = \"super::super::common::Direction::from_str\")]"
);
Run Code Online (Sandbox Code Playgroud)