Skip to content

Commit 44f34c7

Browse files
make serde_json optional
1 parent 25ac200 commit 44f34c7

File tree

7 files changed

+157
-143
lines changed

7 files changed

+157
-143
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

src/bson.rs

Lines changed: 5 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@
2121

2222
//! BSON definition
2323
24+
#[cfg(feature = "serde_json-1")]
25+
mod json;
26+
2427
use std::{
2528
convert::TryFrom,
2629
fmt::{self, Debug, Display, Formatter},
2730
hash::Hash,
2831
ops::Index,
2932
};
3033

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

3637
/// Possible BSON value types.
3738
#[derive(Clone, Default, PartialEq)]
@@ -450,143 +451,7 @@ where
450451
}
451452
}
452453

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-
460454
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-
590455
/// Get the [`ElementType`] of this value.
591456
pub fn element_type(&self) -> ElementType {
592457
match *self {
@@ -668,7 +533,7 @@ impl Bson {
668533
} else {
669534
doc! {
670535
"$binary": {
671-
"base64": base64::encode(bytes),
536+
"base64": crate::base64::encode(bytes),
672537
"subType": hex::encode([tval]),
673538
}
674539
}

src/bson/json.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use serde_json::{json, Value};
2+
3+
use crate::{Binary, Bson, DbPointer, JavaScriptCodeWithScope, Regex, Timestamp};
4+
5+
/// 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).
6+
impl From<Bson> for Value {
7+
fn from(bson: Bson) -> Self {
8+
bson.into_relaxed_extjson()
9+
}
10+
}
11+
12+
impl Bson {
13+
/// Converts the Bson value into its [relaxed extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
14+
pub fn into_relaxed_extjson(self) -> Value {
15+
match self {
16+
Bson::Double(v) if v.is_nan() => {
17+
let s = if v.is_sign_negative() { "-NaN" } else { "NaN" };
18+
19+
json!({ "$numberDouble": s })
20+
}
21+
Bson::Double(v) if v.is_infinite() => {
22+
let s = if v.is_sign_negative() {
23+
"-Infinity"
24+
} else {
25+
"Infinity"
26+
};
27+
28+
json!({ "$numberDouble": s })
29+
}
30+
Bson::Double(v) => json!(v),
31+
Bson::String(v) => json!(v),
32+
Bson::Array(v) => Value::Array(v.into_iter().map(Bson::into_relaxed_extjson).collect()),
33+
Bson::Document(v) => Value::Object(
34+
v.into_iter()
35+
.map(|(k, v)| (k, v.into_relaxed_extjson()))
36+
.collect(),
37+
),
38+
Bson::Boolean(v) => json!(v),
39+
Bson::Null => Value::Null,
40+
Bson::RegularExpression(Regex { pattern, options }) => {
41+
let mut chars: Vec<_> = options.as_str().chars().collect();
42+
chars.sort_unstable();
43+
44+
let options: String = chars.into_iter().collect();
45+
46+
json!({
47+
"$regularExpression": {
48+
"pattern": pattern.into_string(),
49+
"options": options,
50+
}
51+
})
52+
}
53+
Bson::JavaScriptCode(code) => json!({ "$code": code }),
54+
Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
55+
"$code": code,
56+
"$scope": Bson::Document(scope).into_relaxed_extjson(),
57+
}),
58+
Bson::Int32(v) => v.into(),
59+
Bson::Int64(v) => v.into(),
60+
Bson::Timestamp(Timestamp { time, increment }) => json!({
61+
"$timestamp": {
62+
"t": time,
63+
"i": increment,
64+
}
65+
}),
66+
Bson::Binary(Binary { subtype, ref bytes }) => {
67+
let tval: u8 = From::from(subtype);
68+
json!({
69+
"$binary": {
70+
"base64": crate::base64::encode(bytes),
71+
"subType": hex::encode([tval]),
72+
}
73+
})
74+
}
75+
Bson::ObjectId(v) => json!({"$oid": v.to_hex()}),
76+
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time_0_3().year() <= 9999 => {
77+
json!({
78+
// Unwrap safety: timestamps in the guarded range can always be formatted.
79+
"$date": v.try_to_rfc3339_string().unwrap(),
80+
})
81+
}
82+
Bson::DateTime(v) => json!({
83+
"$date": { "$numberLong": v.timestamp_millis().to_string() },
84+
}),
85+
Bson::Symbol(v) => json!({ "$symbol": v }),
86+
Bson::Decimal128(v) => json!({ "$numberDecimal": v.to_string() }),
87+
Bson::Undefined => json!({ "$undefined": true }),
88+
Bson::MinKey => json!({ "$minKey": 1 }),
89+
Bson::MaxKey => json!({ "$maxKey": 1 }),
90+
Bson::DbPointer(DbPointer {
91+
ref namespace,
92+
ref id,
93+
}) => json!({
94+
"$dbPointer": {
95+
"$ref": namespace,
96+
"$id": {
97+
"$oid": id.to_hex()
98+
}
99+
}
100+
}),
101+
}
102+
}
103+
104+
/// Converts the Bson value into its [canonical extended JSON representation](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/).
105+
pub fn into_canonical_extjson(self) -> Value {
106+
match self {
107+
Bson::Int32(i) => json!({ "$numberInt": i.to_string() }),
108+
Bson::Int64(i) => json!({ "$numberLong": i.to_string() }),
109+
Bson::Double(f) if f.is_normal() => {
110+
let mut s = f.to_string();
111+
if f.fract() == 0.0 {
112+
s.push_str(".0");
113+
}
114+
115+
json!({ "$numberDouble": s })
116+
}
117+
Bson::Double(f) if f == 0.0 => {
118+
let s = if f.is_sign_negative() { "-0.0" } else { "0.0" };
119+
120+
json!({ "$numberDouble": s })
121+
}
122+
Bson::DateTime(date) => {
123+
json!({ "$date": { "$numberLong": date.timestamp_millis().to_string() } })
124+
}
125+
Bson::Array(arr) => {
126+
Value::Array(arr.into_iter().map(Bson::into_canonical_extjson).collect())
127+
}
128+
Bson::Document(arr) => Value::Object(
129+
arr.into_iter()
130+
.map(|(k, v)| (k, v.into_canonical_extjson()))
131+
.collect(),
132+
),
133+
Bson::JavaScriptCodeWithScope(JavaScriptCodeWithScope { code, scope }) => json!({
134+
"$code": code,
135+
"$scope": Bson::Document(scope).into_canonical_extjson(),
136+
}),
137+
138+
other => other.into_relaxed_extjson(),
139+
}
140+
}
141+
}

src/extjson.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,6 @@
8888
//! println!("{}", canonical_extjson); // { "x": { "$numberInt": "5" }, "_id": { "$oid": <hexstring> } }
8989
//! ```
9090
91+
#[cfg(feature = "serde_json-1")]
9192
pub mod de;
9293
pub(crate) mod models;

src/extjson/models.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! A module defining serde models for the extended JSON representations of the various BSON types.
22
3+
#![cfg_attr(not(feature = "serde_json-1"), allow(unused))]
4+
35
use serde::{
46
de::{Error as _, Unexpected},
57
Deserialize,
@@ -196,6 +198,7 @@ impl Uuid {
196198
}
197199
}
198200

201+
#[cfg(feature = "serde_json-1")]
199202
#[derive(Deserialize)]
200203
#[serde(deny_unknown_fields)]
201204
pub(crate) struct JavaScriptCodeWithScope {

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
//! | `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. | no |
6969
//! | `compat-3-0-0` | Required for future compatibility if default features are disabled. | no |
7070
//! | `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. | no |
71+
//! | `serde_json-1` | Enable support for v1.x of the [`serde_json`](https://docs.rs/serde_json/1.x) crate in the public API. | no |
7172
//!
7273
//! ## BSON values
7374
//!

0 commit comments

Comments
 (0)