Skip to content

Commit 174fe65

Browse files
RUST-2240 Move serde_json API behind a feature flag (#567)
1 parent 194177a commit 174fe65

File tree

11 files changed

+424
-426
lines changed

11 files changed

+424
-426
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ serde_path_to_error = ["dep:serde_path_to_error"]
4848
# should be used in conjunction with chrono-0_4 or uuid-0_8.
4949
serde_with-3 = ["dep:serde_with", "dep:serde"]
5050
serde = ["dep:serde"]
51+
serde_json-1 = ["dep:serde_json"]
5152

5253
[lib]
5354
name = "bson"
@@ -57,7 +58,7 @@ ahash = "0.8.0"
5758
chrono = { version = "0.4.15", features = ["std"], default-features = false, optional = true }
5859
rand = "0.9"
5960
serde = { version = "1.0", features = ["derive"], optional = true }
60-
serde_json = { version = "1.0", features = ["preserve_order"] }
61+
serde_json = { version = "1.0", features = ["preserve_order"], optional = true }
6162
indexmap = "2.1.0"
6263
hex = "0.4.2"
6364
base64 = "0.22.1"
@@ -84,6 +85,7 @@ pretty_assertions = "0.6.1"
8485
proptest = "1.0.0"
8586
serde_bytes = "0.11"
8687
serde_path_to_error = "0.1.16"
88+
serde_json = "1"
8789
chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false }
8890

8991
[package.metadata.docs.rs]

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t
5050
| `chrono-0_4` | Enable support for v0.4 of the [`chrono`](https://docs.rs/chrono/0.4) crate in the public API. | n/a | no |
5151
| `uuid-1` | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API. | n/a | no |
5252
| `time-0_3` | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API. | n/a | no |
53-
| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with | no |
54-
| `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest). This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature. | serde_path_to_error | no |
53+
| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`.| `serde_with` | no |
54+
| `serde_path_to_error` | Enable support for error paths via integration with [`serde_path_to_error`](https://docs.rs/serde_path_to_err/latest). This is an unstable feature and any breaking changes to `serde_path_to_error` may affect usage of it via this feature. | `serde_path_to_error` | no |
5555
| `compat-3-0-0` | Required for future compatibility if default features are disabled. | n/a | no |
5656
| `large_dates` | Increase the supported year range for some `bson::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 |
57+
| `serde_json-1` | Enable support for v1.x of the [`serde_json`](https://docs.rs/serde_json/1.x) crate in the public API. | `serde_json` | no |
5758

5859
## Overview of the BSON Format
5960

serde-tests/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ edition = "2018"
88
default = []
99

1010
[dependencies]
11-
bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde", "serde_with-3"] }
11+
bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde", "serde_with-3", "serde_json-1"] }
1212
serde = { version = "1.0", features = ["derive"] }
1313
pretty_assertions = "0.6.1"
1414
hex = "0.4.2"

src/bson.rs

Lines changed: 2 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ use std::{
2828
ops::Index,
2929
};
3030

31-
use serde_json::{json, Value};
32-
3331
pub use crate::document::Document;
34-
use crate::{base64, oid, raw::CString, spec::ElementType, Binary, Decimal128};
32+
use crate::{oid, raw::CString, spec::ElementType, Binary, Decimal128};
3533

3634
/// Possible BSON value types.
3735
#[derive(Clone, Default, PartialEq)]
@@ -450,143 +448,7 @@ where
450448
}
451449
}
452450

453-
/// This will create the [relaxed Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) representation of the provided [`Bson`](../enum.Bson.html).
454-
impl From<Bson> for Value {
455-
fn from(bson: Bson) -> Self {
456-
bson.into_relaxed_extjson()
457-
}
458-
}
459-
460451
impl Bson {
461-
/// Converts the Bson value into its [relaxed extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
462-
pub fn into_relaxed_extjson(self) -> Value {
463-
match self {
464-
Bson::Double(v) if v.is_nan() => {
465-
let s = if v.is_sign_negative() { "-NaN" } else { "NaN" };
466-
467-
json!({ "$numberDouble": s })
468-
}
469-
Bson::Double(v) if v.is_infinite() => {
470-
let s = if v.is_sign_negative() {
471-
"-Infinity"
472-
} else {
473-
"Infinity"
474-
};
475-
476-
json!({ "$numberDouble": s })
477-
}
478-
Bson::Double(v) => json!(v),
479-
Bson::String(v) => json!(v),
480-
Bson::Array(v) => Value::Array(v.into_iter().map(Bson::into_relaxed_extjson).collect()),
481-
Bson::Document(v) => Value::Object(
482-
v.into_iter()
483-
.map(|(k, v)| (k, v.into_relaxed_extjson()))
484-
.collect(),
485-
),
486-
Bson::Boolean(v) => json!(v),
487-
Bson::Null => Value::Null,
488-
Bson::RegularExpression(Regex { pattern, options }) => {
489-
let mut chars: Vec<_> = options.as_str().chars().collect();
490-
chars.sort_unstable();
491-
492-
let options: String = chars.into_iter().collect();
493-
494-
json!({
495-
"$regularExpression": {
496-
"pattern": pattern.into_string(),
497-
"options": options,
498-
}
499-
})
500-
}
501-
Bson::JavaScriptCode(code) => json!({ "$code": code }),
502-
Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
503-
"$code": code,
504-
"$scope": Bson::Document(scope).into_relaxed_extjson(),
505-
}),
506-
Bson::Int32(v) => v.into(),
507-
Bson::Int64(v) => v.into(),
508-
Bson::Timestamp(Timestamp { time, increment }) => json!({
509-
"$timestamp": {
510-
"t": time,
511-
"i": increment,
512-
}
513-
}),
514-
Bson::Binary(Binary { subtype, ref bytes }) => {
515-
let tval: u8 = From::from(subtype);
516-
json!({
517-
"$binary": {
518-
"base64": base64::encode(bytes),
519-
"subType": hex::encode([tval]),
520-
}
521-
})
522-
}
523-
Bson::ObjectId(v) => json!({"$oid": v.to_hex()}),
524-
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time_0_3().year() <= 9999 => {
525-
json!({
526-
// Unwrap safety: timestamps in the guarded range can always be formatted.
527-
"$date": v.try_to_rfc3339_string().unwrap(),
528-
})
529-
}
530-
Bson::DateTime(v) => json!({
531-
"$date": { "$numberLong": v.timestamp_millis().to_string() },
532-
}),
533-
Bson::Symbol(v) => json!({ "$symbol": v }),
534-
Bson::Decimal128(v) => json!({ "$numberDecimal": v.to_string() }),
535-
Bson::Undefined => json!({ "$undefined": true }),
536-
Bson::MinKey => json!({ "$minKey": 1 }),
537-
Bson::MaxKey => json!({ "$maxKey": 1 }),
538-
Bson::DbPointer(DbPointer {
539-
ref namespace,
540-
ref id,
541-
}) => json!({
542-
"$dbPointer": {
543-
"$ref": namespace,
544-
"$id": {
545-
"$oid": id.to_hex()
546-
}
547-
}
548-
}),
549-
}
550-
}
551-
552-
/// Converts the Bson value into its [canonical extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
553-
pub fn into_canonical_extjson(self) -> Value {
554-
match self {
555-
Bson::Int32(i) => json!({ "$numberInt": i.to_string() }),
556-
Bson::Int64(i) => json!({ "$numberLong": i.to_string() }),
557-
Bson::Double(f) if f.is_normal() => {
558-
let mut s = f.to_string();
559-
if f.fract() == 0.0 {
560-
s.push_str(".0");
561-
}
562-
563-
json!({ "$numberDouble": s })
564-
}
565-
Bson::Double(f) if f == 0.0 => {
566-
let s = if f.is_sign_negative() { "-0.0" } else { "0.0" };
567-
568-
json!({ "$numberDouble": s })
569-
}
570-
Bson::DateTime(date) => {
571-
json!({ "$date": { "$numberLong": date.timestamp_millis().to_string() } })
572-
}
573-
Bson::Array(arr) => {
574-
Value::Array(arr.into_iter().map(Bson::into_canonical_extjson).collect())
575-
}
576-
Bson::Document(arr) => Value::Object(
577-
arr.into_iter()
578-
.map(|(k, v)| (k, v.into_canonical_extjson()))
579-
.collect(),
580-
),
581-
Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
582-
"$code": code,
583-
"$scope": Bson::Document(scope).into_canonical_extjson(),
584-
}),
585-
586-
other => other.into_relaxed_extjson(),
587-
}
588-
}
589-
590452
/// Get the [`ElementType`] of this value.
591453
pub fn element_type(&self) -> ElementType {
592454
match *self {
@@ -668,7 +530,7 @@ impl Bson {
668530
} else {
669531
doc! {
670532
"$binary": {
671-
"base64": base64::encode(bytes),
533+
"base64": crate::base64::encode(bytes),
672534
"subType": hex::encode([tval]),
673535
}
674536
}

src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Contains the error-related types for the `bson` crate.
2+
13
mod decimal128;
24
mod oid;
35
mod uuid;

src/extjson.rs

Lines changed: 2 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,3 @@
1-
//! Deserialization and serialization of [MongoDB Extended JSON v2](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)
2-
//!
3-
//! ## Overview of Extended JSON
4-
//!
5-
//! MongoDB Extended JSON (abbreviated extJSON) is format of JSON that allows for the encoding of
6-
//! BSON type information. Normal JSON cannot unambiguously represent all BSON types losslessly, so
7-
//! an extension was designed to include conventions for representing those types.
8-
//!
9-
//! For example, a BSON binary is represented by the following format:
10-
//! ```text
11-
//! {
12-
//! "$binary": {
13-
//! "base64": <base64 encoded payload as a string>,
14-
//! "subType": <subtype as a one or two character hex string>,
15-
//! }
16-
//! }
17-
//! ```
18-
//! For more information on extJSON and the complete list of translations, see the [official MongoDB documentation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
19-
//!
20-
//! All MongoDB drivers and BSON libraries interpret and produce extJSON, so it can serve as a
21-
//! useful tool for communicating between applications where raw BSON bytes cannot be used (e.g. via
22-
//! JSON REST APIs). It's also useful for representing BSON data as a string.
23-
//!
24-
//! ### Canonical and Relaxed Modes
25-
//!
26-
//! There are two modes of extJSON: "Canonical" and "Relaxed". They are the same except for the
27-
//! following differences:
28-
//! - In relaxed mode, all BSON numbers are represented by the JSON number type, rather than the
29-
//! object notation.
30-
//! - In relaxed mode, the string in the datetime object notation is RFC 3339 (ISO-8601) formatted
31-
//! (if the date is after 1970).
32-
//!
33-
//! e.g.
34-
//! ```rust
35-
//! # use bson::bson;
36-
//! let doc = bson!({ "x": 5, "d": bson::DateTime::now() });
37-
//!
38-
//! println!("relaxed: {}", doc.clone().into_relaxed_extjson());
39-
//! // relaxed: "{"x":5,"d":{"$date":"2020-06-01T22:19:13.075Z"}}"
40-
//!
41-
//! println!("canonical: {}", doc.into_canonical_extjson());
42-
//! // canonical: {"x":{"$numberInt":"5"},"d":{"$date":{"$numberLong":"1591050020711"}}}
43-
//! ```
44-
//!
45-
//! Canonical mode is useful when BSON values need to be round tripped without losing any type
46-
//! information. Relaxed mode is more useful when debugging or logging BSON data.
47-
//!
48-
//! ## Deserializing Extended JSON
49-
//!
50-
//! Extended JSON can be deserialized using [`Bson`](../enum.Bson.html)'s
51-
//! `TryFrom<serde_json::Value>` implementation. This implementation accepts both canonical and
52-
//! relaxed extJSON, and the two modes can even be mixed within a single representation.
53-
//!
54-
//! e.g.
55-
//! ```rust
56-
//! # use bson::Bson;
57-
//! # use serde_json::json;
58-
//! # use std::convert::{TryFrom, TryInto};
59-
//! let json_doc = json!({ "x": 5i32, "y": { "$numberInt": "5" }, "z": { "subdoc": "hello" } });
60-
//! let bson: Bson = json_doc.try_into().unwrap(); // Bson::Document(...)
61-
//!
62-
//! let json_date = json!({ "$date": { "$numberLong": "1590972160292" } });
63-
//! let bson_date: Bson = json_date.try_into().unwrap(); // Bson::DateTime(...)
64-
//!
65-
//! let invalid_ext_json = json!({ "$numberLong": 5 });
66-
//! Bson::try_from(invalid_ext_json).expect_err("5 should be a string");
67-
//! ```
68-
//!
69-
//! ## Serializing to Extended JSON
70-
//!
71-
//! Extended JSON can be created via [`Bson`](../enum.Bson.html)'s `Into<serde_json::Value>`
72-
//! implementation (which will create relaxed extJSON),
73-
//! [`Bson::into_relaxed_extjson`](../enum.Bson.html#method.into_relaxed_extjson), and
74-
//! [`Bson::into_canonical_extjson`](../enum.Bson.html#method.into_canonical_extjson).
75-
//!
76-
//! e.g.
77-
//! ```rust
78-
//! # use bson::{bson, oid};
79-
//! let doc = bson!({ "x": 5i32, "_id": oid::ObjectId::new() });
80-
//!
81-
//! let relaxed_extjson: serde_json::Value = doc.clone().into();
82-
//! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": <hexstring> } }
83-
//!
84-
//! let relaxed_extjson = doc.clone().into_relaxed_extjson();
85-
//! println!("{}", relaxed_extjson); // { "x": 5, "_id": { "$oid": <hexstring> } }
86-
//!
87-
//! let canonical_extjson = doc.into_canonical_extjson();
88-
//! println!("{}", canonical_extjson); // { "x": { "$numberInt": "5" }, "_id": { "$oid": <hexstring> } }
89-
//! ```
90-
91-
pub mod de;
1+
#[cfg(feature = "serde_json-1")]
2+
pub(crate) mod json;
923
pub(crate) mod models;

0 commit comments

Comments
 (0)