Skip to content

Commit d8fb3f3

Browse files
make serde_json optional
1 parent 431d448 commit d8fb3f3

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"]
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, spec::ElementType, Binary, Decimal128};
35+
use crate::{oid, spec::ElementType, Binary, Decimal128};
3536

3637
/// Possible BSON value types.
3738
#[derive(Clone, Default, PartialEq)]
@@ -444,143 +445,7 @@ where
444445
}
445446
}
446447

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

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.chars().collect();
42+
chars.sort_unstable();
43+
44+
let options: String = chars.into_iter().collect();
45+
46+
json!({
47+
"$regularExpression": {
48+
"pattern": pattern,
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)