1#![cfg_attr(not(windows), forbid(unsafe_code))]
18#![forbid(missing_docs, future_incompatible)]
19
20cfg_if::cfg_if! {
21 if #[cfg(unix)] {
22 mod unix;
23 use unix as sys;
24 } else if #[cfg(windows)] {
25 mod windows;
26 use windows as sys;
27 } else {
28 compile_error! {
29 "async-dns does not support this platform"
30 }
31 }
32}
33
34use std::io;
35use std::iter::FusedIterator;
36use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
37
38pub async fn lookup(name: &str) -> io::Result<impl Iterator<Item = AddressInfo>> {
40 if let Ok(ip) = name.parse::<Ipv4Addr>() {
42 return Ok(OneOrMany::One(Some(AddressInfo {
43 ip_address: ip.into(),
44 })));
45 }
46
47 if let Ok(ip) = name.parse::<Ipv6Addr>() {
48 return Ok(OneOrMany::One(Some(AddressInfo {
49 ip_address: ip.into(),
50 })));
51 }
52
53 sys::lookup(name)
55 .await
56 .map(|v| OneOrMany::Many(v.into_iter()))
57}
58
59#[non_exhaustive]
61pub struct AddressInfo {
62 pub ip_address: IpAddr,
64}
65
66enum OneOrMany<I> {
68 One(Option<AddressInfo>),
69 Many(I),
70}
71
72impl<I: Iterator<Item = AddressInfo>> Iterator for OneOrMany<I> {
73 type Item = AddressInfo;
74
75 fn next(&mut self) -> Option<Self::Item> {
76 match self {
77 OneOrMany::One(v) => v.take(),
78 OneOrMany::Many(v) => v.next(),
79 }
80 }
81
82 fn size_hint(&self) -> (usize, Option<usize>) {
83 match self {
84 OneOrMany::One(v) => (v.is_some() as usize, Some(v.is_some() as usize)),
85 OneOrMany::Many(v) => v.size_hint(),
86 }
87 }
88
89 fn fold<B, F>(self, init: B, mut f: F) -> B
90 where
91 Self: Sized,
92 F: FnMut(B, Self::Item) -> B,
93 {
94 match self {
95 OneOrMany::One(v) => {
96 if let Some(v) = v {
97 f(init, v)
98 } else {
99 init
100 }
101 }
102 OneOrMany::Many(v) => v.fold(init, f),
103 }
104 }
105}
106
107impl<I: FusedIterator<Item = AddressInfo>> FusedIterator for OneOrMany<I> {}
108
109impl<I: ExactSizeIterator<Item = AddressInfo>> ExactSizeIterator for OneOrMany<I> {}
110
111impl<I: DoubleEndedIterator<Item = AddressInfo>> DoubleEndedIterator for OneOrMany<I> {
112 fn next_back(&mut self) -> Option<Self::Item> {
113 match self {
114 OneOrMany::One(v) => v.take(),
115 OneOrMany::Many(v) => v.next_back(),
116 }
117 }
118}
119
120fn _assert_threadsafe() {
121 fn _assertion<F: Send + Sync>(_: F) {}
122 _assertion(lookup("foobar"));
123}