From 09a8cbb30fc6ffb406f975511a46fb496835858b Mon Sep 17 00:00:00 2001 From: Drshika A <67125579+drshika@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:47:41 -0400 Subject: [PATCH] RUST-1699: Add serde_with 3.x integration (#422) * RUST-1699: Add serde_with 3.x integration Co-authored-by: Abraham Egnor Co-authored-by: Isabel Atkinson --- .evergreen/Cargo.lock.msrv | 92 +++++++++++++++++++++++++++++++++----- .evergreen/config.yml | 4 +- Cargo.toml | 4 +- README.md | 4 +- src/datetime.rs | 71 ++++++++++++++++++++++++++--- src/lib.rs | 4 +- src/uuid/mod.rs | 36 ++++++++++++--- 7 files changed, 184 insertions(+), 31 deletions(-) diff --git a/.evergreen/Cargo.lock.msrv b/.evergreen/Cargo.lock.msrv index 90d589d7..d7c8b742 100644 --- a/.evergreen/Cargo.lock.msrv +++ b/.evergreen/Cargo.lock.msrv @@ -61,6 +61,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + [[package]] name = "bit-set" version = "0.5.3" @@ -100,21 +106,22 @@ version = "2.6.0" dependencies = [ "ahash", "assert_matches", - "base64", + "base64 0.13.1", "bitvec", "chrono", "criterion", "hex", "indexmap", "js-sys", - "lazy_static", + "once_cell", "pretty_assertions", "proptest", "rand", "serde", "serde_bytes", "serde_json", - "serde_with", + "serde_with 1.14.0", + "serde_with 3.1.0", "time", "uuid 0.8.2", "uuid 1.1.2", @@ -296,8 +303,18 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core 0.20.3", + "darling_macro 0.20.3", ] [[package]] @@ -314,17 +331,42 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.16", +] + [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core", + "darling_core 0.13.4", "quote", "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core 0.20.3", + "quote", + "syn 2.0.16", +] + [[package]] name = "difference" version = "2.0.0" @@ -469,6 +511,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", + "serde", ] [[package]] @@ -922,7 +965,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" dependencies = [ "serde", - "serde_with_macros", + "serde_with_macros 1.5.2", +] + +[[package]] +name = "serde_with" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e47d95bc83ed33b2ecf84f4187ad1ab9685d18ff28db000c99deac8ce180e3" +dependencies = [ + "base64 0.21.2", + "chrono", + "hex", + "indexmap", + "serde", + "serde_json", + "serde_with_macros 3.1.0", + "time", ] [[package]] @@ -931,12 +990,24 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling", + "darling 0.13.4", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "serde_with_macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65" +dependencies = [ + "darling 0.20.3", + "proc-macro2", + "quote", + "syn 2.0.16", +] + [[package]] name = "strsim" version = "0.10.0" @@ -995,13 +1066,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ "itoa", "libc", "num_threads", + "serde", "time-macros", ] diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 7c9ba3af..ffb6f432 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -195,9 +195,9 @@ axes: - id: "extra-rust-versions" values: - id: "min" - display_name: "1.56 (minimum supported version)" + display_name: "1.60 (minimum supported version)" variables: - RUST_VERSION: "1.56.0" + RUST_VERSION: "1.60.0" MSRV: "true" - id: "nightly" display_name: "nightly" diff --git a/Cargo.toml b/Cargo.toml index fdf9b155..36a1167d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,13 +65,13 @@ once_cell = "1.5.1" uuid-0_8 = { package = "uuid", version = "0.8.1", features = ["serde", "v4"], optional = true } uuid = { version = "1.1.2", features = ["serde", "v4"] } serde_bytes = "0.11.5" -serde_with = { version = "1", optional = true } +serde_with = { version = "1.3.1", optional = true } +serde_with-3 = { package = "serde_with", version = "3.1.0", optional = true } time = { version = "0.3.9", features = ["formatting", "parsing", "macros", "large-dates"] } bitvec = "1.0.1" [target.'cfg(target_arch = "wasm32")'.dependencies] js-sys = "0.3" - [dev-dependencies] assert_matches = "1.2" criterion = "0.3.0" diff --git a/README.md b/README.md index 6fa99643..caa5eae3 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,8 @@ Note that if you are using `bson` through the `mongodb` crate, you do not need t | `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 | | `uuid-0_8` | Enable support for v0.8 of the [`uuid`](https://docs.rs/uuid/0.8) crate in the public API. | n/a | no | | `uuid-1` | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API. | n/a | no | -| `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/latest) integrations for `bson::DateTime` and `bson::Uuid` | serde_with | no | - +| `serde_with` | Enable [`serde_with`](https://docs.rs/serde_with/1.x) 1.x integrations for `bson::DateTime` and `bson::Uuid`.| serde_with | no | +| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for `bson::DateTime` and `bson::Uuid`. Requires Rust 1.61. | serde_with | no | ## Overview of the BSON Format BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents. diff --git a/src/datetime.rs b/src/datetime.rs index a8ce59bb..1b315bad 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -145,20 +145,20 @@ use serde_with::{DeserializeAs, SerializeAs}; /// } /// # } /// ``` -/// ### The `serde_with` feature flag +/// ### The `serde_with-3` feature flag /// -/// The `serde_with` feature can be enabled to support more ergonomic serde attributes for +/// The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for /// (de)serializing [`chrono::DateTime`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/) -/// crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with` can -/// handle nested [`chrono::DateTime`] values (e.g. in [`Option`]), whereas the former only works on -/// fields that are exactly [`chrono::DateTime`]. +/// crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with-3` +/// can handle nested [`chrono::DateTime`] values (e.g. in [`Option`]), whereas the former only +/// works on fields that are exactly [`chrono::DateTime`]. /// ``` -/// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with"))] +/// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] /// # { /// use serde::{Deserialize, Serialize}; /// use bson::doc; /// -/// #[serde_with::serde_as] +/// #[serde_with_3::serde_as] /// #[derive(Deserialize, Serialize, PartialEq, Debug)] /// struct Foo { /// /// Serializes as a BSON datetime rather than using [`chrono::DateTime`]'s serialization @@ -482,6 +482,36 @@ impl SerializeAs> for crate::DateTime { } } +#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] +#[cfg_attr( + docsrs, + doc(cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))) +)] +impl<'de> serde_with_3::DeserializeAs<'de, chrono::DateTime> for crate::DateTime { + fn deserialize_as(deserializer: D) -> std::result::Result, D::Error> + where + D: Deserializer<'de>, + { + let dt = DateTime::deserialize(deserializer)?; + Ok(dt.to_chrono()) + } +} + +#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "chrono-0_4", feature = "chrono-0_4"))))] +impl serde_with_3::SerializeAs> for crate::DateTime { + fn serialize_as( + source: &chrono::DateTime, + serializer: S, + ) -> std::result::Result + where + S: serde::Serializer, + { + let dt = DateTime::from_chrono(*source); + dt.serialize(serializer) + } +} + #[cfg(feature = "time-0_3")] #[cfg_attr(docsrs, doc(cfg(feature = "time-0_3")))] impl From for time::OffsetDateTime { @@ -525,6 +555,33 @@ impl SerializeAs for crate::DateTime { } } +#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "serde_with-3"))))] +impl<'de> serde_with_3::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime { + fn deserialize_as(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let dt = DateTime::deserialize(deserializer)?; + Ok(dt.to_time_0_3()) + } +} + +#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "time-0_3", feature = "chrono-0_4"))))] +impl serde_with_3::SerializeAs for crate::DateTime { + fn serialize_as( + source: &time::OffsetDateTime, + serializer: S, + ) -> std::result::Result + where + S: serde::Serializer, + { + let dt = DateTime::from_time_0_3(*source); + dt.serialize(serializer) + } +} + /// Errors that can occur during [`DateTime`] construction and generation. #[derive(Clone, Debug)] #[non_exhaustive] diff --git a/src/lib.rs b/src/lib.rs index 130f7028..0ce92351 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ //! //! ## Installation //! ### Requirements -//! - Rust 1.56+ +//! - Rust 1.60+ //! //! ### Importing //! This crate is available on [crates.io](https://crates.io/crates/bson). To use it in your application, @@ -267,7 +267,7 @@ //! //! ## Minimum supported Rust version (MSRV) //! -//! The MSRV for this crate is currently 1.56.0. This will be rarely be increased, and if it ever is, +//! The MSRV for this crate is currently 1.60.0. This will be rarely be increased, and if it ever is, //! it will only happen in a minor or major version release. #![allow(clippy::cognitive_complexity, clippy::derive_partial_eq_without_eq)] diff --git a/src/uuid/mod.rs b/src/uuid/mod.rs index 446e57f0..7e5fc44f 100644 --- a/src/uuid/mod.rs +++ b/src/uuid/mod.rs @@ -74,21 +74,21 @@ //! For backwards compatibility, a `uuid-0_8` feature flag can be enabled, which provides the same //! API for interoperation with version 0.8 of the `uuid` crate. //! -//! ## The `serde_with` feature flag +//! ## The `serde_with-3` feature flag //! -//! The `serde_with` feature can be enabled to support more ergonomic serde attributes for +//! The `serde_with-3` feature can be enabled to support more ergonomic serde attributes for //! (de)serializing [`uuid::Uuid`] from/to BSON via the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/) -//! crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with` can -//! handle nested [`uuid::Uuid`] values (e.g. in [`Option`]), whereas the former only works on +//! crate. The main benefit of this compared to the regular `serde_helpers` is that `serde_with-3` +//! can handle nested [`uuid::Uuid`] values (e.g. in [`Option`]), whereas the former only works on //! fields that are exactly [`uuid::Uuid`]. //! ``` -//! # #[cfg(all(feature = "uuid-1", feature = "serde_with"))] +//! # #[cfg(all(feature = "uuid-1", feature = "serde_with-3"))] //! # { //! # use uuid as uuid; //! use serde::{Deserialize, Serialize}; //! use bson::doc; //! -//! #[serde_with::serde_as] +//! #[serde_with_3::serde_as] //! #[derive(Deserialize, Serialize, PartialEq, Debug)] //! struct Foo { //! /// Serializes as a BSON binary rather than using [`uuid::Uuid`]'s serialization @@ -509,6 +509,30 @@ macro_rules! trait_impls { uuid.serialize(serializer) } } + + #[cfg(all($feat, feature = "serde_with-3"))] + #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with-3"))))] + impl<'de> serde_with_3::DeserializeAs<'de, $u> for crate::Uuid { + fn deserialize_as(deserializer: D) -> std::result::Result<$u, D::Error> + where + D: serde::Deserializer<'de>, + { + let uuid = Uuid::deserialize(deserializer)?; + Ok(uuid.into()) + } + } + + #[cfg(all($feat, feature = "serde_with_3"))] + #[cfg_attr(docsrs, doc(cfg(all($feat, feature = "serde_with_3"))))] + impl serde_with_3::SerializeAs<$u> for crate::Uuid { + fn serialize_as(source: &$u, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let uuid = Uuid::from(*source); + uuid.serialize(serializer) + } + } }; } trait_impls!(feature = "uuid-0_8", uuid_0_8::Uuid);