4 个稳定版本
2.0.3 | 2021年11月16日 |
---|
#1258 in 编码
每月下载量 39
500KB
11K SLoC
bson
从 mongodb-bson 分支出来,并增加了对 bson 的 u32/u64 类型支持
Rust 中 BSON 的编码和解码支持
索引
有用的链接
安装
需求
- Rust 1.48+
导入
此软件包可在 crates.io 上获取。要在您的项目中使用它,只需将其添加到项目的 Cargo.toml
文件中。
[dependencies]
bson = "2.0.1"
注意,如果您通过 mongodb
软件包使用 bson
,则无需在您的 Cargo.toml
文件中指定它,因为 mongodb
软件包已经重新导出它。
功能标志
功能 | 描述 | 额外依赖 | 默认 |
---|---|---|---|
chrono-0_4 |
在公共 API 中启用对 chrono 软件包 v0.4 的支持。 |
n/a | no |
uuid-0_8 |
在公共 API 中启用对 uuid 软件包 v0.8 的支持。 |
n/a | no |
serde_with |
启用 serde_with 集成,以支持 bson::DateTime 和 bson::Uuid |
serde_with | no |
BSON格式概述
BSON是Binary JSON的缩写,是一种类似于JSON的文档的二进制编码序列化格式。和BSON一样,BSON支持在文档和数组内部嵌入其他文档和数组。BSON还包含扩展,允许表示JSON规范之外的多种数据类型。例如,BSON包含日期时间类型和二进制数据类型。
// JSON equivalent
{"hello": "world"}
// BSON encoding
\x16\x00\x00\x00 // total document size
\x02 // 0x02 = type String
hello\x00 // field name
\x06\x00\x00\x00world\x00 // field value
\x00 // 0x00 = type EOO ('end of object')
BSON是MongoDB的主要数据表示格式,该crate用于在mongodb
驱动crate的API和实现中。
有关BSON的更多信息,请参阅bsonspec.org。
使用方法
BSON值
许多不同的类型都可以表示为BSON值,包括32位和64位有符号整数、64位浮点数、字符串、日期时间、嵌入式文档等。要查看可能的BSON值的完整列表,请参阅BSON规范。此crate通过Bson
枚举来模拟各种可能的BSON值。
创建Bson
实例
let string = Bson::String("hello world".to_string());
let int = Bson::Int32(5);
let array = Bson::Array(vec![Bson::Int32(5), Bson::Boolean(false)]);
let string: Bson = "hello world".into();
let int: Bson = 5i32.into();
let string = bson!("hello world");
let int = bson!(5);
let array = bson!([5, false]);
bson!
支持数组和对象字面量,并且它自动将指定的任何值转换为Bson
,前提是它们实现了Into<Bson>
。
Bson
值解包
Bson
包含多个辅助方法来访问其底层原生Rust类型。这些辅助方法在事先已知BSON值的特定类型的情况下可能非常有用。
例如:
let value = Bson::Int32(5);
let int = value.as_i32(); // Some(5)
let bool = value.as_bool(); // None
let value = bson!([true]);
let array = value.as_array(); // Some(&Vec<Bson>)
BSON文档
BSON文档是UTF-8编码字符串到BSON值的有序映射。它们在逻辑上与JSON对象相似,可以包含子文档、数组和多种不同类型的值。此crate通过Document
结构来模拟BSON文档。
创建Document
Document
可以从包含BSON数据的字节读取器直接创建,或者通过doc!
宏来创建
let mut bytes = hex::decode("0C0000001069000100000000").unwrap();
let doc = Document::from_reader(&mut bytes.as_slice()).unwrap(); // { "i": 1 }
let doc = doc! {
"hello": "world",
"int": 5,
"subdoc": { "cat": true },
};
doc!
与bson!
类似,不同之处在于它总是返回一个Document
而不是一个Bson
。
Document
成员访问
Document
提供多种方法来方便成员访问
let doc = doc! {
"string": "string",
"bool": true,
"i32": 5,
"doc": { "x": true },
};
// attempt get values as untyped Bson
let none = doc.get("asdfadsf"); // None
let value = doc.get("string"); // Some(&Bson::String("string"))
// attempt to get values with explicit typing
let string = doc.get_str("string"); // Ok("string")
let subdoc = doc.get_document("doc"); // Some(Document({ "x": true }))
let error = doc.get_i64("i32"); // Err(...)
使用强类型数据结构建模 BSON
虽然可以直接处理文档和BSON值,但这通常会在验证必要键是否存在及其值是否为正确类型时引入大量样板代码。serde
提供了一种强大的方式,可以将BSON数据自动映射到Rust数据结构中,从而消除了所有这些样板代码的需求。
例如:
#[derive(Serialize, Deserialize)]
struct Person {
name: String,
age: i32,
phones: Vec<String>,
}
// Some BSON input data as a `Bson`.
let bson_data: Bson = bson!({
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
});
// Deserialize the Person struct from the BSON data, automatically
// verifying that the necessary keys are present and that they are of
// the correct types.
let mut person: Person = bson::from_bson(bson_data).unwrap();
// Do things just like with any other Rust data structure.
println!("Redacting {}'s record.", person.name);
person.name = "REDACTED".to_string();
// Get a serialized version of the input data as a `Bson`.
let redacted_bson = bson::to_bson(&person).unwrap();
任何实现Serialize
和Deserialize
的类型都可以以这种方式使用。这样做有助于将操作数据的“业务逻辑”与将数据转换为或从其序列化形式转换的逻辑分开。这可以导致更清晰、更简洁的代码,同时也减少了错误的可能性。
处理日期和时间
BSON格式包括一个日期时间类型,该类型通过此crate中的bson::DateTime
结构体进行建模,并为该结构体提供了Serialize
和Deserialize
实现,在序列化到或反序列化从BSON时生成和解析BSON日期时间。流行的crate chrono
也提供了一个DateTime
类型,但其Serialize
和Deserialize
实现是在字符串上运行的,因此在使用BSON时,不会使用BSON日期时间类型。为了解决这个问题,可以启用chrono-0_4
功能标志。此标志公开了多个方便的转换,包括从bson::DateTime
到chrono::DateTime
的转换,包括chrono_datetime_as_bson_datetime
serde辅助程序,该程序可以用于将chrono::DateTime
序列化/反序列化到BSON日期时间,以及Bson
的From<chrono::DateTime>
实现,允许在doc!
和bson!
宏中使用chrono::DateTime
值。
例如:
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Foo {
// serializes as a BSON datetime.
date_time: bson::DateTime,
// serializes as an RFC 3339 / ISO-8601 string.
chrono_datetime: chrono::DateTime<chrono::Utc>,
// serializes as a BSON datetime.
// this requires the "chrono-0_4" feature flag
#[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
chrono_as_bson: chrono::DateTime<chrono::Utc>,
}
// this automatic conversion also requires the "chrono-0_4" feature flag
let query = doc! {
"created_at": chrono::Utc::now(),
};
处理 UUID
请参阅bson::uuid
模块的模块级文档。
最低支持的Rust版本(MSRV)
此crate的MSRV目前是1.48.0。这很少会增加,如果增加,也只会发生在小版本或大版本发布时。
贡献
我们鼓励并愿意接受以GitHub拉取请求形式的贡献。在打开一个之前,请务必在本地运行测试;查看测试部分了解如何进行测试。一旦你打开一个pull请求,你的分支将与我们用于持续集成系统的相同的测试矩阵进行测试,因此通常只需要在独立环境中针对集成测试运行本地测试即可。请记住,在打开pull请求之前始终运行lint测试。
运行测试
集成和单元测试
要实际运行测试,你可以像在其他crate中使用cargo
一样使用它
cargo test --verbose # runs against localhost:27017
Linter Tests
我们的代码检查器使用 rustfmt
的夜间版本来验证源代码格式是否正确,并使用 clippy
的稳定版本来静态检测常见的错误。您可以使用 rustup
安装它们。
rustup component add clippy --toolchain stable
rustup component add rustfmt --toolchain nightly
要运行代码检查器测试,请在 .evergreen
目录中运行 check-clippy.sh
和 check-rustfmt.sh
脚本。
bash .evergreen/check-clippy.sh && bash .evergreen/check-rustfmt.sh
持续集成
对 master 的提交会在 evergreen 上自动运行。
依赖项
约 3.5-5MB
约 91K 行代码(SLoC)