cloud_sdk/rate_limit/
time.rs1use super::http_date::parse_http_date;
2
3#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
5pub struct DelaySeconds(u64);
6
7impl DelaySeconds {
8 #[must_use]
10 pub const fn new(seconds: u64) -> Self {
11 Self(seconds)
12 }
13
14 #[must_use]
16 pub const fn get(self) -> u64 {
17 self.0
18 }
19}
20
21#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
23pub struct WallClockTimestamp(u64);
24
25impl WallClockTimestamp {
26 #[must_use]
28 pub const fn new(epoch_seconds: u64) -> Self {
29 Self(epoch_seconds)
30 }
31
32 #[must_use]
34 pub const fn get(self) -> u64 {
35 self.0
36 }
37}
38
39#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
41pub struct HttpDate(i64);
42
43impl HttpDate {
44 pub(crate) const fn new(epoch_seconds: i64) -> Self {
45 Self(epoch_seconds)
46 }
47
48 #[must_use]
50 pub const fn epoch_seconds(self) -> i64 {
51 self.0
52 }
53}
54
55#[derive(Clone, Copy, Debug, Eq, PartialEq)]
57pub enum RetryAfter {
58 Delay(DelaySeconds),
60 HttpDate(HttpDate),
62}
63
64impl RetryAfter {
65 pub fn parse(value: &[u8], now: WallClockTimestamp) -> Result<Self, RetryAfterError> {
70 if value.is_empty() {
71 return Err(RetryAfterError::Empty);
72 }
73 if value.iter().all(u8::is_ascii_digit) {
74 return parse_decimal(value).map(DelaySeconds::new).map(Self::Delay);
75 }
76 parse_http_date(value, now).map(Self::HttpDate)
77 }
78}
79
80fn parse_decimal(value: &[u8]) -> Result<u64, RetryAfterError> {
81 let mut parsed = 0_u64;
82 for byte in value {
83 parsed = parsed
84 .checked_mul(10)
85 .and_then(|current| current.checked_add(u64::from(*byte & 0x0f)))
86 .ok_or(RetryAfterError::Overflow)?;
87 }
88 Ok(parsed)
89}
90
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
93pub enum RetryAfterError {
94 Empty,
96 Overflow,
98 InvalidSyntax,
100 InvalidDate,
102 WeekdayMismatch,
104}
105
106impl_static_error!(RetryAfterError,
107 Self::Empty => "Retry-After value is empty",
108 Self::Overflow => "Retry-After value exceeds its numeric range",
109 Self::InvalidSyntax => "Retry-After syntax is invalid",
110 Self::InvalidDate => "Retry-After date is invalid",
111 Self::WeekdayMismatch => "Retry-After weekday does not match its date",
112);