1use std::future::Future;
2use std::marker::PhantomData;
3use std::pin::Pin;
4use std::task::{Context, Poll};
5
6use http::{header, StatusCode};
7
8use super::{ErrorResponseFuture, Output, Response};
9use crate::client;
10use crate::error::{self, Error};
11
12pub struct ResponseFuture<T> {
14 state: State,
15 phantom: PhantomData<T>,
16}
17
18enum State {
19 InFlight(client::service::ResponseFuture),
20 ErrorResponse(StatusCode, ErrorResponseFuture),
21 Failed(Error),
22 Completed,
23}
24
25impl<T> ResponseFuture<T> {
26 pub(crate) fn new(fut: client::service::ResponseFuture) -> Self {
27 Self {
28 state: State::InFlight(fut),
29 phantom: PhantomData,
30 }
31 }
32
33 pub(crate) fn failed(error: Error) -> Self {
34 Self {
35 state: State::Failed(error),
36 phantom: PhantomData,
37 }
38 }
39}
40
41impl<T: Unpin> Future for ResponseFuture<T> {
42 type Output = Output<T>;
43
44 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
45 loop {
46 let state = std::mem::replace(&mut self.state, State::Completed);
47
48 match state {
49 State::InFlight(mut fut) => {
50 let resp = match Pin::new(&mut fut).poll(cx) {
51 Poll::Ready(Ok(resp)) => Response::new(resp),
52 Poll::Ready(Err(err)) => return Poll::Ready(Err(error::request(err))),
53 Poll::Pending => {
54 self.state = State::InFlight(fut);
55 return Poll::Pending;
56 }
57 };
58
59 if resp.status().is_success() {
60 return Poll::Ready(Ok(resp));
61 }
62
63 let retry_after = resp
64 .headers()
65 .get(header::RETRY_AFTER)
66 .and_then(|v| v.to_str().ok())
67 .and_then(|v| v.parse().ok());
68
69 if let Some(retry_after) = retry_after {
70 return Poll::Ready(Err(error::ratelimit(retry_after)));
71 }
72
73 self.state = State::ErrorResponse(resp.status(), resp.error());
74 }
75 State::ErrorResponse(status, mut fut) => {
76 let error = match Pin::new(&mut fut).poll(cx) {
77 Poll::Ready(Ok(resp)) => resp.error,
78 Poll::Ready(Err(err)) => return Poll::Ready(Err(error::request(err))),
79 Poll::Pending => {
80 self.state = State::ErrorResponse(status, fut);
81 return Poll::Pending;
82 }
83 };
84
85 return Poll::Ready(Err(error::error_for_status(status, error)));
86 }
87 State::Failed(err) => return Poll::Ready(Err(err)),
88 State::Completed => panic!("future is already completed"),
89 }
90 }
91 }
92}