- Notifications
You must be signed in to change notification settings - Fork145
Encoding and decoding support for BSON in Rust
License
mongodb/bson-rust
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Encoding and decoding support for BSON in Rust
- Installation
- Useful links
- Overview of BSON Format
- Usage
- Contributing
- Running the Tests
- Continuous Integration
- Rust 1.81+
This crate is available oncrates.io. To use it in your application, simply add it to your project'sCargo.toml
.
[dependencies]bson ="3.0.0"
Note that if you are usingbson
through themongodb
crate, you do not need to specify it in yourCargo.toml
, since themongodb
crate already re-exports it.
Feature | Description | Extra dependencies | Default |
---|---|---|---|
chrono-0_4 | Enable support for v0.4 of thechrono crate in the public API. | n/a | no |
uuid-1 | Enable support for v1.x of theuuid crate in the public API. | n/a | no |
time-0_3 | Enable support for v0.3 of thetime crate in the public API. | n/a | no |
serde_with-3 | Enableserde_with 3.x integrations forbson::DateTime andbson::Uuid . | serde_with | no |
serde_path_to_error | Enable support for error paths via integration withserde_path_to_error . This is an unstable feature and any breaking changes toserde_path_to_error may affect usage of it via this feature. | serde_path_to_error | no |
compat-3-0-0 | Required for future compatibility if default features are disabled. | n/a | no |
large_dates | Increase the supported year range for somebson::DateTime utilities from +/-9,999 (inclusive) to +/-999,999 (inclusive). Note that enabling this feature can impact performance and introduce parsing ambiguities. | n/a | no |
serde_json-1 | Enable support for v1.x of theserde_json crate in the public API. | serde_json | no |
BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents.Like JSON, BSON supports the embedding of documents and arrays within other documentsand arrays. BSON also contains extensions that allow representation of data types thatare not part of the JSON spec. For example, BSON has a datetime type and a binary data type.
// JSON equivalent{"hello": "world"}// BSON encoding\x16\x00\x00\x00 // total document size\x02 // 0x02 = type Stringhello\x00 // field name\x06\x00\x00\x00world\x00 // field value\x00 // 0x00 = type EOO ('end of object')
BSON is the primary data representation forMongoDB, and this crate is used in themongodb
driver crate in its API and implementation.
For more information about BSON itself, seebsonspec.org.
Many different types can be represented as a BSON value, including 32-bit and 64-bit signedintegers, 64 bit floating point numbers, strings, datetimes, embedded documents, and more. Tosee a full list of possible BSON values, see theBSON specification. The variouspossible BSON values are modeled in this crate by theBson
enum.
CreatingBson
instances
Bson
values can be instantiated directly or via thebson!
macro:
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!
supports both array and object literals, and it automatically converts any values specified toBson
, provided they areInto<Bson>
.
Bson
value unwrapping
Bson
has a number of helper methods for accessing the underlying native Rust types. These helpers can be useful in circumstances in which the specific type of a BSON valueis known ahead of time.
e.g.:
let value =Bson::Int32(5);let int = value.as_i32();// Some(5)let bool = value.as_bool();// Nonelet value =bson!([true]);let array = value.as_array();// Some(&Vec<Bson>)
BSON documents are ordered maps of UTF-8 encoded strings to BSON values. They are logically similar to JSON objects in that they can contain subdocuments, arrays, and values of several different types. This crate models BSON documents via theDocument
struct.
CreatingDocument
s
Document
s can be created directly either from a bytereader containing BSON data or via thedoc!
macro:
letmut 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!
works similarly tobson!
, except that it alwaysreturns aDocument
rather than aBson
.
Document
member access
Document
has a number of methods on it to facilitate memberaccess:
let doc =doc!{"string":"string","bool":true,"i32":5,"doc":{"x":true},};// attempt get values as untyped Bsonlet none = doc.get("asdfadsf");// Nonelet value = doc.get("string");// Some(&Bson::String("string"))// attempt to get values with explicit typinglet string = doc.get_str("string");// Ok("string")let subdoc = doc.get_document("doc");// Some(Document({ "x": true }))let error = doc.get_i64("i32");// Err(...)
While it is possible to work with documents and BSON values directly, it will often introduce alot of boilerplate for verifying the necessary keys are present and their values are the correcttypes.serde
provides a powerful way of mapping BSON data into Rust data structures largelyautomatically, removing the need for all that boilerplate.
e.g.:
#[derive(Serialize,Deserialize)]structPerson{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.letmut 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();
Any types that implementSerialize
andDeserialize
can be used in this way. Doing so helpsseparate the "business logic" that operates over the data from the (de)serialization logic thattranslates the data to/from its serialized form. This can lead to more clear and concise codethat is also less error prone.
When serializing values that cannot be represented in BSON, or deserialzing from BSON that doesnot match the format expected by the type, the default error will only report the specific fieldthat failed. To aid debugging, enabling theserde_path_to_error
feature willaugment errors with thefull field path from root object to failing field. This feature does incur a small CPU and memoryoverhead during (de)serialization and should be enabled with care in performance-sensitiveenvironments.
The BSON format includes a datetime type, which is modeled in this crate by thebson::DateTime
struct, and theSerialize
andDeserialize
implementations for this struct produce and parse BSON datetimes whenserializing to or deserializing from BSON. The popular cratechrono
alsoprovides aDateTime
type, but itsSerialize
andDeserialize
implementations operate on stringsinstead, so when using it with BSON, the BSON datetime type is not used. To work around this, thechrono-0_4
feature flag can be enabled. This flag exposes a number of convenient conversionsbetweenbson::DateTime
andchrono::DateTime
, including thedatetime::FromChrono04DateTime
serde helper, which can be used to (de)serializechrono::DateTime
s to/from BSON datetimes, and theFrom<chrono::DateTime>
implementation forBson
, which allowschrono::DateTime
values to beused in thedoc!
andbson!
macros.
e.g.
use serde::{Serialize,Deserialize};use serde_with::serde_as;#[serde_as]#[derive(Serialize,Deserialize)]structFoo{// 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_as(as ="bson::serde_helpers::datetime::FromChrono04DateTime")]chrono_as_bson: chrono::DateTime<chrono::Utc>,}// this automatic conversion also requires the "chrono-0_4" feature flaglet query =doc!{"created_at": chrono::Utc::now(),};
See the module-level documentation for thebson::uuid
module.
This crate compiles to thewasm32-unknown-unknown
target; when doing so, thejs-sys
crate is used for the current timestamp component ofObjectId
generation.
The MSRV for this crate is currently 1.81. Increases to the MSRV will only happen in a minor or major version release, and will be to a Rust version at least six months old.
We encourage and would happily accept contributions in the form of GitHub pull requests. Before opening one, be sure to run the tests locally; check out thetesting section for information on how to do that. Once you open a pull request, your branch will be run against the same testing matrix that we use for ourcontinuous integration system, so it is usually sufficient to only run the integration tests locally against a standalone. Remember to always run the linter tests before opening a pull request.
To actually run the tests, you can usecargo
like you would in any other crate:
cargotest --verbose# runs against localhost:27017
Our linter tests use the nightly version ofrustfmt
to verify that the source is formatted properly and the stable version ofclippy
to statically detect any common mistakes.You can userustup
to install them both:
rustup component add clippy --toolchain stablerustup component add rustfmt --toolchain nightly
To run the linter tests, run thecheck-clippy.sh
andcheck-rustfmt.sh
scripts in the.evergreen
directory:
bash .evergreen/check-clippy.sh&& bash .evergreen/check-rustfmt.sh
Commits to main are run automatically onevergreen.
About
Encoding and decoding support for BSON in Rust
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.