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
use crate::{Ops, Port, Range};
use std::str::FromStr;
use std::{net::Ipv4Addr, net::TcpListener};

pub struct TcpPort;
impl Ops for TcpPort {
    fn any(host: &str) -> Option<Port> {
        let r = Range::default();
        (r.min..=r.max)
            .filter(|&p| TcpPort::is_port_available(host, p))
            .nth(0)
    }

    fn in_range(host: &str, r: Range) -> Option<Port> {
        (r.min..=r.max)
            .filter(|&p| TcpPort::is_port_available(host, p))
            .nth(0)
    }

    fn from_list(host: &str, v: Vec<Port>) -> Option<Port> {
        v.into_iter()
            .filter(|&p| TcpPort::is_port_available(host, p))
            .nth(0)
    }

    fn except(host: &str, v: Vec<Port>) -> Option<Port> {
        let r = Range::default();
        (r.min..=r.max)
            .filter(|&p| !v.contains(&p) && TcpPort::is_port_available(host, p))
            .nth(0)
    }

    fn in_range_except(host: &str, r: Range, v: Vec<Port>) -> Option<Port> {
        (r.min..=r.max)
            .filter(|&p| !v.contains(&p) && TcpPort::is_port_available(host, p))
            .nth(0)
    }

    fn is_port_available(host: &str, p: Port) -> bool {
        matches!(
            TcpListener::bind((Ipv4Addr::from_str(host).unwrap(), p)).is_ok(),
            true
        )
    }
}