hyper_system_resolver/
background.rs

1//! Background resolver.
2//!
3//! This module contains utilities to aid with implementing resolvers that run
4//! in the background in a [`tokio`] thread pool.
5//!
6//! You can provide a custom [`Resolve`] trait implementation that uses either
7//! [`tokio::spawn`], [`tokio::task::spawn_blocking`] or anything else that
8//! returns [`tokio::task::JoinHandle`].
9
10use std::{
11    fmt,
12    future::Future,
13    io,
14    net::SocketAddr,
15    pin::Pin,
16    task::{self, Poll},
17};
18
19use hyper::client::connect::dns::Name;
20use tokio::task::JoinHandle;
21use tower_service::Service;
22
23/// Resolve the name in the background.
24pub trait Resolve {
25    /// An iterator type used to enumerate the resolved addresses.
26    type Iter: Iterator<Item = SocketAddr>;
27
28    /// Perform the name resolution.
29    fn resolve(&mut self, name: Name) -> JoinHandle<io::Result<Self::Iter>>;
30}
31
32/// A [`hyper`]-compatible resolver implementation.
33/// Delegates the actual resolution logic to the generic parameter `T`.
34#[derive(Clone)]
35pub struct Resolver<T> {
36    inner: T,
37}
38
39impl<T> Resolver<T> {
40    /// Create a new [`Resolver`] backed by `inner` resolution implementation.
41    pub fn new(inner: T) -> Self {
42        Self { inner }
43    }
44
45    /// Consume [`Resolver`] and return the wrapped `T`.
46    pub fn into_inner(self) -> T {
47        self.inner
48    }
49}
50
51impl<T> AsRef<T> for Resolver<T> {
52    fn as_ref(&self) -> &T {
53        &self.inner
54    }
55}
56
57impl<T> Service<Name> for Resolver<T>
58where
59    T: Resolve + Send + Sync + 'static,
60{
61    type Response = <T as Resolve>::Iter;
62    type Error = io::Error;
63    type Future = ResolverFuture<<T as Resolve>::Iter>;
64
65    fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), io::Error>> {
66        Poll::Ready(Ok(()))
67    }
68
69    fn call(&mut self, name: Name) -> Self::Future {
70        let handle = self.inner.resolve(name);
71        ResolverFuture { inner: handle }
72    }
73}
74
75impl<T> fmt::Debug for Resolver<T> {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        f.pad("Resolver")
78    }
79}
80
81/// The opaque resolver future.
82///
83/// Ready when the underlying background resolution is ready.
84/// Propagates panics from the underlying task.
85pub struct ResolverFuture<T> {
86    inner: JoinHandle<io::Result<T>>,
87}
88
89impl<T> Future for ResolverFuture<T> {
90    type Output = io::Result<T>;
91
92    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
93        Pin::new(&mut self.inner).poll(cx).map(|res| match res {
94            Ok(Ok(addrs)) => Ok(addrs),
95            Ok(Err(err)) => Err(err),
96            Err(join_err) => {
97                if join_err.is_cancelled() {
98                    Err(io::Error::new(io::ErrorKind::Interrupted, join_err))
99                } else {
100                    panic!("resolver Resolver task failed: {:?}", join_err)
101                }
102            }
103        })
104    }
105}
106
107impl<T> fmt::Debug for ResolverFuture<T> {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        f.pad("ResolverFuture")
110    }
111}