Skip to content

Commit b4b3c64

Browse files
committed
doc: add module documentation for unsigned_duration serialization and deserialization
1 parent 1ef9631 commit b4b3c64

File tree

1 file changed

+113
-16
lines changed

1 file changed

+113
-16
lines changed

src/fmt/serde.rs

Lines changed: 113 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,13 +1339,87 @@ pub mod tz {
13391339
}
13401340
}
13411341

1342-
/// Serialize and deserialize [`UnsignedDuration`](core::time::Duration) in
1343-
/// the [`friendly`](crate::fmt::friendly) duration format.
1342+
/// Helpers for serializing and deserializing [`std::time::Duration`]
1343+
/// in the [`friendly`](crate::fmt::friendly) duration format.
1344+
///
1345+
/// This module provides functions to be used with Serde's `serialize_with`
1346+
/// and `deserialize_with` attributes. It allows `std::time::Duration`
1347+
/// values to be represented as human-readable strings like "1h 30m" or
1348+
/// "2m 15s 100ms" in your serialized output (e.g., JSON, TOML).
1349+
///
1350+
/// The deserializer expects a non-negative duration string. If a negative
1351+
/// duration string (e.g., "-5s" or "5s ago") is encountered, deserialization
1352+
/// will fail, as `std::time::Duration` cannot represent negative values.
1353+
///
1354+
/// # Module Structure
1355+
///
1356+
/// - [`friendly::compact`](crate::fmt::serde::unsigned_duration::friendly::compact):
1357+
/// For serializing `std::time::Duration` into a compact friendly format
1358+
/// (e.g., "1h 30m"). Contains `required` and `optional` serializers.
1359+
/// - [`deserialize`](crate::fmt::serde::unsigned_duration::deserialize): For
1360+
/// deserializing friendly duration strings back into `std::time::Duration`.
1361+
/// Contains `required` and `optional` deserializers.
1362+
///
1363+
/// # Example: Round-tripping `std::time::Duration`
1364+
///
1365+
/// This example demonstrates how to serialize and deserialize a
1366+
/// `std::time::Duration` field using the helpers from this module.
1367+
///
1368+
/// ```
1369+
/// use core::time::Duration;
1370+
/// use serde::{Deserialize, Serialize};
1371+
///
1372+
/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
1373+
/// struct Task {
1374+
/// name: String,
1375+
/// #[serde(
1376+
/// serialize_with = "jiff::fmt::serde::unsigned_duration::friendly::compact::required",
1377+
/// deserialize_with = "jiff::fmt::serde::unsigned_duration::deserialize::required"
1378+
/// )]
1379+
/// timeout: Duration,
1380+
/// #[serde(
1381+
/// serialize_with = "jiff::fmt::serde::unsigned_duration::friendly::compact::optional",
1382+
/// deserialize_with = "jiff::fmt::serde::unsigned_duration::deserialize::optional"
1383+
/// )]
1384+
/// retry_delay: Option<Duration>,
1385+
/// }
1386+
///
1387+
/// let task = Task {
1388+
/// name: "Task 1".to_string(),
1389+
/// timeout: Duration::from_secs(60 * 60 + 30 * 60), // 1 hour 30 minutes
1390+
/// retry_delay: Some(Duration::from_millis(2500)), // 2 seconds 500 milliseconds
1391+
/// };
1392+
///
1393+
/// let expected_json = r#"{"name":"Task 1","timeout":"1h 30m","retry_delay":"2s 500ms"}"#;
1394+
/// let actual_json = serde_json::to_string(&task)?;
1395+
/// assert_eq!(actual_json, expected_json);
1396+
///
1397+
/// let deserialized_task: Task = serde_json::from_str(&actual_json)?;
1398+
/// assert_eq!(deserialized_task, task);
1399+
///
1400+
/// // Example with None for optional field
1401+
/// let task_no_retry = Task {
1402+
/// name: "Task 2".to_string(),
1403+
/// timeout: Duration::from_secs(5),
1404+
/// retry_delay: None,
1405+
/// };
1406+
/// let expected_json_no_retry = r#"{"name":"Task 2","timeout":"5s","retry_delay":null}"#;
1407+
/// let actual_json_no_retry = serde_json::to_string(&task_no_retry)?;
1408+
/// assert_eq!(actual_json_no_retry, expected_json_no_retry);
1409+
///
1410+
/// let deserialized_task_no_retry: Task = serde_json::from_str(&actual_json_no_retry)?;
1411+
/// assert_eq!(deserialized_task_no_retry, task_no_retry);
1412+
///
1413+
/// # Ok::<(), Box<dyn std::error::Error>>(())
1414+
/// ```
13441415
pub mod unsigned_duration {
1345-
/// Serialize and deserialize [`UnsignedDuration`](core::time::Duration)
1346-
/// in the [`friendly`](crate::fmt::friendly) duration format.
1416+
/// Serialize [`UnsignedDuration`](core::time::Duration)
1417+
/// in the [`friendly`](crate::fmt::friendly) duration format using
1418+
/// compact designators (e.g., "1h 30m" instead of "1 hour 30 minutes").
1419+
///
1420+
/// These routines are for use with Serde's `serialize_with` attribute.
13471421
pub mod friendly {
1348-
/// Serialize and deserialize [`UnsignedDuration`](core::time::Duration)
1422+
/// Serialize [`UnsignedDuration`](core::time::Duration)
13491423
/// in the [`friendly`](crate::fmt::friendly) duration format using
13501424
/// compact designators.
13511425
pub mod compact {
@@ -1368,9 +1442,10 @@ pub mod unsigned_duration {
13681442
}
13691443
}
13701444

1371-
/// Serialize a required `UnsignedDuration`[`core::time::Duration`]
1372-
/// in the [`friendly`](crate::fmt::friendly) duration format using
1373-
/// compact designators.
1445+
/// Serializes a required [`std::time::Duration`] in the friendly,
1446+
/// compact duration format (e.g., "1h 30m").
1447+
///
1448+
/// This function is intended for use with `#[serde(serialize_with = "...")]`.
13741449
#[inline]
13751450
pub fn required<S: serde::Serializer>(
13761451
duration: &UnsignedDuration,
@@ -1379,8 +1454,13 @@ pub mod unsigned_duration {
13791454
se.collect_str(&CompactUnsignedDuration(duration))
13801455
}
13811456

1382-
/// Serialize an optional [`UnsignedDuration`](core::time::Duration)
1383-
/// in the [`friendly`](crate::fmt::friendly) duration format.
1457+
/// Serializes an optional [`std::time::Duration`] in the friendly,
1458+
/// compact duration format (e.g., "1h 30m").
1459+
///
1460+
/// If the duration is `None`, it will be serialized as `null` (or its
1461+
/// equivalent in the chosen format).
1462+
///
1463+
/// This function is intended for use with `#[serde(serialize_with = "...")]`.
13841464
#[inline]
13851465
pub fn optional<S: serde::Serializer>(
13861466
duration: &Option<UnsignedDuration>,
@@ -1396,6 +1476,14 @@ pub mod unsigned_duration {
13961476

13971477
/// Deserialize an [`UnsignedDuration`](core::time::Duration) in the
13981478
/// [`friendly`](crate::fmt::friendly) duration format.
1479+
///
1480+
/// These routines are for use with Serde's `deserialize_with` attribute.
1481+
/// They expect a non-negative duration string (e.g., "1h 30m", "2s 500ms").
1482+
/// If a negative duration string (e.g., "-5s" or "5s ago") is encountered,
1483+
/// deserialization will fail because `std::time::Duration` cannot represent
1484+
/// negative values.
1485+
///
1486+
/// For serialization, use the helpers in the sibling `friendly` module.
13991487
pub mod deserialize {
14001488
use crate::fmt::friendly;
14011489
use core::time::Duration as UnsignedDuration;
@@ -1425,8 +1513,7 @@ pub mod unsigned_duration {
14251513
.parse_duration(value)
14261514
.map_err(de::Error::custom)?;
14271515

1428-
UnsignedDuration::try_from(duration)
1429-
.map_err(de::Error::custom)
1516+
UnsignedDuration::try_from(duration).map_err(de::Error::custom)
14301517
}
14311518
}
14321519

@@ -1463,17 +1550,27 @@ pub mod unsigned_duration {
14631550
}
14641551
}
14651552

1466-
/// Deserialize an [`UnsignedDuration`](core::time::Duration) in the
1467-
/// [`friendly`](crate::fmt::friendly) duration format.
1553+
/// Deserializes a required [`std::time::Duration`] in the friendly
1554+
/// format (e.g., "1h 30m").
1555+
///
1556+
/// Expects a non-negative duration. Deserialization will fail if the
1557+
/// string represents a negative duration.
1558+
///
1559+
/// This function is intended for use with `#[serde(deserialize_with = "...")]`.
14681560
#[inline]
14691561
pub fn required<'de, D: serde::Deserializer<'de>>(
14701562
de: D,
14711563
) -> Result<UnsignedDuration, D::Error> {
14721564
de.deserialize_str(UnsignedDurationVisitor)
14731565
}
14741566

1475-
/// Deserialize an optional [`UnsignedDuration`](core::time::Duration)
1476-
/// in the [`friendly`](crate::fmt::friendly) duration format.
1567+
/// Deserializes an optional [`std::time::Duration`] in the friendly
1568+
/// format (e.g., "1h 30m"), or `null`.
1569+
///
1570+
/// Expects a non-negative duration if a string is provided. Deserialization
1571+
/// will fail if the string represents a negative duration.
1572+
///
1573+
/// This function is intended for use with `#[serde(deserialize_with = "...")]`.
14771574
#[inline]
14781575
pub fn optional<'de, D: serde::Deserializer<'de>>(
14791576
de: D,

0 commit comments

Comments
 (0)