/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tower-0.5.2/src/hedge/select.rs
Line | Count | Source |
1 | | use pin_project_lite::pin_project; |
2 | | use std::{ |
3 | | future::Future, |
4 | | pin::Pin, |
5 | | task::{Context, Poll}, |
6 | | }; |
7 | | use tower_service::Service; |
8 | | |
9 | | /// A policy which decides which requests can be cloned and sent to the B |
10 | | /// service. |
11 | | pub trait Policy<Request> { |
12 | | fn clone_request(&self, req: &Request) -> Option<Request>; |
13 | | } |
14 | | |
15 | | /// Select is a middleware which attempts to clone the request and sends the |
16 | | /// original request to the A service and, if the request was able to be cloned, |
17 | | /// the cloned request to the B service. Both resulting futures will be polled |
18 | | /// and whichever future completes first will be used as the result. |
19 | | #[derive(Debug)] |
20 | | pub struct Select<P, A, B> { |
21 | | policy: P, |
22 | | a: A, |
23 | | b: B, |
24 | | } |
25 | | |
26 | | pin_project! { |
27 | | #[derive(Debug)] |
28 | | pub struct ResponseFuture<AF, BF> { |
29 | | #[pin] |
30 | | a_fut: AF, |
31 | | #[pin] |
32 | | b_fut: Option<BF>, |
33 | | } |
34 | | } |
35 | | |
36 | | impl<P, A, B> Select<P, A, B> { |
37 | 0 | pub const fn new<Request>(policy: P, a: A, b: B) -> Self |
38 | 0 | where |
39 | 0 | P: Policy<Request>, |
40 | 0 | A: Service<Request>, |
41 | 0 | A::Error: Into<crate::BoxError>, |
42 | 0 | B: Service<Request, Response = A::Response>, |
43 | 0 | B::Error: Into<crate::BoxError>, |
44 | | { |
45 | 0 | Select { policy, a, b } |
46 | 0 | } |
47 | | } |
48 | | |
49 | | impl<P, A, B, Request> Service<Request> for Select<P, A, B> |
50 | | where |
51 | | P: Policy<Request>, |
52 | | A: Service<Request>, |
53 | | A::Error: Into<crate::BoxError>, |
54 | | B: Service<Request, Response = A::Response>, |
55 | | B::Error: Into<crate::BoxError>, |
56 | | { |
57 | | type Response = A::Response; |
58 | | type Error = crate::BoxError; |
59 | | type Future = ResponseFuture<A::Future, B::Future>; |
60 | | |
61 | 0 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { |
62 | 0 | match (self.a.poll_ready(cx), self.b.poll_ready(cx)) { |
63 | 0 | (Poll::Ready(Ok(())), Poll::Ready(Ok(()))) => Poll::Ready(Ok(())), |
64 | 0 | (Poll::Ready(Err(e)), _) => Poll::Ready(Err(e.into())), |
65 | 0 | (_, Poll::Ready(Err(e))) => Poll::Ready(Err(e.into())), |
66 | 0 | _ => Poll::Pending, |
67 | | } |
68 | 0 | } |
69 | | |
70 | 0 | fn call(&mut self, request: Request) -> Self::Future { |
71 | 0 | let b_fut = if let Some(cloned_req) = self.policy.clone_request(&request) { |
72 | 0 | Some(self.b.call(cloned_req)) |
73 | | } else { |
74 | 0 | None |
75 | | }; |
76 | 0 | ResponseFuture { |
77 | 0 | a_fut: self.a.call(request), |
78 | 0 | b_fut, |
79 | 0 | } |
80 | 0 | } |
81 | | } |
82 | | |
83 | | impl<AF, BF, T, AE, BE> Future for ResponseFuture<AF, BF> |
84 | | where |
85 | | AF: Future<Output = Result<T, AE>>, |
86 | | AE: Into<crate::BoxError>, |
87 | | BF: Future<Output = Result<T, BE>>, |
88 | | BE: Into<crate::BoxError>, |
89 | | { |
90 | | type Output = Result<T, crate::BoxError>; |
91 | | |
92 | 0 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
93 | 0 | let this = self.project(); |
94 | | |
95 | 0 | if let Poll::Ready(r) = this.a_fut.poll(cx) { |
96 | 0 | return Poll::Ready(Ok(r.map_err(Into::into)?)); |
97 | 0 | } |
98 | 0 | if let Some(b_fut) = this.b_fut.as_pin_mut() { |
99 | 0 | if let Poll::Ready(r) = b_fut.poll(cx) { |
100 | 0 | return Poll::Ready(Ok(r.map_err(Into::into)?)); |
101 | 0 | } |
102 | 0 | } |
103 | 0 | Poll::Pending |
104 | 0 | } |
105 | | } |