serde你在干什么 - 环境准备

serde 源码解析 | 准备篇

最近做一个练习项目,要求利用serde,为Redis Simple Protocol写一个序列化、反序列化工具。

理解Redis Simple Protocol倒是不难,可是这个serde,人都给我看蒙了。尤其在看反序列化过程的时候,心态一度爆炸,写下了这样的感想:

太复杂了

太TM复杂了

想吼想哭想闹

想吃垃圾食品

想一瞬间变成天上乌漆嘛黑的冰雹云

轰他娘的山本联队

最后总算硬着头皮写出了一版。记录下这个过程。

要了解serde,光看文档难度还是太高了,像是读词典小说,文学上想想《哈扎尔辞典》,游戏上想想宫崎英高养起来的大批”魂学家”,就是那种支离破碎的感觉。所以还原为时间顺序,一步步理解起来更容易。官网给出了一个简化的json样例,叫serde-example,我的学习就是基于这份代码。按照下面的步骤,不妨先把环境搭建起来。

build

将仓库克隆到本地,修改cargo.toml、ser.rs、de.rs三个文件,支持edition-2018,也随意升级一下serde版本,没什么关系。这个时候cargo check应该可以通过了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// cargo.toml
[package]
name = "serde-example"
edition = "2018" // 新增edition,使用2018的标准
version = "0.1.0"
authors = ["David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "An example Serializer and Deserializer data format for Serde"
repository = "https://github.com/serde-rs/example-format"
documentation = "https://serde.rs/data-format.html"
keywords = ["serde"]
categories = ["encoding"]
publish = false

[dependencies]
serde = { version = "1.0.103", features = ["derive"] } // 修改

1
2
// ser.rs & de.rs
use crate::error::{Error, Result}; // 增加crate

run

添加src/bin/inspect.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/bin/inspect.rs
use serde::{Deserialize, Serialize};
use serde_example::{from_str, to_string};

#[derive(Debug, Serialize, Deserialize)]
enum Command {
Set { key: String, value: String },
Get { key: String },
Rm(String),
Quit,
}

fn main() {
let cmd = Command::Set {
key: "A".to_owned(),
value: "42".to_owned(),
};
let ser_cmd = to_string(&cmd).unwrap();
let de_cmd: Command = from_str(&ser_cmd).unwrap();
println!(
"origin: {:?}\nserialized: {}\ndeserialized: {:?}",
cmd, ser_cmd, de_cmd
);
}

运行cargo run --bin inspect就会输出

1
2
3
origin: Set { key: "A", value: "42" }
serialized: {"Set":{"key":"A","value":"42"}}
deserialized: Set { key: "A", value: "42" }

expand derive

还有一份关键的代码,藏在#[derive(Debug, Serialize, Deserialize)]里,这条语句自动生成一些(很多!)代码,为Command实现关键的两个序列化trait。

这要借助cargo-expand工具,如果没有先装一下,一般下面两个命令搞定

1
2
$ rustup toolchain install nightly  # 如果只使用过stable版本,需要先装nightly
$ cargo install cargo-expand

运行cargo expand --bin inspect,终端输出生成代码。

其中一段类似下面这样,实现的是Serialize,把它复制到derive_ser.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const _IMPL_SERIALIZE_FOR_Command: () = {
#[allow(unknown_lints)]
#[allow(rust_2018_idioms)]
extern crate serde as _serde;
#[automatically_derived]
impl _serde::Serialize for Command {
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where
__S: _serde::Serializer,
{
match *self {
Command::Set { ref key, ref value } => {
...
_serde::ser::SerializeStructVariant::end(__serde_state)
}
Command::Get { ref key } => {
...
_serde::ser::SerializeStructVariant::end(__serde_state)
}
Command::Rm(ref __field0) => _serde::Serializer::serialize_newtype_variant(
__serializer,
"Command",
2u32,
"Rm",
__field0,
),
Command::Quit => _serde::Serializer::serialize_unit_variant(
__serializer,
"Command",
3u32,
"Quit",
),
}
}
}
};

另一段结构像这样,实现的是Deserialize,把它复制到derive_de.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
const _IMPL_DESERIALIZE_FOR_Command: () = {
#[allow(unknown_lints)]
#[allow(rust_2018_idioms)]
extern crate serde as _serde;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for Command {
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where
__D: _serde::Deserializer<'de>,
{
#[allow(non_camel_case_types)]
enum __Field { __field0, __field1, __field2, __field3, }
struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(&self, __formatter: &mut _serde::export::Formatter) ... {}
fn visit_u64<__E>(self, __value: u64) ... {}
fn visit_str<__E>(self, __value: &str) ... {}
fn visit_bytes<__E>(self, __value: &[u8]) ... {}
}
}
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D) ... {}
}

struct __Visitor<'de> {
marker: _serde::export::PhantomData<Command>,
lifetime: _serde::export::PhantomData<&'de ()>,
}
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = Command;
fn expecting(&self, __formatter: &mut _serde::export::Formatter)
fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result<Self::Value, __A::Error>
where
__A: _serde::de::EnumAccess<'de>,
{
match match _serde::de::EnumAccess::variant(__data) {
_serde::export::Ok(__val) => __val,
_serde::export::Err(__err) => {
return _serde::export::Err(__err);
}
} {
(__Field::__field0, __variant) => {...}
(__Field::__field1, __variant) => {...}
(__Field::__field2, __variant) => {...}
(__Field::__field3, __variant) => {...}
}
}
}

const VARIANTS: &'static [&'static str] = &["Set", "Get", "Rm", "Quit"];
_serde::Deserializer::deserialize_enum(
__deserializer,
"Command",
VARIANTS,
__Visitor {
marker: _serde::export::PhantomData::<Command>,
lifetime: _serde::export::PhantomData,
},
)
}
}
};

好了,准备工作就这么多。开始受苦吧。