nt_time/serde_with/unix_time/
nanoseconds.rs

1// SPDX-FileCopyrightText: 2024 Shun Sakai
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Use [Unix time] in nanoseconds when serializing and deserializing a
6//! [`FileTime`].
7//!
8//! Use this module in combination with Serde's [`with`] attribute.
9//!
10//! # Examples
11//!
12//! ```
13//! use nt_time::{
14//!     FileTime,
15//!     serde::{Deserialize, Serialize},
16//!     serde_with::unix_time,
17//! };
18//!
19//! #[derive(Deserialize, Serialize)]
20//! struct Time {
21//!     #[serde(with = "unix_time::nanoseconds")]
22//!     time: FileTime,
23//! }
24//!
25//! let ft = Time {
26//!     time: FileTime::NT_TIME_EPOCH,
27//! };
28//! let json = serde_json::to_string(&ft).unwrap();
29//! assert_eq!(json, r#"{"time":-11644473600000000000}"#);
30//!
31//! let ft: Time = serde_json::from_str(&json).unwrap();
32//! assert_eq!(ft.time, FileTime::NT_TIME_EPOCH);
33//! ```
34//!
35//! [Unix time]: https://en.wikipedia.org/wiki/Unix_time
36//! [`with`]: https://serde.rs/field-attrs.html#with
37
38pub mod option;
39
40use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
41
42use crate::FileTime;
43
44#[allow(clippy::missing_errors_doc)]
45/// Serializes a [`FileTime`] into the given Serde serializer.
46///
47/// This serializes using [Unix time] in nanoseconds.
48///
49/// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
50#[inline]
51pub fn serialize<S: Serializer>(ft: &FileTime, serializer: S) -> Result<S::Ok, S::Error> {
52    ft.to_unix_time_nanos().serialize(serializer)
53}
54
55#[allow(clippy::missing_errors_doc)]
56/// Deserializes a [`FileTime`] from the given Serde deserializer.
57///
58/// This deserializes from its [Unix time] in nanoseconds.
59///
60/// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
61#[inline]
62pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<FileTime, D::Error> {
63    FileTime::from_unix_time_nanos(<_>::deserialize(deserializer)?).map_err(D::Error::custom)
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
71    struct Test {
72        #[serde(with = "crate::serde_with::unix_time::nanoseconds")]
73        time: FileTime,
74    }
75
76    #[test]
77    fn serialize_json() {
78        assert_eq!(
79            serde_json::to_string(&Test {
80                time: FileTime::NT_TIME_EPOCH
81            })
82            .unwrap(),
83            r#"{"time":-11644473600000000000}"#
84        );
85        assert_eq!(
86            serde_json::to_string(&Test {
87                time: FileTime::UNIX_EPOCH
88            })
89            .unwrap(),
90            r#"{"time":0}"#
91        );
92        assert_eq!(
93            serde_json::to_string(&Test {
94                time: FileTime::MAX
95            })
96            .unwrap(),
97            r#"{"time":1833029933770955161500}"#
98        );
99    }
100
101    #[test]
102    fn deserialize_json() {
103        assert_eq!(
104            serde_json::from_str::<Test>(r#"{"time":-11644473600000000000}"#).unwrap(),
105            Test {
106                time: FileTime::NT_TIME_EPOCH
107            }
108        );
109        assert_eq!(
110            serde_json::from_str::<Test>(r#"{"time":0}"#).unwrap(),
111            Test {
112                time: FileTime::UNIX_EPOCH
113            }
114        );
115        assert_eq!(
116            serde_json::from_str::<Test>(r#"{"time":1833029933770955161500}"#).unwrap(),
117            Test {
118                time: FileTime::MAX
119            }
120        );
121    }
122}