Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ 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-1` | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.0) crate in the public API. | n/a | no |
| `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 |
| `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 |
| `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) type conversion utilities in the public API. | `serde_with` | no |
| `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 |
| `compat-3-0-0` | Required for future compatibility if default features are disabled. | n/a | no |
| `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 |
Expand Down
10 changes: 6 additions & 4 deletions serde-tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1187,13 +1187,14 @@ fn u2i() {

#[test]
fn serde_with_chrono() {
use bson::serde_helpers::datetime;
#[serde_with::serde_as]
#[derive(Deserialize, Serialize, PartialEq, Debug)]
struct Foo {
#[serde_as(as = "Option<bson::DateTime>")]
#[serde_as(as = "Option<datetime::FromChrono04DateTime>")]
as_bson: Option<chrono::DateTime<chrono::Utc>>,

#[serde_as(as = "Option<bson::DateTime>")]
#[serde_as(as = "Option<datetime::FromChrono04DateTime>")]
none_bson: Option<chrono::DateTime<chrono::Utc>>,
}

Expand All @@ -1211,13 +1212,14 @@ fn serde_with_chrono() {

#[test]
fn serde_with_uuid() {
use bson::serde_helpers::uuid_1;
#[serde_with::serde_as]
#[derive(Deserialize, Serialize, PartialEq, Debug)]
struct Foo {
#[serde_as(as = "Option<bson::Uuid>")]
#[serde_as(as = "Option<uuid_1::AsBinary>")]
as_bson: Option<uuid::Uuid>,

#[serde_as(as = "Option<bson::Uuid>")]
#[serde_as(as = "Option<uuid_1::AsBinary>")]
none_bson: Option<uuid::Uuid>,
}

Expand Down
84 changes: 2 additions & 82 deletions src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ use std::{

#[cfg(feature = "chrono-0_4")]
use chrono::{LocalResult, TimeZone, Utc};
#[cfg(all(
feature = "serde_with-3",
any(feature = "chrono-0_4", feature = "time-0_3", feature = "jiff-0_2")
))]
use serde::{Deserialize, Deserializer, Serialize};
use time::format_description::well_known::Rfc3339;

pub use crate::datetime::builder::DateTimeBuilder;
Expand Down Expand Up @@ -108,7 +103,7 @@ use crate::error::{Error, Result};
///
/// ### `serde_helpers`
/// The `bson` crate provides a number of useful helpers for serializing and deserializing
/// various datetime types to and from different formats using the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/)
/// various datetime types to and from different formats using the [`serde_with`](https://docs.rs/serde_with/latest/serde_with/)
/// crate.
///
/// > **Note:** All helpers in this module require use of the [`#[serde_as]`](https://docs.rs/serde_with/latest/serde_with/attr.serde_as.html)
Expand Down Expand Up @@ -149,7 +144,7 @@ use crate::error::{Error, Result};
/// }
/// # }
/// ```
/// The main benefit of using the [`serde_with`](https://docs.rs/serde_with/1.11.0/serde_with/) crate
/// The main benefit of using the [`serde_with`](https://docs.rs/serde_with/latest/serde_with/) crate
/// is that it can handle nested [`chrono::DateTime`] values (e.g. in [`Option`] or [`Vec`]).
/// ```
/// # #[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
Expand Down Expand Up @@ -496,31 +491,6 @@ impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for crate::DateTime {
}
}

#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))]
impl<'de> serde_with::DeserializeAs<'de, chrono::DateTime<Utc>> for crate::DateTime {
Copy link
Contributor Author

@abr-egn abr-egn Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DeserializeAs/SerializeAs are supposed to only be implemented for container types or converter types, not leaf value types; this was essentially tagging crate::DateTime as a converter type for itself.

fn deserialize_as<D>(deserializer: D) -> std::result::Result<chrono::DateTime<Utc>, 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"))]
impl serde_with::SerializeAs<chrono::DateTime<Utc>> for crate::DateTime {
fn serialize_as<S>(
source: &chrono::DateTime<Utc>,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let dt = DateTime::from_chrono(*source);
dt.serialize(serializer)
}
}

#[cfg(feature = "jiff-0_2")]
impl From<crate::DateTime> for jiff::Timestamp {
fn from(bson_dt: DateTime) -> Self {
Expand All @@ -535,31 +505,6 @@ impl From<jiff::Timestamp> for crate::DateTime {
}
}

#[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))]
impl<'de> serde_with::DeserializeAs<'de, jiff::Timestamp> for crate::DateTime {
fn deserialize_as<D>(deserializer: D) -> std::result::Result<jiff::Timestamp, D::Error>
where
D: Deserializer<'de>,
{
let dt = DateTime::deserialize(deserializer)?;
Ok(dt.to_jiff())
}
}

#[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))]
impl serde_with::SerializeAs<jiff::Timestamp> for crate::DateTime {
fn serialize_as<S>(
source: &jiff::Timestamp,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let dt = DateTime::from_jiff(*source);
dt.serialize(serializer)
}
}

#[cfg(feature = "time-0_3")]
impl From<crate::DateTime> for time::OffsetDateTime {
fn from(bson_dt: DateTime) -> Self {
Expand All @@ -573,28 +518,3 @@ impl From<time::OffsetDateTime> for crate::DateTime {
Self::from_time_0_3(x)
}
}

#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))]
impl<'de> serde_with::DeserializeAs<'de, time::OffsetDateTime> for crate::DateTime {
fn deserialize_as<D>(deserializer: D) -> std::result::Result<time::OffsetDateTime, D::Error>
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"))]
impl serde_with::SerializeAs<time::OffsetDateTime> for crate::DateTime {
fn serialize_as<S>(
source: &time::OffsetDateTime,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let dt = DateTime::from_time_0_3(*source);
dt.serialize(serializer)
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
//! | `uuid-1` | Enable support for v1.x of the [`uuid`](https://docs.rs/uuid/1.x) crate in the public API. | no |
//! | `time-0_3` | Enable support for v0.3 of the [`time`](https://docs.rs/time/0.3) crate in the public API. | no |
//! | `serde` | Enable integration with the [`serde`](https://docs.rs/serde/) serialization/deserialization framework. | no |
//! | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) 3.x integrations for [`DateTime`] and [`Uuid`]. | no |
//! | `serde_with-3` | Enable [`serde_with`](https://docs.rs/serde_with/3.x) type conversion utilities in the public API. | no |
//! | `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 |
//! | `compat-3-0-0` | Required for future compatibility if default features are disabled. | yes |
//! | `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 |
Expand Down
10 changes: 6 additions & 4 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ macro_rules! rawdoc {
///
/// This macro generates a `SerializeAs`/`DeserializeAs` implementation for a given type,
/// with optional struct-level attributes like `#[derive(...)]` or `/// doc comments`.
#[allow(unused_macros)]
#[cfg(feature = "serde")]
macro_rules! serde_conv_doc {
($(#[$meta:meta])* $vis:vis $m:ident, $t:ty, $ser:expr, $de:expr) => {
#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -470,7 +470,8 @@ macro_rules! serde_conv_doc {
}
}

impl SerializeAs<$t> for $m {
#[cfg(feature = "serde_with-3")]
impl serde_with::SerializeAs<$t> for $m {
fn serialize_as<S>(x: &$t, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Expand All @@ -479,7 +480,8 @@ macro_rules! serde_conv_doc {
}
}

impl<'de> DeserializeAs<'de, $t> for $m {
#[cfg(feature = "serde_with-3")]
impl<'de> serde_with::DeserializeAs<'de, $t> for $m {
fn deserialize_as<D>(deserializer: D) -> Result<$t, D::Error>
where
D: Deserializer<'de>,
Expand All @@ -491,5 +493,5 @@ macro_rules! serde_conv_doc {
};
}

#[allow(unused_imports)]
#[cfg(feature = "serde")]
pub(crate) use serde_conv_doc;
Loading