Implement an async version of ToSocketAddrs (#74)
* Implement an async version of ToSocketAddrs * fix documentation issue * genius hack: pretending to be `impl Future` * replace `std::net::ToSocketAddrs` with `async-std::net::ToSocketAddrs` * Move unit tests into the tests directory * Stylistic changes * Remove re-exports in async_std::net * fix broken link * some mirror changes * remove unnecessary format * migrate: `std::net::ToSocketAddrs` -> `async_std::net::ToSocketAddrs` * fix typo(tutorial) * remove unnecessary type bound * lifetime for futurepull/144/head
parent
1f7f318c36
commit
238a3c882b
@ -0,0 +1,162 @@
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::pin::Pin;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use futures::future::{ready, Ready};
|
||||
|
||||
use crate::future::Future;
|
||||
use crate::io;
|
||||
use crate::task::blocking;
|
||||
use crate::task::{Context, Poll};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "docs")] {
|
||||
#[doc(hidden)]
|
||||
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
|
||||
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $i:ty) => (ImplFuture<$a, io::Result<$i>>);
|
||||
}
|
||||
} else {
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $i:ty) => ($f<$a, $i>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for objects which can be converted or resolved to one or more [`SocketAddr`] values.
|
||||
///
|
||||
/// This trait is an async version of [`std::net::ToSocketAddrs`].
|
||||
///
|
||||
/// [`std::net::ToSocketAddrs`]: https://doc.rust-lang.org/std/net/trait.ToSocketAddrs.html
|
||||
/// [`SocketAddr`]: https://doc.rust-lang.org/std/net/enum.SocketAddr.html
|
||||
pub trait ToSocketAddrs {
|
||||
/// Returned iterator over socket addresses which this type may correspond to.
|
||||
type Iter: Iterator<Item = SocketAddr>;
|
||||
|
||||
/// Converts this object to an iterator of resolved `SocketAddr`s.
|
||||
///
|
||||
/// The returned iterator may not actually yield any values depending on the outcome of any
|
||||
/// resolution performed.
|
||||
///
|
||||
/// Note that this function may block a backend thread while resolution is performed.
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub enum ToSocketAddrsFuture<'a, I: Iterator<Item = SocketAddr>> {
|
||||
Phantom(PhantomData<&'a ()>),
|
||||
Join(blocking::JoinHandle<io::Result<I>>),
|
||||
Ready(Ready<io::Result<I>>),
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = SocketAddr>> Future for ToSocketAddrsFuture<'_, I> {
|
||||
type Output = io::Result<I>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
match self.get_mut() {
|
||||
ToSocketAddrsFuture::Join(f) => Pin::new(&mut *f).poll(cx),
|
||||
ToSocketAddrsFuture::Ready(f) => Pin::new(&mut *f).poll(cx),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for SocketAddr {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for SocketAddrV4 {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for SocketAddrV6 {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for (IpAddr, u16) {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for (Ipv4Addr, u16) {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for (Ipv6Addr, u16) {
|
||||
type Iter = std::option::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for (&str, u16) {
|
||||
type Iter = std::vec::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
let host = self.0.to_string();
|
||||
let port = self.1;
|
||||
let join = blocking::spawn(async move {
|
||||
std::net::ToSocketAddrs::to_socket_addrs(&(host.as_str(), port))
|
||||
});
|
||||
ToSocketAddrsFuture::Join(join)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for str {
|
||||
type Iter = std::vec::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
let socket_addrs = self.to_string();
|
||||
let join =
|
||||
blocking::spawn(async move { std::net::ToSocketAddrs::to_socket_addrs(&socket_addrs) });
|
||||
ToSocketAddrsFuture::Join(join)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToSocketAddrs for &'a [SocketAddr] {
|
||||
type Iter = std::iter::Cloned<std::slice::Iter<'a, SocketAddr>>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrsFuture::Ready(ready(std::net::ToSocketAddrs::to_socket_addrs(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToSocketAddrs + ?Sized> ToSocketAddrs for &T {
|
||||
type Iter = T::Iter;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
(**self).to_socket_addrs()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSocketAddrs for String {
|
||||
type Iter = std::vec::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> ret!('_, ToSocketAddrsFuture, Self::Iter) {
|
||||
ToSocketAddrs::to_socket_addrs(self.as_str())
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
|
||||
use async_std::net::ToSocketAddrs;
|
||||
use async_std::task;
|
||||
|
||||
fn blocking_resolve<A>(a: A) -> Result<Vec<SocketAddr>, String>
|
||||
where
|
||||
A: ToSocketAddrs,
|
||||
A::Iter: Send,
|
||||
{
|
||||
let socket_addrs = task::block_on(a.to_socket_addrs());
|
||||
match socket_addrs {
|
||||
Ok(a) => Ok(a.collect()),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_socket_addr_ipaddr_u16() {
|
||||
let a = Ipv4Addr::new(77, 88, 21, 11);
|
||||
let p = 12345;
|
||||
let e = SocketAddr::V4(SocketAddrV4::new(a, p));
|
||||
assert_eq!(Ok(vec![e]), blocking_resolve((a, p)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_socket_addr_str_u16() {
|
||||
let a = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 24352));
|
||||
assert_eq!(Ok(vec![a]), blocking_resolve(("77.88.21.11", 24352)));
|
||||
|
||||
let a = SocketAddr::V6(SocketAddrV6::new(
|
||||
Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1),
|
||||
53,
|
||||
0,
|
||||
0,
|
||||
));
|
||||
assert_eq!(Ok(vec![a]), blocking_resolve(("2a02:6b8:0:1::1", 53)));
|
||||
|
||||
let a = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 23924));
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
assert!(blocking_resolve(("localhost", 23924)).unwrap().contains(&a));
|
||||
#[cfg(target_env = "sgx")]
|
||||
let _ = a;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_socket_addr_str() {
|
||||
let a = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 24352));
|
||||
assert_eq!(Ok(vec![a]), blocking_resolve("77.88.21.11:24352"));
|
||||
|
||||
let a = SocketAddr::V6(SocketAddrV6::new(
|
||||
Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1),
|
||||
53,
|
||||
0,
|
||||
0,
|
||||
));
|
||||
assert_eq!(Ok(vec![a]), blocking_resolve("[2a02:6b8:0:1::1]:53"));
|
||||
|
||||
let a = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 23924));
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
assert!(blocking_resolve("localhost:23924").unwrap().contains(&a));
|
||||
#[cfg(target_env = "sgx")]
|
||||
let _ = a;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_socket_addr_string() {
|
||||
let a = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 24352));
|
||||
let s: &str = "77.88.21.11:24352";
|
||||
assert_eq!(Ok(vec![a]), blocking_resolve(s));
|
||||
|
||||
let s: &String = &"77.88.21.11:24352".to_string();
|
||||
assert_eq!(Ok(vec![a]), blocking_resolve(s));
|
||||
|
||||
let s: String = "77.88.21.11:24352".to_string();
|
||||
assert_eq!(Ok(vec![a]), blocking_resolve(s));
|
||||
}
|
||||
|
||||
// FIXME: figure out why this fails on openbsd and fix it
|
||||
#[test]
|
||||
#[cfg(not(any(windows, target_os = "openbsd")))]
|
||||
fn to_socket_addr_str_bad() {
|
||||
assert!(blocking_resolve("1200::AB00:1234::2552:7777:1313:34300").is_err());
|
||||
}
|
Loading…
Reference in New Issue