ssh_key/certificate/
unix_time.rs
1use crate::{decode::Decode, encode::Encode, reader::Reader, writer::Writer, Error, Result};
4use core::fmt;
5use core::fmt::Formatter;
6
7#[cfg(feature = "std")]
8use std::time::{Duration, SystemTime, UNIX_EPOCH};
9
10pub const MAX_SECS: u64 = 253402300799;
17
18#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
20pub(super) struct UnixTime {
21 secs: u64,
23
24 #[cfg(feature = "std")]
26 time: SystemTime,
27}
28
29impl UnixTime {
30 #[cfg(not(feature = "std"))]
35 pub fn new(secs: u64) -> Result<Self> {
36 if secs <= MAX_SECS {
37 Ok(Self { secs })
38 } else {
39 Err(Error::Time)
40 }
41 }
42
43 #[cfg(feature = "std")]
49 pub fn new(secs: u64) -> Result<Self> {
50 if secs > MAX_SECS {
51 return Err(Error::Time);
52 }
53
54 match UNIX_EPOCH.checked_add(Duration::from_secs(secs)) {
55 Some(time) => Ok(Self { secs, time }),
56 None => Err(Error::Time),
57 }
58 }
59
60 #[cfg(all(feature = "std", feature = "fingerprint"))]
62 pub fn now() -> Result<Self> {
63 SystemTime::now().try_into()
64 }
65}
66
67impl Decode for UnixTime {
68 fn decode(reader: &mut impl Reader) -> Result<Self> {
69 u64::decode(reader)?.try_into()
70 }
71}
72
73impl Encode for UnixTime {
74 fn encoded_len(&self) -> Result<usize> {
75 self.secs.encoded_len()
76 }
77
78 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
79 self.secs.encode(writer)
80 }
81}
82
83impl From<UnixTime> for u64 {
84 fn from(unix_time: UnixTime) -> u64 {
85 unix_time.secs
86 }
87}
88
89#[cfg(feature = "std")]
90impl From<UnixTime> for SystemTime {
91 fn from(unix_time: UnixTime) -> SystemTime {
92 unix_time.time
93 }
94}
95
96impl TryFrom<u64> for UnixTime {
97 type Error = Error;
98
99 fn try_from(unix_secs: u64) -> Result<UnixTime> {
100 Self::new(unix_secs)
101 }
102}
103
104#[cfg(feature = "std")]
105impl TryFrom<SystemTime> for UnixTime {
106 type Error = Error;
107
108 fn try_from(time: SystemTime) -> Result<UnixTime> {
109 Self::new(time.duration_since(UNIX_EPOCH)?.as_secs())
110 }
111}
112
113impl fmt::Debug for UnixTime {
114 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
115 write!(f, "{}", self.secs)
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::{UnixTime, MAX_SECS};
122 use crate::Error;
123
124 #[test]
125 fn new_with_max_secs() {
126 assert!(UnixTime::new(MAX_SECS).is_ok());
127 }
128
129 #[test]
130 fn new_over_max_secs_returns_error() {
131 assert_eq!(UnixTime::new(MAX_SECS + 1), Err(Error::Time));
132 }
133}