agnostic_net/
to_socket_addrs.rs

1use std::{
2  future::Future,
3  io,
4  net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
5  pin::Pin,
6  task::Poll,
7  vec,
8};
9
10use agnostic_lite::AsyncBlockingSpawner;
11
12use super::{RuntimeLite, ToSocketAddrs};
13
14#[doc(hidden)]
15pub enum ToSocketAddrsFuture<H> {
16  Ready(Option<SocketAddr>),
17  Blocking(H),
18}
19
20type ReadyFuture<T> = std::future::Ready<io::Result<T>>;
21
22impl<T, R: RuntimeLite> ToSocketAddrs<R> for &T
23where
24  T: ToSocketAddrs<R> + ?Sized + Send + Sync,
25{
26  type Iter = T::Iter;
27  type Future = T::Future;
28
29  fn to_socket_addrs(&self) -> Self::Future {
30    (**self).to_socket_addrs()
31  }
32}
33
34impl<R: RuntimeLite> ToSocketAddrs<R> for SocketAddr {
35  type Iter = std::option::IntoIter<SocketAddr>;
36  type Future = ReadyFuture<Self::Iter>;
37
38  fn to_socket_addrs(&self) -> Self::Future {
39    let iter = Some(*self).into_iter();
40    std::future::ready(Ok(iter))
41  }
42}
43
44impl<R: RuntimeLite> ToSocketAddrs<R> for SocketAddrV4 {
45  type Iter = std::option::IntoIter<SocketAddr>;
46  type Future = ReadyFuture<Self::Iter>;
47
48  fn to_socket_addrs(&self) -> Self::Future {
49    ToSocketAddrs::<R>::to_socket_addrs(&SocketAddr::V4(*self))
50  }
51}
52
53impl<R: RuntimeLite> ToSocketAddrs<R> for SocketAddrV6 {
54  type Iter = std::option::IntoIter<SocketAddr>;
55  type Future = ReadyFuture<Self::Iter>;
56
57  fn to_socket_addrs(&self) -> Self::Future {
58    ToSocketAddrs::<R>::to_socket_addrs(&SocketAddr::V6(*self))
59  }
60}
61
62impl<R: RuntimeLite> ToSocketAddrs<R> for (IpAddr, u16) {
63  type Iter = std::option::IntoIter<SocketAddr>;
64  type Future = ReadyFuture<Self::Iter>;
65
66  fn to_socket_addrs(&self) -> Self::Future {
67    ToSocketAddrs::<R>::to_socket_addrs(&SocketAddr::from(*self))
68  }
69}
70
71impl<R: RuntimeLite> ToSocketAddrs<R> for (Ipv4Addr, u16) {
72  type Iter = std::option::IntoIter<SocketAddr>;
73  type Future = ReadyFuture<Self::Iter>;
74
75  fn to_socket_addrs(&self) -> Self::Future {
76    let (ip, port) = *self;
77    ToSocketAddrs::<R>::to_socket_addrs(&SocketAddrV4::new(ip, port))
78  }
79}
80
81impl<R: RuntimeLite> ToSocketAddrs<R> for (Ipv6Addr, u16) {
82  type Iter = std::option::IntoIter<SocketAddr>;
83  type Future = ReadyFuture<Self::Iter>;
84
85  fn to_socket_addrs(&self) -> Self::Future {
86    let (ip, port) = *self;
87    ToSocketAddrs::<R>::to_socket_addrs(&SocketAddrV6::new(ip, port, 0, 0))
88  }
89}
90
91impl<R: RuntimeLite> ToSocketAddrs<R> for [SocketAddr] {
92  type Iter = std::vec::IntoIter<SocketAddr>;
93  type Future = ReadyFuture<Self::Iter>;
94
95  fn to_socket_addrs(&self) -> Self::Future {
96    #[inline]
97    fn slice_to_vec(addrs: &[SocketAddr]) -> Vec<SocketAddr> {
98      addrs.to_vec()
99    }
100
101    // This uses a helper method because clippy doesn't like the `to_vec()`
102    // call here (it will allocate, whereas `self.iter().copied()` would
103    // not), but it's actually necessary in order to ensure that the
104    // returned iterator is valid for the `'static` lifetime, which the
105    // borrowed `slice::Iter` iterator would not be.
106    //
107    // Note that we can't actually add an `allow` attribute for
108    // `clippy::unnecessary_to_owned` here, as Tokio's CI runs clippy lints
109    // on Rust 1.52 to avoid breaking LTS releases of Tokio. Users of newer
110    // Rust versions who see this lint should just ignore it.
111    let iter = slice_to_vec(self).into_iter();
112    std::future::ready(Ok(iter))
113  }
114}
115
116impl<R: RuntimeLite> ToSocketAddrs<R> for (String, u16)
117where
118  ToSocketAddrsFuture<
119    <R::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<io::Result<sealed::OneOrMore>>,
120  >: Future<Output = io::Result<sealed::OneOrMore>> + Send,
121{
122  type Iter = sealed::OneOrMore;
123  type Future = ToSocketAddrsFuture<
124    <R::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<io::Result<sealed::OneOrMore>>,
125  >;
126
127  fn to_socket_addrs(&self) -> Self::Future {
128    ToSocketAddrs::<R>::to_socket_addrs(&(self.0.as_str(), self.1))
129  }
130}
131
132impl<R: RuntimeLite> ToSocketAddrs<R> for String
133where
134  ToSocketAddrsFuture<
135    <R::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<io::Result<sealed::OneOrMore>>,
136  >: Future<Output = io::Result<sealed::OneOrMore>> + Send,
137{
138  type Iter = <str as ToSocketAddrs<R>>::Iter;
139  type Future = <str as ToSocketAddrs<R>>::Future;
140
141  fn to_socket_addrs(&self) -> Self::Future {
142    ToSocketAddrs::<R>::to_socket_addrs(&self[..])
143  }
144}
145
146impl<R: RuntimeLite> ToSocketAddrs<R> for str
147where
148  ToSocketAddrsFuture<
149    <R::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<io::Result<sealed::OneOrMore>>,
150  >: Future<Output = io::Result<sealed::OneOrMore>> + Send,
151{
152  type Iter = sealed::OneOrMore;
153
154  type Future = ToSocketAddrsFuture<
155    <R::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<io::Result<sealed::OneOrMore>>,
156  >;
157
158  fn to_socket_addrs(&self) -> Self::Future {
159    // First check if the input parses as a socket address
160    let res: Result<SocketAddr, _> = self.parse();
161
162    if let Ok(addr) = res {
163      return ToSocketAddrsFuture::Ready(Some(addr));
164    }
165
166    // Run DNS lookup on the blocking pool
167    let s = self.to_owned();
168
169    ToSocketAddrsFuture::Blocking(R::spawn_blocking(move || {
170      std::net::ToSocketAddrs::to_socket_addrs(&s).map(sealed::OneOrMore::More)
171    }))
172  }
173}
174
175impl<R: RuntimeLite> ToSocketAddrs<R> for (&str, u16)
176where
177  ToSocketAddrsFuture<
178    <R::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<io::Result<sealed::OneOrMore>>,
179  >: Future<Output = io::Result<sealed::OneOrMore>> + Send,
180{
181  type Iter = sealed::OneOrMore;
182  type Future = ToSocketAddrsFuture<
183    <R::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<io::Result<sealed::OneOrMore>>,
184  >;
185
186  fn to_socket_addrs(&self) -> Self::Future {
187    let (host, port) = *self;
188
189    // try to parse the host as a regular IP address first
190    if let Ok(addr) = host.parse::<Ipv4Addr>() {
191      let addr = SocketAddrV4::new(addr, port);
192      let addr = SocketAddr::V4(addr);
193
194      return ToSocketAddrsFuture::Ready(Some(addr));
195    }
196
197    if let Ok(addr) = host.parse::<Ipv6Addr>() {
198      let addr = SocketAddrV6::new(addr, port, 0, 0);
199      let addr = SocketAddr::V6(addr);
200
201      return ToSocketAddrsFuture::Ready(Some(addr));
202    }
203
204    let host = host.to_owned();
205    ToSocketAddrsFuture::Blocking(R::spawn_blocking(move || {
206      std::net::ToSocketAddrs::to_socket_addrs(&(&host[..], port)).map(sealed::OneOrMore::More)
207    }))
208  }
209}
210
211impl<R: agnostic_lite::JoinHandle<io::Result<sealed::OneOrMore>>> Future
212  for ToSocketAddrsFuture<R>
213{
214  type Output = io::Result<sealed::OneOrMore>;
215
216  fn poll(
217    self: std::pin::Pin<&mut Self>,
218    cx: &mut std::task::Context<'_>,
219  ) -> std::task::Poll<Self::Output> {
220    match self.get_mut() {
221      Self::Ready(i) => Poll::Ready(Ok(sealed::OneOrMore::One(i.take().into_iter()))),
222      Self::Blocking(i) => {
223        let res = Pin::new(i).poll(cx).map_err(Into::into)?;
224        match res {
225          Poll::Ready(res) => match res {
226            Ok(res) => Poll::Ready(Ok(res)),
227            Err(e) => Poll::Ready(Err(e)),
228          },
229          Poll::Pending => Poll::Pending,
230        }
231      }
232    }
233  }
234}
235
236mod sealed {
237  use super::*;
238  use std::option;
239
240  #[derive(Debug)]
241  #[doc(hidden)]
242  pub enum OneOrMore {
243    One(option::IntoIter<SocketAddr>),
244    More(vec::IntoIter<SocketAddr>),
245  }
246
247  impl Iterator for OneOrMore {
248    type Item = SocketAddr;
249
250    fn next(&mut self) -> Option<Self::Item> {
251      match self {
252        OneOrMore::One(i) => i.next(),
253        OneOrMore::More(i) => i.next(),
254      }
255    }
256
257    fn size_hint(&self) -> (usize, Option<usize>) {
258      match self {
259        OneOrMore::One(i) => i.size_hint(),
260        OneOrMore::More(i) => i.size_hint(),
261      }
262    }
263  }
264}