kcp-rs 0.2.5

A Rust implementation of KCP Stream Protocol
Documentation
use crate::protocol::Kcp;

use ::hashlink::LinkedHashMap;
use ::parking_lot::Mutex;
use ::std::{
    sync::Arc,
    time::{Duration, Instant},
};

#[derive(Clone)]
pub struct ConvCache(Arc<Mutex<Inner>>);

struct Inner {
    map: LinkedHashMap<u32, Instant>,
    timeout: Duration,
}

impl ConvCache {
    pub fn new(capacity: usize, timeout: Duration) -> Self {
        Self(Arc::new(Mutex::new(Inner {
            map: if capacity == 0 {
                LinkedHashMap::new()
            } else {
                LinkedHashMap::with_capacity(capacity)
            },
            timeout,
        })))
    }

    pub fn allocate(&self, exists: impl Fn(&u32) -> bool) -> u32 {
        let mut guard = self.0.lock();
        Self::update(&mut guard, Instant::now());
        loop {
            let conv = Kcp::rand_conv();
            if !exists(&conv) && !guard.map.contains_key(&conv) {
                break conv;
            }
        }
    }

    pub fn add(&self, conv: u32) {
        let mut guard = self.0.lock();
        let now = Instant::now();
        Self::update(&mut guard, now);
        if Kcp::is_valid_conv(conv) {
            guard.map.insert(conv, now);
        }
    }

    pub fn fill<T>(&self, iter: T)
    where
        T: IntoIterator<Item = u32>,
    {
        let mut guard = self.0.lock();
        let now = Instant::now();
        Self::update(&mut guard, now);
        for conv in iter {
            if Kcp::is_valid_conv(conv) {
                guard.map.insert(conv, now);
            }
        }
    }

    pub fn dump(&self) -> Vec<u32> {
        let mut guard = self.0.lock();
        Self::update(&mut guard, Instant::now());
        guard.map.keys().copied().collect()
    }

    fn update(this: &mut Inner, now: Instant) {
        while let Some((_, time)) = this.map.front() {
            if now.duration_since(*time) < this.timeout {
                break;
            }
            this.map.pop_front();
        }
    }
}