#![cfg_attr(not(windows), forbid(unsafe_code))]
#![forbid(missing_docs, future_incompatible)]
cfg_if::cfg_if! {
if #[cfg(unix)] {
mod unix;
use unix as sys;
} else if #[cfg(windows)] {
mod windows;
use windows as sys;
} else {
compile_error! {
"async-dns does not support this platform"
}
}
}
use std::io;
use std::iter::FusedIterator;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub async fn lookup(name: &str) -> io::Result<impl Iterator<Item = AddressInfo>> {
if let Ok(ip) = name.parse::<Ipv4Addr>() {
return Ok(OneOrMany::One(Some(AddressInfo {
ip_address: ip.into(),
})));
}
if let Ok(ip) = name.parse::<Ipv6Addr>() {
return Ok(OneOrMany::One(Some(AddressInfo {
ip_address: ip.into(),
})));
}
sys::lookup(name)
.await
.map(|v| OneOrMany::Many(v.into_iter()))
}
#[non_exhaustive]
pub struct AddressInfo {
pub ip_address: IpAddr,
}
enum OneOrMany<I> {
One(Option<AddressInfo>),
Many(I),
}
impl<I: Iterator<Item = AddressInfo>> Iterator for OneOrMany<I> {
type Item = AddressInfo;
fn next(&mut self) -> Option<Self::Item> {
match self {
OneOrMany::One(v) => v.take(),
OneOrMany::Many(v) => v.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
OneOrMany::One(v) => (v.is_some() as usize, Some(v.is_some() as usize)),
OneOrMany::Many(v) => v.size_hint(),
}
}
fn fold<B, F>(self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
match self {
OneOrMany::One(v) => {
if let Some(v) = v {
f(init, v)
} else {
init
}
}
OneOrMany::Many(v) => v.fold(init, f),
}
}
}
impl<I: FusedIterator<Item = AddressInfo>> FusedIterator for OneOrMany<I> {}
impl<I: ExactSizeIterator<Item = AddressInfo>> ExactSizeIterator for OneOrMany<I> {}
impl<I: DoubleEndedIterator<Item = AddressInfo>> DoubleEndedIterator for OneOrMany<I> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
OneOrMany::One(v) => v.take(),
OneOrMany::Many(v) => v.next_back(),
}
}
}
fn _assert_threadsafe() {
fn _assertion<F: Send + Sync>(_: F) {}
_assertion(lookup("foobar"));
}