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
use std::{
    iter::{Chain, Filter, FromIterator},
    slice::Iter,
};

pub use std::net::IpAddr;

/// Address selection rules
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum AddrSelect {
    /// Select any available IP address (default)
    AnyType,
    /// Select any address but prefer IPv4 if available
    PreferV4,
    /// Select any address but prefer IPv6 if available
    PreferV6,
    /// Select IPv4 address only
    OnlyV4,
    /// Select IPv6 address only
    OnlyV6,
}

impl Default for AddrSelect {
    fn default() -> Self {
        Self::AnyType
    }
}

impl AddrSelect {
    /// Is IPv6 address allowed
    pub fn has_v6(&self) -> bool {
        self != &Self::OnlyV4
    }

    /// Is IPv4 address allowed
    pub fn has_v4(&self) -> bool {
        self != &Self::OnlyV6
    }
}

pub struct IpAddrIter<'a>(IterVariant<'a>);

type AddrFn = fn(&&IpAddr) -> bool;
type IterAddr<'a> = Iter<'a, IpAddr>;
type FilterAddr<'a> = Filter<IterAddr<'a>, AddrFn>;

enum IterVariant<'a> {
    Any(IterAddr<'a>),
    Only(FilterAddr<'a>),
    Prefer(Chain<FilterAddr<'a>, FilterAddr<'a>>),
}

impl<'a> Iterator for IpAddrIter<'a> {
    type Item = &'a IpAddr;

    fn next(&mut self) -> Option<Self::Item> {
        use IterVariant::*;
        match &mut self.0 {
            Any(iter) => iter.next(),
            Only(iter) => iter.next(),
            Prefer(iter) => iter.next(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct IpAddrs(Vec<IpAddr>);

impl From<Vec<IpAddr>> for IpAddrs {
    fn from(addrs: Vec<IpAddr>) -> Self {
        Self(addrs)
    }
}

impl FromIterator<IpAddr> for IpAddrs {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = IpAddr>,
    {
        iter.into_iter().collect::<Vec<_>>().into()
    }
}

impl IpAddrs {
    pub fn iter(&self, rule: AddrSelect) -> IpAddrIter<'_> {
        use AddrSelect::*;
        use IterVariant::*;
        IpAddrIter(match rule {
            AnyType => Any(self.0.iter()),
            OnlyV4 => Only(self.0.iter().filter(is_v4 as AddrFn)),
            OnlyV6 => Only(self.0.iter().filter(is_v6 as AddrFn)),
            PreferV4 => Prefer(
                self.0
                    .iter()
                    .filter(is_v4 as AddrFn)
                    .chain(self.0.iter().filter(is_v6 as AddrFn)),
            ),
            PreferV6 => Prefer(
                self.0
                    .iter()
                    .filter(is_v6 as AddrFn)
                    .chain(self.0.iter().filter(is_v4 as AddrFn)),
            ),
        })
    }
}

fn is_v4(addr: &&IpAddr) -> bool {
    addr.is_ipv4()
}

fn is_v6(addr: &&IpAddr) -> bool {
    addr.is_ipv6()
}