chuchi_postgres_types/time/
timeout.rs1use std::time::{Duration, SystemTime};
2
3#[derive(Debug, Clone)]
4pub struct Timeout {
5 inner: SystemTime,
6}
7
8impl Timeout {
9 pub fn new(dur: Duration) -> Self {
10 Self {
11 inner: SystemTime::now() + dur,
12 }
13 }
14
15 pub fn now() -> Self {
16 Self {
17 inner: SystemTime::now(),
18 }
19 }
20
21 pub fn has_elapsed(&self) -> bool {
22 SystemTime::now() > self.inner
23 }
24
25 pub fn remaining(&self) -> Option<Duration> {
27 self.inner.duration_since(SystemTime::now()).ok()
28 }
29
30 pub fn as_secs(&self) -> u64 {
32 self.inner
33 .duration_since(SystemTime::UNIX_EPOCH)
34 .expect("Welcome to the past!")
35 .as_secs()
36 }
37
38 pub fn from_secs(s: u64) -> Option<Self> {
39 SystemTime::UNIX_EPOCH
40 .checked_add(Duration::from_secs(s))
41 .map(|c| Timeout { inner: c })
42 }
43}
44
45#[cfg(feature = "serde")]
46mod impl_serde {
47 use super::*;
48
49 use serde::de::{Deserializer, Error};
50 use serde::ser::Serializer;
51 use serde::{Deserialize, Serialize};
52
53 impl Serialize for Timeout {
54 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
55 where
56 S: Serializer,
57 {
58 serializer.serialize_u64(self.as_secs())
59 }
60 }
61
62 impl<'de> Deserialize<'de> for Timeout {
63 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 let num: u64 = Deserialize::deserialize(deserializer)?;
68 Self::from_secs(num).ok_or(D::Error::custom("timeout to big"))
69 }
70 }
71}
72
73#[cfg(feature = "postgres")]
74mod postgres {
75 use super::*;
76 use bytes::BytesMut;
77 use postgres_types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
78
79 impl ToSql for Timeout {
80 fn to_sql(
81 &self,
82 ty: &Type,
83 out: &mut BytesMut,
84 ) -> Result<IsNull, Box<dyn std::error::Error + Sync + Send>> {
85 let secs: i64 = self.as_secs().try_into()?;
86
87 secs.to_sql(ty, out)
88 }
89
90 fn accepts(ty: &Type) -> bool
91 where
92 Self: Sized,
93 {
94 <i64 as ToSql>::accepts(ty)
95 }
96
97 to_sql_checked!();
98 }
99
100 impl<'a> FromSql<'a> for Timeout {
101 fn from_sql(
102 ty: &Type,
103 raw: &'a [u8],
104 ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> {
105 let secs: u64 = <i64 as FromSql>::from_sql(ty, raw)?.try_into()?;
106
107 Self::from_secs(secs).ok_or_else(|| "timeout to large".into())
108 }
109
110 fn accepts(ty: &Type) -> bool {
111 <i64 as FromSql>::accepts(ty)
112 }
113 }
114}