1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! [`AddrInfoHints`] and associated types.
//!
//! This is only required if you prefer a portable interface.
//! You can use a raw [`dns_lookup::AddrInfoHints`] instead.

use dns_lookup::AddrFamily;

#[cfg(unix)]
use libc::{AF_INET, AF_INET6, AF_UNIX, AF_UNSPEC};

#[cfg(windows)]
use winapi::shared::ws2def::{AF_INET, AF_INET6, AF_UNIX, AF_UNSPEC};

/// The address family to request when resolving the name.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AddressFamily {
    /// No preference.
    Unspec,
    /// Request UNIX-family address.
    Unix,
    /// Request IPv4-family address.
    Inet,
    /// Request IPv6-family address.
    Inet6,
    /// Request custom address family.
    Custom(i32),
}

impl Default for AddressFamily {
    fn default() -> Self {
        Self::Unspec
    }
}

impl From<AddrFamily> for AddressFamily {
    fn from(af: AddrFamily) -> Self {
        match af {
            AddrFamily::Inet => Self::Inet,
            AddrFamily::Inet6 => Self::Inet6,
            AddrFamily::Unix => Self::Unix,
        }
    }
}

/// Portable [`AddrInfoHints`].
#[derive(Debug, Builder, Default)]
pub struct AddrInfoHints {
    #[builder(default)]
    /// Address family to request.
    pub address_family: AddressFamily,
}

impl AddrInfoHints {
    /// Create a new [`AddrInfoHints`] builder.
    pub fn builder() -> AddrInfoHintsBuilder {
        AddrInfoHintsBuilder::default()
    }
}

impl From<&AddrInfoHints> for dns_lookup::AddrInfoHints {
    fn from(opts: &AddrInfoHints) -> Self {
        let address = match opts.address_family {
            AddressFamily::Unspec => AF_UNSPEC,
            AddressFamily::Inet => AF_INET,
            AddressFamily::Inet6 => AF_INET6,
            AddressFamily::Unix => AF_UNIX,
            AddressFamily::Custom(val) => val,
        };
        Self {
            address,
            ..Default::default()
        }
    }
}

impl From<AddrInfoHints> for dns_lookup::AddrInfoHints {
    fn from(opts: AddrInfoHints) -> Self {
        From::from(&opts)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn address_family() {
        let cases = vec![
            (AddrInfoHints::default(), AF_UNSPEC),
            (
                AddrInfoHints {
                    address_family: AddressFamily::Unspec,
                },
                AF_UNSPEC,
            ),
            (
                AddrInfoHints {
                    address_family: AddressFamily::Inet,
                },
                AF_INET,
            ),
            (
                AddrInfoHints {
                    address_family: AddressFamily::Inet6,
                },
                AF_INET6,
            ),
            (
                AddrInfoHints {
                    address_family: AddressFamily::Unix,
                },
                AF_UNIX,
            ),
            (
                AddrInfoHints {
                    address_family: AddressFamily::Custom(123),
                },
                123,
            ),
        ];

        for (addr_info_hints, expected) in cases {
            let dns_lookup::AddrInfoHints { address, .. } = addr_info_hints.into();
            assert_eq!(address, expected);
        }
    }
}