4 个版本
0.2.1 | 2021 年 1 月 22 日 |
---|---|
0.2.0 | 2021 年 1 月 17 日 |
0.1.1 | 2021 年 1 月 13 日 |
0.1.0 | 2021 年 1 月 10 日 |
#912 在 编码
3MB
3K SLoC
rawbson
rawbson
提供了对 BSON 数据的零拷贝操作。
用法
可以从包含原始 BSON 数据的 Vec<u8>
创建一个 rawbson 文档,并通过与 bson-rust crate 中类似的方法访问元素。请注意,rawbson 返回一个 Result<Option>,因为文档中的字节只有在尝试访问包含的数据时才进行完全验证。
use rawbson::{
DocBuf,
elem,
};
// \x16\x00\x00\x00 // total document size
// \x02 // 0x02 = type String
// hello\x00 // field name
// \x06\x00\x00\x00world\x00 // field value
// \x00
let doc = DocBuf::new(b"\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00".to_vec())?;
let elem: Option<elem::Element> = doc.get("hello")?;
assert_eq!(
elem.unwrap().as_str()?,
"world",
);
# Ok::<(), rawbson::RawError>(())
bson-rust 互操作
该 crate 设计为与 bson crate 顺利互操作。
可以从 DocBuf
创建一个 bson::document::Document
。内部,将 Document
序列化为一个 Vec<u8>
,然后将这些字节包含在 DocBuf
中。
use bson::doc;
use rawbson::{
DocBuf,
};
let document = doc!{"goodbye": {"cruel": "world"}};
let raw = DocBuf::from_document(&document);
let value: Option<&str> = raw.get_document("goodbye")?
.map(|docref| docref.get_str("cruel"))
.transpose()?
.flatten();
assert_eq!(
value,
Some("world"),
);
# Ok::<(), rawbson::RawError>(())
引用类型
也可以使用 [Doc
] 引用类型访问 BSON 文档,这是一个无大小类型,它将 BSON 有效负载表示为 [u8]
。这允许在不重新分配的情况下访问嵌套文档。[Doc] 必须始终通过指针类型访问,类似于 [T]
和 str
。
此类型将至少与已弃用的 [DocRef] 类型共存一个次要版本。
以下示例在一个基于堆栈的数组中构建一个 bson 文档,并从中提取一个 &str,不进行堆分配。
use rawbson::Doc;
let bytes = b"\x13\x00\x00\x00\x02hi\x00\x06\x00\x00\x00y'all\x00\x00";
assert_eq!(Doc::new(bytes)?.get_str("hi")?, Some("y'all"));
# Ok::<(), rawbson::RawError>(())
迭代
《Doc》实现了IntoIterator
,也可以通过DocBuf::iter
或已弃用的DocRef::into_iter
访问。
use bson::doc;
use rawbson::{DocBuf, elem::Element};
let doc = DocBuf::from_document(&doc! {"crate": "rawbson", "license": "MIT"});
let mut dociter = doc.iter();
let (key, value): (&str, Element) = dociter.next().unwrap()?;
assert_eq!(key, "crate");
assert_eq!(value.as_str()?, "rawbson");
let (key, value): (&str, Element) = dociter.next().unwrap()?;
assert_eq!(key, "license");
assert_eq!(value.as_str()?, "MIT");
# Ok::<(), rawbson::RawError>(())
serde支持
还提供了serde反序列化支持。
目前尚未提供serde序列化支持。现在,请使用bson::to_document
代替,然后使用bson::Document::to_writer
或DocBuf::from_document
进行序列化。
use serde::Deserialize;
use bson::{doc, Document, oid::ObjectId, DateTime};
use rawbson::{DocBuf, de::from_docbuf};
#[derive(Deserialize)]
#[serde(rename_all="camelCase")]
struct User {
#[serde(rename = "_id")]
id: ObjectId,
first_name: String,
last_name: String,
birthdate: Option<chrono::DateTime<chrono::Utc>>,
#[serde(flatten)]
extra: Document,
}
let doc = DocBuf::from_document(&doc!{
"_id": ObjectId::with_string("543254325432543254325432")?,
"firstName": "John",
"lastName": "Doe",
"birthdate": null,
"luckyNumbers": [3, 60, 2147483647],
"nickname": "Red",
});
let user: User = from_docbuf(&doc)?;
assert_eq!(user.id.to_hex(), "543254325432543254325432");
assert_eq!(user.first_name, "John");
assert_eq!(user.last_name, "Doe");
assert_eq!(user.extra.get_str("nickname")?, "Red");
assert!(user.birthdate.is_none());
# Ok::<(), Box<dyn std::error::Error>>(())
性能
待办:用更严格的分析替换此部分。
由于rawbson不需要解析BSON负载或为文档中的每个元素分配空间,因此访问文档中的单个元素和按顺序遍历元素比使用bson::Document
类型要快得多。
将原始字节反序列化到自定义类型也比使用bson crate提供的反序列化方法要快得多,因为所有这些方法都是首先将它们反序列化到解析后的Bson类型。
另一方面,由于找到特定键需要从文档的开始遍历,创建具有O(1)元素访问的解析bson::Document
,当在文档中反复访问随机元素时,访问速度会更快。
此crate提供了一个criterion基准测试套件来支持这些断言。在我的Thinkpad X1 Carbon (Gen 5)上运行这些基准测试的输出可以在./criterion-report目录中找到。
欢迎提出改进这些基准测试质量的建议。
依赖项
~6.5MB
~122K SLoC