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)
  • 容器

常量如下:

存储十六进制十进制
NOBYTES000 0 00000x000
BYTE001 0 00000x2032
WORD010 0 00000x4064
DWORD011 0 00000x6096
QWORD100 0 00000x80128
STRING101 0 00000xA0160
BLOB110 0 00000xC0192
CONTAINER111 0 00000xE0224

子类型大小

下一位表示类型使用 1 个还是 2 个字节。

如果该位为 0,则类型只使用 1 个字节,子类型有 4 位(0 到 15)

 +-------- 存储类型
 |  +----- 子类型大小
 |  |  +-- 子类型
000 0 0000

当该位为 1 时,类型使用另一个字节,子类型有 12 位(最多 4096)

 +-------- 存储类型
 |  +----- 子类型大小
 |  |
000 1 0000  0000 0000
      |  子类型   |
      +-------------+

子类型

每个存储可以有多达 4096 个子类型。它们表示存储在该存储空间中的值的类型。

**示例:**一个双字可以包含有符号整数、无符号整数、单精度浮点数等等...甚至还可以包含用户定义的类型

以下是基本数据类型的值,子类型已突出显示:

类型存储十六进制十进制
NullNOBYTES0000 00000x000
TrueNOBYTES0000 00010x011
FalseNOBYTES0000 00100x022
UInt8BYTE0010 00000x2032
Int8BYTE0010 00010x2133
UInt16WORD0100 00000x4064
Int16WORD0100 00010x4165
UInt32DWORD0110 00000x6096
Int32DWORD0110 00010x6197
FloatDWORD0110 00100x6298
UInt64QWORD1000 00000x80128
Int64QWORD1000 00010x81129
DoubleQWORD1000 00100x82130
TextSTRING1010 00000xA0160
DateTimeSTRING1010 00010xA1161
DateSTRING1010 00100xA2162
TimeSTRING1010 00110xA3163
DecimalStrSTRING1010 01000xA4164
BlobBLOB1100 00000xC0192
ListCONTAINER1110 00000xE0224
MapCONTAINER1110 00010xE1225
ObjectCONTAINER1110 00100xE2226

用户定义类型

应用程序可以使用不同的 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_MINUINT64_MAX
浮点数IEEE 754
字符串02 GB
二进制大对象02 GB
容器42 GB

关联数组

键类型最小值最大值
数字INT32_MININT32_MAX
文本0255字节

子类型:每种存储类型最多可达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       // [数据](空终止)