扩展库 / bson
bson
数据格式MongoDB BSON 二进制序列化编解码 — var 直转架构,无需 Builder/Iterator 中间层。table 字面量直接编码为 BSON,解码后直接用字符串键索引、整数下标访问数组、xtime 自动互操作。
典型场景
快速开始
import bson
func main(...) as int
// 一行编码:var table → BSON 二进制
var bin = bson.encode({"name": "xlang", "ver": 6, "tags": ["fast", "safe"]})
// 一行解码:BSON → var,直接索引
var doc = bson.decode(bin)
println(doc["name"]) // xlang
println(doc["tags"][0]) // fast
// 文件 I/O
bson.save("data.bson", doc)
var loaded = bson.load("data.bson")
return 0
end核心特性
- var 直转 — 无 Builder/Iterator,table 字面量直接 encode/decode
- 类型自动映射 — int→Int32/Int64, float→Double, xtime→Date, array→Array, table→Document
- 数组原生支持 — BSON Array 解码为 xlang array,支持 [0] 索引、.length、for in
- xtime 互操作 — BSON Date 自动转为 xtime,可直接调用 time.year() 等
- 多文档流 — concat + decodeAll 支持 MongoDB 导出/wire protocol 场景
- 边界安全 — 畸形 BSON 输入不会越界读取,所有 reader 带 bounds check
- 零拷贝优化 — encode/concat 使用 xrtMalloc + 所有权转移,减少一次内存拷贝
类型映射表
| xlang var | BSON 类型 | 说明 |
|---|---|---|
| string | String (0x02) | UTF-8 文本 |
| int (≤32bit) | Int32 (0x10) | 自动判断范围 |
| int (>32bit) | Int64 (0x12) | 自动判断范围 |
| float | Double (0x01) | 64-bit IEEE 754 |
| bool | Boolean (0x08) | true/false |
| null | Null (0x0A) | 空值 |
| xtime | Date (0x09) | 毫秒精度 |
| table | Document (0x03) | 嵌套文档 |
| array / list | Array (0x04) | 有序序列 |
包信息
| 字段 | 值 |
|---|---|
| 包名 | bson |
| 版本 | 3.0.0 |
| 实现 | C 混编 (TCC 内嵌编译) |
| 内核 | cloudwu/lua-bson (MIT) |
| 依赖 | 无 |
| ABI | 1 |
核心 API
将 var table 编码为 BSON 二进制。自动推断值类型:int→Int32/Int64, float→Double, xtime→Date, table→Document, array/list→Array。
将 BSON 二进制解码为 var table。Document→table, Array→array, Date→xtime, String→string。
解码拼接的 BSON 流(多个文档连续存放),返回 array of table。适用于 MongoDB 导出文件。
二进制安全拼接两个 BSON var。用于构造多文档流(var 的 + 运算符对含 null 字节的二进制不安全)。
从文件加载 BSON 并解码为 var table。
将 var table 编码为 BSON 并写入文件,返回写入字节数。
工具函数
生成 24 字符十六进制 ObjectId(兼容 MongoDB 格式:4字节时间戳 + 5字节机器标识 + 3字节计数器)。
从 ObjectId 提取创建时间,返回 xtime 秒数。可用 time(oidTime(...)) 转为 xtime 类型。
将 BSON 二进制转为十六进制字符串(调试用)。
读取 BSON 文档头部声明的字节长度(不解析内容)。
教学范例
覆盖全部 API 的逐步教学代码:
import bson
func main(...) as int
// ═══ 1. 基本编解码 ═══
var doc = {"name": "xlang", "version": 6, "pi": 3.14159, "active": true}
var bin = bson.encode(doc)
println("编码长度: ", bson.docLength(bin))
var decoded = bson.decode(bin)
println("name = ", decoded["name"])
println("version = ", decoded["version"])
// ═══ 2. 嵌套文档 ═══
var nested = {"type": "user", "profile": {"city": "Beijing", "zip": 100000}}
var n = bson.decode(bson.encode(nested))
println("city = ", n["profile"]["city"])
// ═══ 3. 数组 ═══
var withArr = {"title": "demo", "tags": ["dev", "fun", "xlang"]}
var a = bson.decode(bson.encode(withArr))
println("tag[0] = ", a["tags"][0])
println("tags.length = ", a["tags"].length)
// ═══ 4. null 和 int64 ═══
var mixed = {"nothing": null, "big": 9876543210, "small": 42}
var m = bson.decode(bson.encode(mixed))
println("big = ", m["big"])
// ═══ 5. ObjectId ═══
string oid1 = bson.objectId()
println("OID: ", oid1)
int oidSecs = bson.oidTime(oid1)
println("OID 年份: ", time.year(time(oidSecs)))
// ═══ 6. Hex 调试 ═══
string hexStr = bson.toHex(bson.encode({"x": 1}))
println("hex: ", hexStr)
// ═══ 7. 文件 I/O ═══
int written = bson.save("data.bson", {"saved": true, "count": 7})
var loaded = bson.load("data.bson")
println("loaded.count = ", loaded["count"])
// ═══ 8. 多文档流 ═══
var stream = bson.concat(bson.encode({"id": 1}), bson.encode({"id": 2}))
var docs = bson.decodeAll(stream)
println("文档数: ", docs.length)
println("bson example: PASS")
return 0
end运行范例
cd release xl.exe run examples\extlibs\bson.xl
测试覆盖
测试文件:extlibs/bson/test/bson_test.xl,覆盖全部公开 API:
- 基本 encode/decode 往返(string/int/float/bool)
- 直接索引访问
- 嵌套文档链式索引
- 数组解码为 xlang array(整数索引 + .length)
- xtime 互操作(Date 自动转换)
- null 和 int64 边界
- ObjectId 生成(唯一性 + 24字符)
- ObjectId 时间提取
- Hex 调试输出
- 文件 I/O(save + load 往返)
- 多文档流(concat + decodeAll)
完整测试代码
import bson
func main(...) as int
print("=== bson var 直转测试 ===")
// 1. 基本往返
var doc = {"name": "xlang", "version": 6, "pi": 3.14159, "active": true}
var bin = bson.encode(doc)
print("编码长度: " + string(bson.docLength(bin)))
var decoded = bson.decode(bin)
print("name = " + string(decoded["name"]))
print("version = " + string(decoded["version"]))
// 2. 嵌套文档
var nested = {"type": "user", "profile": {"city": "Beijing", "zip": 100000}}
var n = bson.decode(bson.encode(nested))
print("city = " + string(n["profile"]["city"]))
// 3. 数组
var withArr = {"title": "test", "tags": ["dev", "fun", "xlang"]}
var a = bson.decode(bson.encode(withArr))
print("tag0 = " + string(a["tags"][0]))
print("len = " + string(a["tags"].length))
// 4. null / int64
var mixed = {"nothing": null, "big": 9876543210, "small": 42}
var m = bson.decode(bson.encode(mixed))
print("big = " + string(m["big"]))
// 5. ObjectId
string oid1 = bson.objectId()
print("OID: " + oid1)
int oidT = bson.oidTime(oid1)
print("OID 年份: " + string(time.year(time(oidT))))
// 6. Hex
string hexStr = bson.toHex(bson.encode({"x": 1}))
print("hex: " + hexStr)
// 7. 文件 I/O
int written = bson.save("build/bson_test_tmp.bson", {"saved": true, "count": 7})
var loaded = bson.load("build/bson_test_tmp.bson")
print("loaded.count = " + string(loaded["count"]))
// 8. 多文档流
var stream = bson.concat(bson.encode({"id": 1, "msg": "hello"}),
bson.encode({"id": 2, "msg": "world"}))
var docs = bson.decodeAll(stream)
print("文档数: " + string(docs.length))
print("doc[0].msg = " + string(docs[0]["msg"]))
print("=== 测试完成 ===")
return 0
end运行测试
cd release xl.exe run extlibs\bson\test\bson_test.xl