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
#![crate_name = "unique_port"]

use once_cell::sync::Lazy;
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener};
use std::ops::Range;
use std::sync::Mutex;

static PORT_IDX: Lazy<Mutex<u16>> = Lazy::new(|| Mutex::new(1000));

/// Returns a free unique local port. Every time a call to this function during one run should return a unique address.
///
/// # Examples
/// ```
/// use unique_port::get_unique_free_port;
///
/// let port_1 = get_unique_free_port().unwrap();
/// let port_2 = get_unique_free_port().unwrap();
/// assert_ne!(port_1, port_2);
/// ```
pub fn get_unique_free_port() -> Result<u16, String> {
    let mut port_idx = PORT_IDX
        .lock()
        .map_err(|_| "Failed to aquire the lock".to_owned())?;
    let result = get_free_port(*port_idx..u16::MAX);
    if let Ok(port) = result {
        *port_idx = port + 1;
    }
    result
}

/// Returns empty port from range. Can be not unique
fn get_free_port(ports: Range<u16>) -> Result<u16, String> {
    ports
        .into_iter()
        .find(|port| TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, *port)).is_ok())
        .ok_or_else(|| "Failed to get empty port".to_owned())
}