@@ -1339,13 +1339,87 @@ pub mod tz {
1339
1339
}
1340
1340
}
1341
1341
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
+ /// ```
1344
1415
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.
1347
1421
pub mod friendly {
1348
- /// Serialize and deserialize [`UnsignedDuration`](core::time::Duration)
1422
+ /// Serialize [`UnsignedDuration`](core::time::Duration)
1349
1423
/// in the [`friendly`](crate::fmt::friendly) duration format using
1350
1424
/// compact designators.
1351
1425
pub mod compact {
@@ -1368,9 +1442,10 @@ pub mod unsigned_duration {
1368
1442
}
1369
1443
}
1370
1444
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 = "...")]`.
1374
1449
#[ inline]
1375
1450
pub fn required < S : serde:: Serializer > (
1376
1451
duration : & UnsignedDuration ,
@@ -1379,8 +1454,13 @@ pub mod unsigned_duration {
1379
1454
se. collect_str ( & CompactUnsignedDuration ( duration) )
1380
1455
}
1381
1456
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 = "...")]`.
1384
1464
#[ inline]
1385
1465
pub fn optional < S : serde:: Serializer > (
1386
1466
duration : & Option < UnsignedDuration > ,
@@ -1396,6 +1476,14 @@ pub mod unsigned_duration {
1396
1476
1397
1477
/// Deserialize an [`UnsignedDuration`](core::time::Duration) in the
1398
1478
/// [`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.
1399
1487
pub mod deserialize {
1400
1488
use crate :: fmt:: friendly;
1401
1489
use core:: time:: Duration as UnsignedDuration ;
@@ -1425,8 +1513,7 @@ pub mod unsigned_duration {
1425
1513
. parse_duration ( value)
1426
1514
. map_err ( de:: Error :: custom) ?;
1427
1515
1428
- UnsignedDuration :: try_from ( duration)
1429
- . map_err ( de:: Error :: custom)
1516
+ UnsignedDuration :: try_from ( duration) . map_err ( de:: Error :: custom)
1430
1517
}
1431
1518
}
1432
1519
@@ -1463,17 +1550,27 @@ pub mod unsigned_duration {
1463
1550
}
1464
1551
}
1465
1552
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 = "...")]`.
1468
1560
#[ inline]
1469
1561
pub fn required < ' de , D : serde:: Deserializer < ' de > > (
1470
1562
de : D ,
1471
1563
) -> Result < UnsignedDuration , D :: Error > {
1472
1564
de. deserialize_str ( UnsignedDurationVisitor )
1473
1565
}
1474
1566
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 = "...")]`.
1477
1574
#[ inline]
1478
1575
pub fn optional < ' de , D : serde:: Deserializer < ' de > > (
1479
1576
de : D ,
0 commit comments