Binn 规范
June 2, 2023 · View on GitHub
格式
每个值都有 4 个可能的参数存储:
[type][size][count][data]
但大多数是可选的。所有值中只有类型参数是必须的。以下是基本数据类型的参数列表:
布尔值,空值: [type] 整数,浮点数(存储:字节,字,双字,四字): [type][data] 字符串,二进制大对象(BLOB): [type][size][data] 列表,对象,映射: [type][size][count][data]
每个参数可以用多态大小存储:
| 参数 | 大小 |
|---|---|
| [type] | 1 或 2 字节 |
| [size] | 1 或 4 字节 |
| [count] | 1 或 4 字节 |
| [data] | n 字节 |
[类型]
每个值的存储都从数据类型开始。它可以使用 1 或 2 个字节。第一个字节分为以下几部分:
+-------- 存储类型 | +----- 子类型大小 | | +-- 子类型 000 0 0000
存储
最高的 3 位用于存储类型。它包含了数据将使用多少字节的信息。存储类型可以是以下任意一种:
- 无额外字节
- 1 字节
- 字(2 字节,大端)
- 双字(4 字节,大端)
- 四字(8 字节,大端)
- 字符串(UTF-8,空终止)
- 二进制大对象(BLOB)
- 容器
常量如下:
| 存储 | 位 | 十六进制 | 十进制 |
|---|---|---|---|
| NOBYTES | 000 0 0000 | 0x00 | 0 |
| BYTE | 001 0 0000 | 0x20 | 32 |
| WORD | 010 0 0000 | 0x40 | 64 |
| DWORD | 011 0 0000 | 0x60 | 96 |
| QWORD | 100 0 0000 | 0x80 | 128 |
| STRING | 101 0 0000 | 0xA0 | 160 |
| BLOB | 110 0 0000 | 0xC0 | 192 |
| CONTAINER | 111 0 0000 | 0xE0 | 224 |
子类型大小
下一位表示类型使用 1 个还是 2 个字节。
如果该位为 0,则类型只使用 1 个字节,子类型有 4 位(0 到 15)
+-------- 存储类型 | +----- 子类型大小 | | +-- 子类型 000 0 0000
当该位为 1 时,类型使用另一个字节,子类型有 12 位(最多 4096)
+-------- 存储类型
| +----- 子类型大小
| |
000 1 0000 0000 0000
| 子类型 |
+-------------+
子类型
每个存储可以有多达 4096 个子类型。它们表示存储在该存储空间中的值的类型。
**示例:**一个双字可以包含有符号整数、无符号整数、单精度浮点数等等...甚至还可以包含用户定义的类型
以下是基本数据类型的值,子类型已突出显示:
| 类型 | 存储 | 位 | 十六进制 | 十进制 |
|---|---|---|---|---|
| Null | NOBYTES | 0000 0000 | 0x00 | 0 |
| True | NOBYTES | 0000 0001 | 0x01 | 1 |
| False | NOBYTES | 0000 0010 | 0x02 | 2 |
| UInt8 | BYTE | 0010 0000 | 0x20 | 32 |
| Int8 | BYTE | 0010 0001 | 0x21 | 33 |
| UInt16 | WORD | 0100 0000 | 0x40 | 64 |
| Int16 | WORD | 0100 0001 | 0x41 | 65 |
| UInt32 | DWORD | 0110 0000 | 0x60 | 96 |
| Int32 | DWORD | 0110 0001 | 0x61 | 97 |
| Float | DWORD | 0110 0010 | 0x62 | 98 |
| UInt64 | QWORD | 1000 0000 | 0x80 | 128 |
| Int64 | QWORD | 1000 0001 | 0x81 | 129 |
| Double | QWORD | 1000 0010 | 0x82 | 130 |
| Text | STRING | 1010 0000 | 0xA0 | 160 |
| DateTime | STRING | 1010 0001 | 0xA1 | 161 |
| Date | STRING | 1010 0010 | 0xA2 | 162 |
| Time | STRING | 1010 0011 | 0xA3 | 163 |
| DecimalStr | STRING | 1010 0100 | 0xA4 | 164 |
| Blob | BLOB | 1100 0000 | 0xC0 | 192 |
| List | CONTAINER | 1110 0000 | 0xE0 | 224 |
| Map | CONTAINER | 1110 0001 | 0xE1 | 225 |
| Object | CONTAINER | 1110 0010 | 0xE2 | 226 |
用户定义类型
应用程序可以使用不同的 DateTime 类型,并将值存储在 DWORD 或 QWORD 中。
存储 = QWORD (0x80)
子类型 = 5 (0x05) [选择任何未使用的]类型 DateTime = (0x80 | 0x05 => 0x85)
应用程序可以在 Binn 结构中发送 HTML,并定义一个类型以区别于纯文本。
存储 = STRING (0xA0)
子类型 = 9 (0x09) [选择任何未使用的]类型 HTML = (0xA0 | 0x09 => 0xA9)
如果子类型大于 15,则必须使用新字节,并设置子类型大小位:
存储 = STRING (0xA000)
子类型大小 = (0x0100)
子类型 = 21 (0x0015)类型 HTML = (0xA000 | 0x1000 | 0x0015 => 0xB015)
创建的类型参数必须以大端方式存储。
[大小]
此参数用于字符串、二进制大对象和容器。它可以有1个或4个字节。
如果大小的第一个比特为0,则只使用1个字节。因此,当数据大小最多为127(0x7F)字节时,大小参数将只使用1个字节。
否则,将使用一个4字节大小的参数,其中最高有效位为1。这使我们的上限为2 GigaBytes(0x7FFFFFFF)。
| 数据大小 | 大小参数使用 |
|---|---|
| <= 127字节 | 1字节 |
| > 127字节 | 4字节 |
如果使用4个字节存储较小的大小,没有问题。读取器必须接受两者。
对于字符串,大小参数不包括空终止符。
对于容器,大小参数包括类型参数。它存储整个结构的大小。
**注意:**在2.0之前的版本中,二进制大对象的大小仅使用4个字节存储,不支持1字节大小。
[计数]
此参数仅用于容器,以通知其中的项目数量。它可以有1个或4个字节,格式与大小参数完全相同。
| 计数 | 计数参数使用 |
|---|---|
| <= 127项 | 1字节 |
| > 127项 | 4字节 |
容器
列表
列表是容器,用于一个接一个地存储值。
计数参数通知容器内的值数量。
[123, "test", 2.5, true]
映射
映射是使用整数作为键的关联数组。
键使用大端字节序DWORD(4字节)存储,作为有符号整数读取。
因此,当前的限制是从INT32_MIN到INT32_MAX。但如果需要,还有增加的空间。
计数参数通知容器内的键/值对数量。
{1: 10, 5: "the value", 7: true}
对象
对象是使用文本作为键的关联数组。
键不是空终止的,限制为255字节长。
键存储在键长度之前,使用单字节表示键长度。
计数参数通知容器内的键/值对数量。
{"id": 1, "name": "John", "points": 30.5, "active": true}
限制
| 类型 | 最小值 | 最大值 |
|---|---|---|
| 整数 | INT64_MIN | UINT64_MAX |
| 浮点数 | IEEE 754 | |
| 字符串 | 0 | 2 GB |
| 二进制大对象 | 0 | 2 GB |
| 容器 | 4 | 2 GB |
关联数组
| 键类型 | 最小值 | 最大值 |
|---|---|---|
| 数字 | INT32_MIN | INT32_MAX |
| 文本 | 0 | 255字节 |
子类型:每种存储类型最多可达4096个
示例结构
一个类似于{"hello":"world"}的json数据序列化为:
Binn: (17字节)
\xE2 // [类型] 对象(容器) \x11 // [大小] 容器总大小 \x01 // [计数] 键/值对 \x05hello // 键 \xA0 // [类型] = 字符串 \x05 // [大小] world\x00 // [数据](空终止)
3个整数的列表:
Json: (14字节)
[123, -456, 789]
Binn: (11字节)
\xE0 // [类型] 列表(容器) \x0B // [大小] 容器总大小 \x03 // [计数] 项目 \x20 // [类型] = uint8 \x7B // [数据] (123) \x41 // [类型] = int16 \xFE\x38 // [数据] (-456) \x40 // [类型] = uint16 \x03\x15 // [数据] (789)
列表中的映射:
Json: (25字节)
{1: "add", 2: [-12345, 6789]}
Binn: (26字节)
\xE1 // [类型] 映射(容器) \x1A // [大小] 容器总大小 \x02 // [计数] 键/值对 \x00\x00\x00\x01 // 键 \xA0 // [类型] = 字符串 \x03 // [大小] add\x00 // [数据](空终止) \x00\x00\x00\x02 // 键 \xE0 // [类型] 列表(容器) \x09 // [大小] 容器总大小 \x02 // [计数] 项目 \x41 // [类型] = int16 \xCF\xC7 // [数据] (-12345) \x40 // [类型] = uint16 \x1A\x85 // [数据] (6789)
对象列表:
Json: (47字节)
[ {"id": 1, "name": "John"}, {"id": 2, "name": "Eric"} ]
Binn: (43字节)
\xE0 // [类型] 列表(容器) \x2B // [大小] 容器总大小 \x02 // [计数] 项目 \xE2 // [类型] 对象(容器) \x14 // [大小] 容器总大小 \x02 // [计数] 键/值对 \x02id // 键 \x20 // [类型] = uint8 \x01 // [数据] (1) \x04name // 键 \xA0 // [类型] = 字符串 \x04 // [大小] John\x00 // [数据](空终止) \xE2 // [类型] 对象(容器) \x14 // [大小] 容器总大小 \x02 // [计数] 键/值对 \x02id // 键 \x20 // [类型] = uint8 \x02 // [数据] (2) \x04name // 键 \xA0 // [类型] = 字符串 \x04 // [大小] Eric\x00 // [数据](空终止)