rtx 0.1.0

RTx is a zero-cost runtime-abstraction intended for use by Rust libraries to enable the Freedom of Choice between asynchronous runtimes.
use smallvec::SmallVec;
use std::io;
use std::net::SocketAddr;

#[cfg(feature = "async")]
use crate::future::BoxFuture;

// TODO: implement ToSocketAddrs for more combinations, see:
//  https://doc.rust-lang.org/stable/std/net/trait.ToSocketAddrs.html#implementors

/// A trait for objects which can be converted or resolved to one or more [`SocketAddr`] values.
pub trait ToSocketAddrs {
    type Iter: IntoIterator<Item = SocketAddr>;

    #[cfg(feature = "async")]
    fn to_socket_addrs(&self) -> BoxFuture<io::Result<Self::Iter>>;

    #[cfg(feature = "blocking")]
    fn to_socket_addrs_blocking(&self) -> io::Result<Self::Iter>;
}

impl<A: ToSocketAddrs + ?Sized> ToSocketAddrs for &'_ A {
    type Iter = A::Iter;

    #[cfg(feature = "async")]
    fn to_socket_addrs(&self) -> BoxFuture<io::Result<Self::Iter>> {
        (*self).to_socket_addrs()
    }

    #[cfg(feature = "blocking")]
    fn to_socket_addrs_blocking(&self) -> io::Result<Self::Iter> {
        (*self).to_socket_addrs_blocking()
    }
}

impl ToSocketAddrs for str {
    type Iter = smallvec::IntoIter<[SocketAddr; 2]>;

    #[cfg(feature = "async")]
    fn to_socket_addrs(&self) -> BoxFuture<io::Result<Self::Iter>> {
        Box::pin(async move {
            let addresses: SmallVec<[SocketAddr; 2]> = pick_async_runtime_async!(self, {
                "async-std" => |host|  async move {
                    let addresses = <Self as async_std::net::ToSocketAddrs>::to_socket_addrs(host).await?;
                    let addresses = SmallVec::<[SocketAddr; 2]>::from_iter(addresses);

                    Ok::<_, io::Error>(addresses)
                },

                "tokio" => |host| async move {
                    let addresses = tokio::net::lookup_host(host).await?;
                    let addresses = SmallVec::<[SocketAddr; 2]>::from_iter(addresses);

                    Ok::<_, io::Error>(addresses)
                },
            })
            .resolve().await
            .into_result()
            // NOTE: without this, when there are no async runtimes enabled, this throws an ICE
            .map_err(|err: io::Error| err)?
            .into_inner();

            Ok(addresses.into_iter())
        })
    }

    #[cfg(feature = "blocking")]
    fn to_socket_addrs_blocking(&self) -> io::Result<Self::Iter> {
        let addresses = std::net::ToSocketAddrs::to_socket_addrs(self)?;
        let addresses = SmallVec::<[SocketAddr; 2]>::from_iter(addresses);

        Ok(addresses.into_iter())
    }
}