1use core::fmt;
2
3use std::{error, time::Instant};
4
5use http::{HeaderName, HeaderValue, Response, StatusCode};
6
7use crate::{
8 gcra::NotUntil,
9 timer::{DefaultTimer, Timer},
10};
11
12#[derive(Debug)]
14pub struct TooManyRequests {
15 after_seconds: u64,
16}
17
18impl fmt::Display for TooManyRequests {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 write!(f, "too many requests. wait for {}", self.after_seconds)
21 }
22}
23
24impl error::Error for TooManyRequests {}
25
26impl From<NotUntil<Instant>> for TooManyRequests {
27 fn from(e: NotUntil<Instant>) -> Self {
28 let after_seconds = e.wait_time_from(DefaultTimer.now()).as_secs();
29 Self { after_seconds }
30 }
31}
32
33const X_RT_AFTER: HeaderName = HeaderName::from_static("x-ratelimit-after");
34
35impl TooManyRequests {
36 pub fn extend_response<Ext>(&self, res: &mut Response<Ext>) {
40 *res.status_mut() = StatusCode::TOO_MANY_REQUESTS;
41 res.headers_mut()
42 .insert(X_RT_AFTER, HeaderValue::from(self.after_seconds));
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct InsufficientCapacity(pub u32);
54
55impl fmt::Display for InsufficientCapacity {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 write!(f, "required number of cells {} exceeds bucket's capacity", self.0)
58 }
59}
60
61impl error::Error for InsufficientCapacity {}
62
63#[cfg(test)]
64mod test {
65 use super::InsufficientCapacity;
66
67 #[test]
68 fn coverage() {
69 let display_output = format!("{}", InsufficientCapacity(3));
70 assert!(display_output.contains('3'));
71 let debug_output = format!("{:?}", InsufficientCapacity(3));
72 assert!(debug_output.contains('3'));
73 assert_eq!(InsufficientCapacity(3), InsufficientCapacity(3));
74 }
75}