4 个稳定版本

2.0.3 2021年11月16日

#1258 in 编码

每月下载量 39

MIT 许可证

500KB
11K SLoC

bson

从 mongodb-bson 分支出来,并增加了对 bson 的 u32/u64 类型支持

crates.io docs.rs crates.io

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::DateTimebson::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实例

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();

任何实现SerializeDeserialize的类型都可以以这种方式使用。这样做有助于将操作数据的“业务逻辑”与将数据转换为或从其序列化形式转换的逻辑分开。这可以导致更清晰、更简洁的代码,同时也减少了错误的可能性。

处理日期和时间

BSON格式包括一个日期时间类型,该类型通过此crate中的bson::DateTime结构体进行建模,并为该结构体提供了SerializeDeserialize实现,在序列化到或反序列化从BSON时生成和解析BSON日期时间。流行的crate chrono也提供了一个DateTime类型,但其SerializeDeserialize实现是在字符串上运行的,因此在使用BSON时,不会使用BSON日期时间类型。为了解决这个问题,可以启用chrono-0_4功能标志。此标志公开了多个方便的转换,包括从bson::DateTimechrono::DateTime的转换,包括chrono_datetime_as_bson_datetime serde辅助程序,该程序可以用于将chrono::DateTime序列化/反序列化到BSON日期时间,以及BsonFrom<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.shcheck-rustfmt.sh 脚本。

bash .evergreen/check-clippy.sh && bash .evergreen/check-rustfmt.sh

持续集成

对 master 的提交会在 evergreen 上自动运行。

依赖项

约 3.5-5MB
约 91K 行代码(SLoC)