PackStream
PackStream 是一种用于交换富类型数据的二进制表示格式。它为 Bolt 消息协议提供了一个语法层。
版本 1
PackStream 是一种通用数据序列化格式,最初受到 MessagePack 的启发(但不兼容)。
该格式提供了一个与 Cypher 支持的类型完全兼容的类型系统,更多信息请参阅 Cypher 手册 → 值和类型。
PackStream 提供了一系列核心数据类型,其中许多类型支持多种二进制表示,并具备灵活的扩展机制。
核心数据类型如下表所示。
| 数据类型 | 描述 |
|---|---|
缺失或空值 |
|
true 或 false |
|
带符号 64 位整数 |
|
64 位浮点数 |
|
字节数组 |
|
Unicode 文本,UTF-8 |
|
值的有序集合 |
|
键值对集合(不保证顺序) |
|
带类型签名的复合值 |
|
不包含无符号整数和 32 位浮点数。这是一个深思熟虑的设计决策,旨在允许跨客户端语言实现更广泛的兼容性。 |
通用表示
每个序列化的 PackStream 值都以一个标记字节 (marker byte) 开头。
该标记包含数据类型信息,以及对于需要该信息的类型,包含直接或间接的大小信息。大小信息的编码方式因标记类型而异。
某些值(例如布尔值 true)可以在单个标记字节内编码。许多小整数(具体为 -16 到 +127 之间)也编码在单个字节内。
部分标记字节被保留用于格式本身的未来扩展。不应使用这些字节,在传入的数据流中遇到它们应视为错误。
数据类型
Integer
标记, TINY_INT
| 标记 | 十进制数 |
|---|---|
|
-16 |
|
-15 |
|
-14 |
|
-13 |
|
-12 |
|
-11 |
|
-10 |
|
-9 |
|
-8 |
|
-7 |
|
-6 |
|
-5 |
|
-4 |
|
-3 |
|
-2 |
|
-1 |
|
0 |
|
1 |
|
2 |
… |
… |
… |
… |
… |
… |
|
126 |
|
127 |
标记, INT_8: C8
标记, INT_16: C9
标记, INT_32: CA
标记, INT_64: CB
根据数值大小,整数值占用 1、2、3、5 或 9 个字节。可用的表示形式为
| 表示 | 大小 (字节) | 描述 |
|---|---|---|
|
1 |
仅标记字节 |
|
2 |
标记字节 |
|
3 |
标记字节 |
|
5 |
标记字节 |
|
9 |
标记字节 |
下文展示了可用的编码,每个编码都显示了十进制值 42 的有效表示
| 表示 | 大小 (字节) | 描述 |
|---|---|---|
|
1 |
|
|
2 |
|
|
3 |
|
|
5 |
|
|
9 |
|
某些标记字节既可用于表示小整数的值,也可用于表示其类型。这些标记可以通过高位比特为 0(对于正值)或高位半字节仅包含 1(对于负值)来识别。具体来说,00 到 7F(含)之间的值可以直接转换为相同值的正整数。同样,F0 到 FF(含)之间的值可以同样转换为 -16 到 -1 之间的负数。
|
虽然可以使用更宽的格式来编码小数,但通常建议使用尽可能紧凑的表示形式。 |
下表显示了带符号 64 位范围内每个可能整数的最佳表示形式
| 范围最小值 | 范围最大值 | 最佳表示 |
|---|---|---|
-9 223 372 036 854 775 808 |
-2 147 483 649 |
|
-2 147 483 648 |
-32 769 |
|
-32 768 |
-129 |
|
-128 |
-17 |
|
-16 |
+127 |
|
+128 |
+32 767 |
|
+32 768 |
+2 147 483 647 |
|
+2 147 483 648 |
+9 223 372 036 854 775 807 |
|
值 -9223372036854775808(最小值)可以表示为
CB 80 00 00 00 00 00 00 00
值 9223372036854775807(最大值)可以表示为
CB 7F FF FF FF FF FF FF FF
Float
标记: C1
浮点数是双精度浮点值,通常用于表示分数和小数。它们编码为单个 C1 标记字节,后跟 8 个字节,这些字节根据 IEEE 754 浮点数“双精度格式”位布局以大端序排列。
-
第 63 位(由掩码
0x8000000000000000选择的位)代表数字的符号。 -
第 62-52 位(由掩码
0x7ff0000000000000选择的位)代表指数。 -
第 51-0 位(由掩码
0x000fffffffffffff选择的位)代表数字的尾数(有时称为 mantissa)。
十进制值 1.23 可以表示为
C1 3F F3 AE 14 7A E1 47 AE
Bytes
字节是字节值的数组。它们用于传输原始二进制数据,大小表示包含的字节数。与其他值不同,对于包含少于 16 个字节的字节数组,没有单独的编码。
| 标记 | 大小 | 最大大小 |
|---|---|---|
|
8 位大端序无符号整数 |
255 字节 |
|
16 位大端序无符号整数 |
65 535 字节 |
|
32 位大端序无符号整数 |
2 147 483 647 字节 |
应根据规模使用标记 CC、CD 或 CE 之一。此标记后跟大小和字节本身。
注意:虽然 CE 后面的 32 位无符号整数可以容纳更大的数字,但字节数组的最大大小限制为 2 147 483 647(带符号 32 位整数的最大值)。
空字节数组 b[]
CC 00
包含三个值 1、2 和 3 的字节数组;b[1, 2, 3]
CC 03 01 02 03
String
标记
对于较短字符串
| 标记 | 大小 (字节) |
|---|---|
|
0 |
|
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
对于较长字符串
| 标记 | 大小 | 最大字节数 |
|---|---|---|
|
8 位大端序无符号整数 |
255 字节 |
|
16 位大端序无符号整数 |
65 535 字节 |
|
32 位大端序无符号整数 |
2 147 483 647 字节 |
文本数据表示为 UTF-8 编码的字节。
|
字符串表示中用到的大小是 UTF-8 编码数据的字节数,而不是原始文本的字符数。 |
对于包含少于 16 个字节的编码文本(包括空字符串),标记字节应包含高位半字节 8(二进制 1000),后跟包含大小的低位半字节。编码数据紧随标记之后。对于包含 16 个或更多字节的编码文本,应根据规模使用标记 D0、D1 或 D2。此标记后跟大小和 UTF-8 编码数据。
注意:虽然 D3 后面的 32 位无符号整数可以容纳更大的数字,但字符串的最大字节大小限制为 2 147 483 647(带符号 32 位整数的最大值)。
| 值 | 编码 |
|---|---|
|
|
|
|
|
|
|
|
List
列表是值的异构序列,因此允许在同一个列表中混合使用不同类型。列表的大小表示该列表中的项目数量,而不是总的打包字节大小。
标记
| 标记 | 大小 (项目) | 最大大小 |
|---|---|---|
|
标记的低位半字节 |
0 个项目 |
|
标记的低位半字节 |
1 个项目 |
|
标记的低位半字节 |
2 个项目 |
|
标记的低位半字节 |
3 个项目 |
|
标记的低位半字节 |
4 个项目 |
|
标记的低位半字节 |
5 个项目 |
|
标记的低位半字节 |
6 个项目 |
|
标记的低位半字节 |
7 个项目 |
|
标记的低位半字节 |
8 个项目 |
|
标记的低位半字节 |
9 个项目 |
|
标记的低位半字节 |
10 个项目 |
|
标记的低位半字节 |
11 个项目 |
|
标记的低位半字节 |
12 个项目 |
|
标记的低位半字节 |
13 个项目 |
|
标记的低位半字节 |
14 个项目 |
|
标记的低位半字节 |
15 个项目 |
|
8 位大端序无符号整数 |
255 个项目 |
|
16 位大端序无符号整数 |
65 535 个项目 |
|
32 位大端序无符号整数 |
2 147 483 647 个项目 |
对于包含少于 16 个项目的列表(包括空列表),标记字节应包含高位半字节 9(二进制 1001),后跟包含大小的低位半字节。列表中的项目随后按顺序序列化在标记之后。
对于包含 16 个或更多项目的列表,应根据规模使用标记 D4、D5 或 D6。此标记后跟大小和按顺序序列化的列表项目。
注意:虽然 D6 后面的 32 位无符号整数可以容纳更大的数字,但列表的最大大小限制为 2 147 483 647(带符号 32 位整数的最大值)。
[]
90
[Integer(1), Integer(2), Integer(3)]
93 01 02 03
[
Integer(1),
Float(2.0),
String("three")
]
93 01 C1 40 00 00 00 00 00 00 00 85 74 68 72 65 65
[
Integer(1),
Integer(2),
...
Integer(40)
]
D4 28 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28
Dictionary
Dictionary 是包含键值对条目的列表
-
键必须是
String -
可以包含同一个键的多个实例
-
允许混合类型
Dictionary 的大小表示该字典中的键值对条目数量,而不是总的打包字节大小。
标记
| 标记 | 大小 (键值对条目) | 最大大小 |
|---|---|---|
|
包含在标记的低位半字节中 |
0 |
|
包含在标记的低位半字节中 |
1 |
|
包含在标记的低位半字节中 |
2 |
|
包含在标记的低位半字节中 |
3 |
|
包含在标记的低位半字节中 |
4 |
|
包含在标记的低位半字节中 |
5 |
|
包含在标记的低位半字节中 |
6 |
|
包含在标记的低位半字节中 |
7 |
|
包含在标记的低位半字节中 |
8 |
|
包含在标记的低位半字节中 |
9 |
|
包含在标记的低位半字节中 |
10 |
|
包含在标记的低位半字节中 |
11 |
|
包含在标记的低位半字节中 |
12 |
|
包含在标记的低位半字节中 |
13 |
|
包含在标记的低位半字节中 |
14 |
|
包含在标记的低位半字节中 |
15 |
|
8 位大端序无符号整数 |
255 条目 |
|
16 位大端序无符号整数 |
65 535 条目 |
|
32 位大端序无符号整数 |
2 147 483 647 条目 |
对于包含少于 16 个键值对条目的字典(包括空字典),标记字节应包含高位半字节 A(二进制 1010),后跟包含大小的低位半字节。
字典中的条目随后按 [key, value, key, value] 的顺序序列化在标记之后。
|
键始终是 |
对于包含 16 个或更多键值对条目的字典,应根据规模使用标记 D8、D9 或 DA。此标记后跟大小和键值对条目。
注意:虽然 DA 后面的 32 位无符号整数可以容纳更大的数字,但字典的最大大小限制为 2 147 483 647(带符号 32 位整数的最大值)。
{}
A0
{"one": "eins"}
A1 83 6F 6E 65 84 65 69 6E 73
{"A": 1, "B": 2 ... "Z": 26}
D8 1A 81 41 01 81 42 02 81 43 03 81 44 04 81 45 05 81 46 06 81 47 07 81 48 08 81 49 09 81 4A 0A 81 4B 0B 81 4C 0C 81 4D 0D 81 4E 0E 81 4F 0F 81 50 10 81 51 11 81 52 12 81 53 13 81 54 14 81 55 15 81 56 16 81 57 17 81 58 18 81 59 19 81 5A 1A
如果在解包时存在同一个键的多个实例,应使用该键最后出现的值。
[("key_1", 1), ("key_2", 2), ("key_1", 3)] -> {"key_1": 3, "key_2": 2}
Structure
结构是一种复合值,由字段和唯一类型代码组成。除标记外,结构编码由一个单字节(标签字节)组成,后跟最多 15 个字段,每个字段是一个独立的值。结构的大小以字段数来衡量,而不是总字节大小。此计数不包含标签。
标记
| 标记 | 大小 (字段) | 最大大小 |
|---|---|---|
|
包含在标记的低位半字节中 |
0 个字段 |
|
包含在标记的低位半字节中 |
1 个字段 |
|
包含在标记的低位半字节中 |
2 个字段 |
|
包含在标记的低位半字节中 |
3 个字段 |
|
包含在标记的低位半字节中 |
4 个字段 |
|
包含在标记的低位半字节中 |
5 个字段 |
|
包含在标记的低位半字节中 |
6 个字段 |
|
包含在标记的低位半字节中 |
7 个字段 |
|
包含在标记的低位半字节中 |
8 个字段 |
|
包含在标记的低位半字节中 |
9 个字段 |
|
包含在标记的低位半字节中 |
10 个字段 |
|
包含在标记的低位半字节中 |
11 个字段 |
|
包含在标记的低位半字节中 |
12 个字段 |
|
包含在标记的低位半字节中 |
13 个字段 |
|
包含在标记的低位半字节中 |
14 个字段 |
|
包含在标记的低位半字节中 |
15 个字段 |
对于包含少于 16 个字段的结构,标记字节应包含高位半字节 B(二进制 1011),后跟包含大小的低位半字节。标记后紧跟标签字节和按该顺序排列的字段值。标签字节用于标识结构的类型或类,并可包含 0 到 +127 之间的任何值。
PackStream 本身不为不同的结构定义语义。请参阅相关 Bolt 版本的 结构语义 (Structure Semantics)。