PackStream
PackStream 是一种用于交换丰富类型数据的二进制表示格式。它为 Bolt 消息协议提供了一个语法层。
版本 1
PackStream 是一种通用数据序列化格式,最初受(但与)MessagePack启发。
该格式提供了一个与 Cypher 支持的类型完全兼容的类型系统,有关更多信息,请参阅Cypher 手册→值和类型。
PackStream 提供了许多核心数据类型,其中许多都支持多种二进制表示形式,以及灵活的扩展机制。
下表描述了核心数据类型。
数据类型 | 描述 |
---|---|
缺少或空值 |
|
真 或 假 |
|
带符号的 64 位整数 |
|
64 位浮点数 |
|
字节数组 |
|
Unicode 文本,UTF-8 |
|
值的排序集合 |
|
键值对的集合(不保证顺序) |
|
具有类型签名的复合值 |
不包括无符号整数或 32 位浮点数。这是为了允许在客户端语言之间具有更广泛的兼容性而做出的刻意设计决策。 |
一般表示
每个序列化后的 PackStream 值都以一个标记字节开头。
标记包含数据类型信息以及需要该信息类型的直接或间接大小信息。大小信息是如何编码的因标记类型而异。
某些值,例如布尔值 true,可以在单个标记字节中编码。许多小整数(具体来说,介于 -16 和 +127 之间(包括 -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 |
|
一些标记字节可用于承载小整数的值及其类型。这些标记可以通过零高位(对于正值)或仅包含 1 的高位 nibble(对于负值)来识别。具体来说,值 00
到 7F
(包括 00
和 7F
)可以与具有相同值的正整数直接转换。同样,值 F0
到 FF
(包括 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
选择的位)表示数字的尾数(有时称为尾数)。
十进制值 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 个字节的编码文本(包括空字符串),标记字节应包含高位 nibble 8
(二进制 1000)以及包含大小的低位 nibble。编码数据紧随标记符之后。对于包含 16 个字节或更多字节的编码文本,应根据规模使用标记符 D0
、D1
或 D2
。此标记符后跟大小和 UTF-8 编码数据。
注意:虽然 D3
后面的无符号 32 位整数可以容纳更大的数字,但字符串的最大字节大小限制为 2,147,483,647(有符号 32 位整数的最大值)。
值 | 编码 |
---|---|
|
|
|
|
|
|
|
|
列表 (List)
列表是值的异构序列,因此允许在同一列表中混合使用多种类型。列表的大小表示该列表中项目的数量,而不是打包的总字节大小。
标记符
标记 | 大小(项目数) | 最大尺寸 |
---|---|---|
|
标记符的低位 nibble |
0 个项目 |
|
标记符的低位 nibble |
1 个项目 |
|
标记符的低位 nibble |
2 个项目 |
|
标记符的低位 nibble |
3 个项目 |
|
标记符的低位 nibble |
4 个项目 |
|
标记符的低位 nibble |
5 个项目 |
|
标记符的低位 nibble |
6 个项目 |
|
标记符的低位 nibble |
7 个项目 |
|
标记符的低位 nibble |
8 个项目 |
|
标记符的低位 nibble |
9 个项目 |
|
标记符的低位 nibble |
10 个项目 |
|
标记符的低位 nibble |
11 个项目 |
|
标记符的低位 nibble |
12 个项目 |
|
标记符的低位 nibble |
13 个项目 |
|
标记符的低位 nibble |
14 个项目 |
|
标记符的低位 nibble |
15 个项目 |
|
8 位大端无符号整数 |
255 个项目 |
|
16 位大端无符号整数 |
65,535 个项目 |
|
32 位大端无符号整数 |
2,147,483,647 个项目 |
对于包含少于 16 个项目的列表(包括空列表),标记字节应包含高位 nibble 9
(二进制 1001)以及包含大小的低位 nibble。列表中的项目然后按顺序序列化,紧随标记符之后。
对于包含 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)
字典
是一个包含键值对的列表。
-
键必须是
字符串 (String)
。 -
可以包含同一键的多个实例。
-
允许混合使用多种类型。
字典
的大小表示该字典中键值对的数量,而不是打包的总字节大小。
标记符
标记 | 大小(键值对数) | 最大尺寸 |
---|---|---|
|
包含在标记符的低位 nibble 中 |
0 |
|
包含在标记符的低位 nibble 中 |
1 |
|
包含在标记符的低位 nibble 中 |
2 |
|
包含在标记符的低位 nibble 中 |
3 |
|
包含在标记符的低位 nibble 中 |
4 |
|
包含在标记符的低位 nibble 中 |
5 |
|
包含在标记符的低位 nibble 中 |
6 |
|
包含在标记符的低位 nibble 中 |
7 |
|
包含在标记符的低位 nibble 中 |
8 |
|
包含在标记符的低位 nibble 中 |
9 |
|
包含在标记符的低位 nibble 中 |
10 |
|
包含在标记符的低位 nibble 中 |
11 |
|
包含在标记符的低位 nibble 中 |
12 |
|
包含在标记符的低位 nibble 中 |
13 |
|
包含在标记符的低位 nibble 中 |
14 |
|
包含在标记符的低位 nibble 中 |
15 |
|
8 位大端无符号整数 |
255 个条目 |
|
16 位大端无符号整数 |
65,535 个条目 |
|
32 位大端无符号整数 |
2,147,483,647 个条目 |
对于包含少于 16 个键值对的字典(包括空字典),标记字节应包含高位 nibble A
(二进制 1010
)以及包含大小的低位 nibble。
字典中的条目然后按 [键, 值, 键, 值]
顺序序列化,紧随标记符之后。
键始终为 |
对于包含 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 个字段的序列,每个字段都是一个单独的值。结构体的大小以字段数衡量,而不是总字节大小。此计数不包括标签。
标记符
标记 | 大小(字段数) | 最大尺寸 |
---|---|---|
|
包含在标记符的低位 nibble 中 |
0 个字段 |
|
包含在标记符的低位 nibble 中 |
1 个字段 |
|
包含在标记符的低位 nibble 中 |
2 个字段 |
|
包含在标记符的低位 nibble 中 |
3 个字段 |
|
包含在标记符的低位 nibble 中 |
4 个字段 |
|
包含在标记符的低位 nibble 中 |
5 个字段 |
|
包含在标记符的低位 nibble 中 |
6 个字段 |
|
包含在标记符的低位 nibble 中 |
7 个字段 |
|
包含在标记符的低位 nibble 中 |
8 个字段 |
|
包含在标记符的低位 nibble 中 |
9 个字段 |
|
包含在标记符的低位 nibble 中 |
10 个字段 |
|
包含在标记符的低位 nibble 中 |
11 个字段 |
|
包含在标记符的低位 nibble 中 |
12 个字段 |
|
包含在标记符的低位 nibble 中 |
13 个字段 |
|
包含在标记符的低位 nibble 中 |
14 个字段 |
|
包含在标记符的低位 nibble 中 |
15 个字段 |
对于包含少于 16 个字段的结构体,标记字节应包含高位 nibble B
(二进制 1011
)以及包含大小的低位 nibble。标记符后紧跟**标签字节**和字段值,顺序排列。**标签字节**用于标识结构体的类型或类别,并且可以保存 0 到 +127 之间的任何值。
PackStream 本身不定义不同结构体的语义。相反,请参阅结构体语义以了解相关 Bolt 版本。