netsim 0.3.0

Run tests in network-isolated threads. Intercept and meddle with their packets.
Documentation
use crate::priv_prelude::*;

pub struct PortMap {
    outgoing_map: HashMap<SocketAddrV4, u16>,
    incoming_map: HashMap<u16, SocketAddrV4>,
    next_port: u16,
}

impl PortMap {
    const INITIAL_PORT: u16 = 1025;

    pub fn new() -> PortMap {
        PortMap {
            outgoing_map: HashMap::new(),
            incoming_map: HashMap::new(),
            next_port: PortMap::INITIAL_PORT,
        }
    }

    pub fn outgoing_port(&mut self, internal_addr: SocketAddrV4) -> u16 {
        match self.outgoing_map.entry(internal_addr) {
            hash_map::Entry::Occupied(entry) => *entry.get(),
            hash_map::Entry::Vacant(entry) => {
                let mut attempts = PortMap::INITIAL_PORT;
                let port = loop {
                    let port = self.next_port;
                    self.next_port = {
                        self.next_port.checked_add(1).unwrap_or(PortMap::INITIAL_PORT)
                    };
                    match self.incoming_map.entry(port) {
                        hash_map::Entry::Occupied(mut entry) => {
                            attempts = match attempts.checked_add(1) {
                                Some(attempts) => attempts,
                                None => {
                                    entry.insert(internal_addr);
                                    break port;
                                },
                            };
                        },
                        hash_map::Entry::Vacant(entry) => {
                            entry.insert(internal_addr);
                            break port;
                        },
                    }
                };
                *entry.insert(port)
            },
        }
    }

    pub fn incoming_addr(&self, port: u16) -> Option<SocketAddrV4> {
        self.incoming_map.get(&port).copied()
    }
}