refactor(client): use pin_project for Resolve futures
This commit is contained in:
		| @@ -17,14 +17,14 @@ use std::str::FromStr; | ||||
|  | ||||
| use tokio_sync::{mpsc, oneshot}; | ||||
|  | ||||
| use crate::common::{Future, Never, Pin, Poll, Unpin, task}; | ||||
| use crate::common::{Future, Never, Pin, Poll, task}; | ||||
|  | ||||
| /// Resolve a hostname to a set of IP addresses. | ||||
| pub trait Resolve: Unpin { | ||||
| pub trait Resolve { | ||||
|     /// The set of IP addresses to try to connect to. | ||||
|     type Addrs: Iterator<Item=IpAddr>; | ||||
|     /// A Future of the resolved set of addresses. | ||||
|     type Future: Future<Output=Result<Self::Addrs, io::Error>> + Unpin; | ||||
|     type Future: Future<Output=Result<Self::Addrs, io::Error>>; | ||||
|     /// Resolve a hostname. | ||||
|     fn resolve(&self, name: Name) -> Self::Future; | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ use std::time::Duration; | ||||
| use http::uri::{Scheme, Uri}; | ||||
| use futures_util::{TryFutureExt, FutureExt}; | ||||
| use net2::TcpBuilder; | ||||
| use pin_project::{pin_project, project}; | ||||
| use tokio_net::driver::Handle; | ||||
| use tokio_net::tcp::TcpStream; | ||||
| use tokio_timer::{Delay, Timeout}; | ||||
| @@ -359,7 +360,9 @@ impl StdError for InvalidUrl { | ||||
| } | ||||
| /// A Future representing work to connect to a URL. | ||||
| #[must_use = "futures do nothing unless polled"] | ||||
| #[pin_project] | ||||
| pub struct HttpConnecting<R: Resolve = GaiResolver> { | ||||
|     #[pin] | ||||
|     state: State<R>, | ||||
|     handle: Option<Handle>, | ||||
|     connect_timeout: Option<Duration>, | ||||
| @@ -372,61 +375,61 @@ pub struct HttpConnecting<R: Resolve = GaiResolver> { | ||||
|     recv_buffer_size: Option<usize>, | ||||
| } | ||||
|  | ||||
| #[pin_project] | ||||
| enum State<R: Resolve> { | ||||
|     Lazy(R, String, Option<IpAddr>), | ||||
|     Resolving(R::Future, Option<IpAddr>), | ||||
|     Resolving(#[pin] R::Future, Option<IpAddr>), | ||||
|     Connecting(ConnectingTcp), | ||||
|     Error(Option<io::Error>), | ||||
| } | ||||
|  | ||||
| impl<R: Resolve> Future for HttpConnecting<R> | ||||
| where | ||||
|     R::Future: Unpin, | ||||
| { | ||||
| impl<R: Resolve> Future for HttpConnecting<R> { | ||||
|     type Output = Result<(TcpStream, Connected), io::Error>; | ||||
|  | ||||
|     fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||
|         let me = &mut *self; | ||||
|     #[project] | ||||
|     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { | ||||
|         let mut me = self.project(); | ||||
|         loop { | ||||
|             let state; | ||||
|             match me.state { | ||||
|                 State::Lazy(ref resolver, ref mut host, local_addr) => { | ||||
|             #[project] | ||||
|             match me.state.as_mut().project() { | ||||
|                 State::Lazy(ref resolver, ref mut host, ref local_addr) => { | ||||
|                     // If the host is already an IP addr (v4 or v6), | ||||
|                     // skip resolving the dns and start connecting right away. | ||||
|                     if let Some(addrs) = dns::IpAddrs::try_parse(host, me.port) { | ||||
|                     if let Some(addrs) = dns::IpAddrs::try_parse(host, *me.port) { | ||||
|                         state = State::Connecting(ConnectingTcp::new( | ||||
|                             local_addr, addrs, me.connect_timeout, me.happy_eyeballs_timeout, me.reuse_address)); | ||||
|                             **local_addr, addrs, *me.connect_timeout, *me.happy_eyeballs_timeout, *me.reuse_address)); | ||||
|                     } else { | ||||
|                         let name = dns::Name::new(mem::replace(host, String::new())); | ||||
|                         state = State::Resolving(resolver.resolve(name), local_addr); | ||||
|                         state = State::Resolving(resolver.resolve(name), **local_addr); | ||||
|                     } | ||||
|                 }, | ||||
|                 State::Resolving(ref mut future, local_addr) => { | ||||
|                     let addrs =  ready!(Pin::new(future).poll(cx))?; | ||||
|                     let port = me.port; | ||||
|                 State::Resolving(future, local_addr) => { | ||||
|                     let addrs =  ready!(future.poll(cx))?; | ||||
|                     let port = *me.port; | ||||
|                     let addrs = addrs | ||||
|                         .map(|addr| SocketAddr::new(addr, port)) | ||||
|                         .collect(); | ||||
|                     let addrs = dns::IpAddrs::new(addrs); | ||||
|                     state = State::Connecting(ConnectingTcp::new( | ||||
|                         local_addr, addrs, me.connect_timeout, me.happy_eyeballs_timeout, me.reuse_address)); | ||||
|                         *local_addr, addrs, *me.connect_timeout, *me.happy_eyeballs_timeout, *me.reuse_address)); | ||||
|                 }, | ||||
|                 State::Connecting(ref mut c) => { | ||||
|                     let sock = ready!(c.poll(cx, &me.handle))?; | ||||
|  | ||||
|                     if let Some(dur) = me.keep_alive_timeout { | ||||
|                         sock.set_keepalive(Some(dur))?; | ||||
|                         sock.set_keepalive(Some(*dur))?; | ||||
|                     } | ||||
|  | ||||
|                     if let Some(size) = me.send_buffer_size { | ||||
|                         sock.set_send_buffer_size(size)?; | ||||
|                         sock.set_send_buffer_size(*size)?; | ||||
|                     } | ||||
|  | ||||
|                     if let Some(size) = me.recv_buffer_size { | ||||
|                         sock.set_recv_buffer_size(size)?; | ||||
|                         sock.set_recv_buffer_size(*size)?; | ||||
|                     } | ||||
|  | ||||
|                     sock.set_nodelay(me.nodelay)?; | ||||
|                     sock.set_nodelay(*me.nodelay)?; | ||||
|  | ||||
|                     let extra = HttpInfo { | ||||
|                         remote_addr: sock.peer_addr()?, | ||||
| @@ -438,7 +441,7 @@ where | ||||
|                 }, | ||||
|                 State::Error(ref mut e) => return Poll::Ready(Err(e.take().expect("polled more than once"))), | ||||
|             } | ||||
|             me.state = state; | ||||
|             me.state.set(state); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user