1use std::future::Future;
4use url::Url;
5
6pub trait Session {
15 fn should_procede(&mut self, url: &Url) -> bool;
17
18 fn mark_success(&mut self, url: &Url);
20
21 fn mark_failure(&mut self, url: &Url);
23}
24
25pub trait SessionFactory {
27 type Session: Session;
29
30 fn build_session(&self) -> Self::Session;
32}
33
34pub struct RequestCountSession {
39 count: usize,
40 max_requests: usize,
41}
42
43#[derive(Clone, Debug)]
45pub struct SessionError;
46
47pub async fn guard<Fut, T, E, S>(fut: Fut, url: &Url, mut session: S) -> Result<T, E>
50where
51 Fut: Future<Output = Result<T, E>>,
52 E: From<SessionError>,
53 S: Session,
54{
55 if !session.should_procede(url) {
56 return Err(SessionError.into());
57 }
58
59 match fut.await {
60 Ok(t) => {
61 session.mark_success(url);
62 Ok(t)
63 }
64 Err(e) => {
65 session.mark_failure(url);
66 Err(e)
67 }
68 }
69}
70
71impl RequestCountSession {
72 pub fn max(max_requests: usize) -> Self {
76 Self {
77 count: 0,
78 max_requests,
79 }
80 }
81}
82
83impl std::fmt::Display for SessionError {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 write!(f, "SessionError")
86 }
87}
88
89impl std::error::Error for SessionError {}
90
91impl Session for RequestCountSession {
92 fn should_procede(&mut self, _: &Url) -> bool {
93 self.count < self.max_requests
94 }
95
96 fn mark_success(&mut self, _: &Url) {
97 self.count += 1;
98 }
99
100 fn mark_failure(&mut self, _: &Url) {
101 self.count += 1;
102 }
103}
104
105impl Session for () {
106 fn should_procede(&mut self, _: &Url) -> bool {
107 true
108 }
109
110 fn mark_success(&mut self, _: &Url) {}
111 fn mark_failure(&mut self, _: &Url) {}
112}
113
114impl<'a, T> Session for &'a mut T
115where
116 T: Session,
117{
118 fn should_procede(&mut self, url: &Url) -> bool {
119 T::should_procede(self, url)
120 }
121
122 fn mark_success(&mut self, url: &Url) {
123 T::mark_success(self, url)
124 }
125
126 fn mark_failure(&mut self, url: &Url) {
127 T::mark_failure(self, url)
128 }
129}
130
131impl<T> Session for Box<T>
132where
133 T: Session,
134{
135 fn should_procede(&mut self, url: &Url) -> bool {
136 T::should_procede(self, url)
137 }
138
139 fn mark_success(&mut self, url: &Url) {
140 T::mark_success(self, url)
141 }
142
143 fn mark_failure(&mut self, url: &Url) {
144 T::mark_failure(self, url)
145 }
146}
147
148impl<T, U> Session for (T, U)
149where
150 T: Session,
151 U: Session,
152{
153 fn should_procede(&mut self, url: &Url) -> bool {
154 self.0.should_procede(url) && self.1.should_procede(url)
155 }
156
157 fn mark_success(&mut self, url: &Url) {
158 self.0.mark_success(url);
159 self.1.mark_success(url);
160 }
161
162 fn mark_failure(&mut self, url: &Url) {
163 self.0.mark_failure(url);
164 self.1.mark_failure(url);
165 }
166}
167
168impl<T, U, V> Session for (T, U, V)
169where
170 T: Session,
171 U: Session,
172 V: Session,
173{
174 fn should_procede(&mut self, url: &Url) -> bool {
175 self.0.should_procede(url) && self.1.should_procede(url) && self.2.should_procede(url)
176 }
177
178 fn mark_success(&mut self, url: &Url) {
179 self.0.mark_success(url);
180 self.1.mark_success(url);
181 self.2.mark_success(url);
182 }
183
184 fn mark_failure(&mut self, url: &Url) {
185 self.0.mark_failure(url);
186 self.1.mark_failure(url);
187 self.2.mark_failure(url);
188 }
189}
190
191impl<T, U, V, W> Session for (T, U, V, W)
192where
193 T: Session,
194 U: Session,
195 V: Session,
196 W: Session,
197{
198 fn should_procede(&mut self, url: &Url) -> bool {
199 self.0.should_procede(url)
200 && self.1.should_procede(url)
201 && self.2.should_procede(url)
202 && self.3.should_procede(url)
203 }
204
205 fn mark_success(&mut self, url: &Url) {
206 self.0.mark_success(url);
207 self.1.mark_success(url);
208 self.2.mark_success(url);
209 self.3.mark_success(url);
210 }
211
212 fn mark_failure(&mut self, url: &Url) {
213 self.0.mark_failure(url);
214 self.1.mark_failure(url);
215 self.2.mark_failure(url);
216 self.3.mark_failure(url);
217 }
218}
219
220impl<T, U, V, W, X> Session for (T, U, V, W, X)
221where
222 T: Session,
223 U: Session,
224 V: Session,
225 W: Session,
226 X: Session,
227{
228 fn should_procede(&mut self, url: &Url) -> bool {
229 self.0.should_procede(url)
230 && self.1.should_procede(url)
231 && self.2.should_procede(url)
232 && self.3.should_procede(url)
233 && self.4.should_procede(url)
234 }
235
236 fn mark_success(&mut self, url: &Url) {
237 self.0.mark_success(url);
238 self.1.mark_success(url);
239 self.2.mark_success(url);
240 self.3.mark_success(url);
241 self.4.mark_success(url);
242 }
243
244 fn mark_failure(&mut self, url: &Url) {
245 self.0.mark_failure(url);
246 self.1.mark_failure(url);
247 self.2.mark_failure(url);
248 self.3.mark_failure(url);
249 self.4.mark_failure(url);
250 }
251}
252
253impl<T, U, V, W, X, Y> Session for (T, U, V, W, X, Y)
254where
255 T: Session,
256 U: Session,
257 V: Session,
258 W: Session,
259 X: Session,
260 Y: Session,
261{
262 fn should_procede(&mut self, url: &Url) -> bool {
263 self.0.should_procede(url)
264 && self.1.should_procede(url)
265 && self.2.should_procede(url)
266 && self.3.should_procede(url)
267 && self.4.should_procede(url)
268 && self.5.should_procede(url)
269 }
270
271 fn mark_success(&mut self, url: &Url) {
272 self.0.mark_success(url);
273 self.1.mark_success(url);
274 self.2.mark_success(url);
275 self.3.mark_success(url);
276 self.4.mark_success(url);
277 self.5.mark_success(url);
278 }
279
280 fn mark_failure(&mut self, url: &Url) {
281 self.0.mark_failure(url);
282 self.1.mark_failure(url);
283 self.2.mark_failure(url);
284 self.3.mark_failure(url);
285 self.4.mark_failure(url);
286 self.5.mark_failure(url);
287 }
288}
289
290impl<T, U, V, W, X, Y, Z> Session for (T, U, V, W, X, Y, Z)
291where
292 T: Session,
293 U: Session,
294 V: Session,
295 W: Session,
296 X: Session,
297 Y: Session,
298 Z: Session,
299{
300 fn should_procede(&mut self, url: &Url) -> bool {
301 self.0.should_procede(url)
302 && self.1.should_procede(url)
303 && self.2.should_procede(url)
304 && self.3.should_procede(url)
305 && self.4.should_procede(url)
306 && self.5.should_procede(url)
307 && self.6.should_procede(url)
308 }
309
310 fn mark_success(&mut self, url: &Url) {
311 self.0.mark_success(url);
312 self.1.mark_success(url);
313 self.2.mark_success(url);
314 self.3.mark_success(url);
315 self.4.mark_success(url);
316 self.5.mark_success(url);
317 self.6.mark_success(url);
318 }
319
320 fn mark_failure(&mut self, url: &Url) {
321 self.0.mark_failure(url);
322 self.1.mark_failure(url);
323 self.2.mark_failure(url);
324 self.3.mark_failure(url);
325 self.4.mark_failure(url);
326 self.5.mark_failure(url);
327 self.6.mark_failure(url);
328 }
329}